mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-05 11:53:41 +00:00

With VIRTCHNL2_CAP_MACFILTER enabled, the following warning is generated
on module load:
[ 324.701677] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:578
[ 324.701684] in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 1582, name: NetworkManager
[ 324.701689] preempt_count: 201, expected: 0
[ 324.701693] RCU nest depth: 0, expected: 0
[ 324.701697] 2 locks held by NetworkManager/1582:
[ 324.701702] #0: ffffffff9f7be770 (rtnl_mutex){....}-{3:3}, at: rtnl_newlink+0x791/0x21e0
[ 324.701730] #1: ff1100216c380368 (_xmit_ETHER){....}-{2:2}, at: __dev_open+0x3f0/0x870
[ 324.701749] Preemption disabled at:
[ 324.701752] [<ffffffff9cd23b9d>] __dev_open+0x3dd/0x870
[ 324.701765] CPU: 30 UID: 0 PID: 1582 Comm: NetworkManager Not tainted 6.15.0-rc5+ #2 PREEMPT(voluntary)
[ 324.701771] Hardware name: Intel Corporation M50FCP2SBSTD/M50FCP2SBSTD, BIOS SE5C741.86B.01.01.0001.2211140926 11/14/2022
[ 324.701774] Call Trace:
[ 324.701777] <TASK>
[ 324.701779] dump_stack_lvl+0x5d/0x80
[ 324.701788] ? __dev_open+0x3dd/0x870
[ 324.701793] __might_resched.cold+0x1ef/0x23d
<..>
[ 324.701818] __mutex_lock+0x113/0x1b80
<..>
[ 324.701917] idpf_ctlq_clean_sq+0xad/0x4b0 [idpf]
[ 324.701935] ? kasan_save_track+0x14/0x30
[ 324.701941] idpf_mb_clean+0x143/0x380 [idpf]
<..>
[ 324.701991] idpf_send_mb_msg+0x111/0x720 [idpf]
[ 324.702009] idpf_vc_xn_exec+0x4cc/0x990 [idpf]
[ 324.702021] ? rcu_is_watching+0x12/0xc0
[ 324.702035] idpf_add_del_mac_filters+0x3ed/0xb50 [idpf]
<..>
[ 324.702122] __hw_addr_sync_dev+0x1cf/0x300
[ 324.702126] ? find_held_lock+0x32/0x90
[ 324.702134] idpf_set_rx_mode+0x317/0x390 [idpf]
[ 324.702152] __dev_open+0x3f8/0x870
[ 324.702159] ? __pfx___dev_open+0x10/0x10
[ 324.702174] __dev_change_flags+0x443/0x650
<..>
[ 324.702208] netif_change_flags+0x80/0x160
[ 324.702218] do_setlink.isra.0+0x16a0/0x3960
<..>
[ 324.702349] rtnl_newlink+0x12fd/0x21e0
The sequence is as follows:
rtnl_newlink()->
__dev_change_flags()->
__dev_open()->
dev_set_rx_mode() - > # disables BH and grabs "dev->addr_list_lock"
idpf_set_rx_mode() -> # proceed only if VIRTCHNL2_CAP_MACFILTER is ON
__dev_uc_sync() ->
idpf_add_mac_filter ->
idpf_add_del_mac_filters ->
idpf_send_mb_msg() ->
idpf_mb_clean() ->
idpf_ctlq_clean_sq() # mutex_lock(cq_lock)
Fix by converting cq_lock to a spinlock. All operations under the new
lock are safe except freeing the DMA memory, which may use vunmap(). Fix
by requesting a contiguous physical memory for the DMA mapping.
Fixes: a251eee621
("idpf: add SRIOV support and other ndo_ops")
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Ahmed Zaki <ahmed.zaki@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Samuel Salin <Samuel.salin@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
178 lines
4.8 KiB
C
178 lines
4.8 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/* Copyright (C) 2023 Intel Corporation */
|
|
|
|
#ifndef _IDPF_CONTROLQ_API_H_
|
|
#define _IDPF_CONTROLQ_API_H_
|
|
|
|
#include "idpf_mem.h"
|
|
|
|
struct idpf_hw;
|
|
|
|
/* Used for queue init, response and events */
|
|
enum idpf_ctlq_type {
|
|
IDPF_CTLQ_TYPE_MAILBOX_TX = 0,
|
|
IDPF_CTLQ_TYPE_MAILBOX_RX = 1,
|
|
IDPF_CTLQ_TYPE_CONFIG_TX = 2,
|
|
IDPF_CTLQ_TYPE_CONFIG_RX = 3,
|
|
IDPF_CTLQ_TYPE_EVENT_RX = 4,
|
|
IDPF_CTLQ_TYPE_RDMA_TX = 5,
|
|
IDPF_CTLQ_TYPE_RDMA_RX = 6,
|
|
IDPF_CTLQ_TYPE_RDMA_COMPL = 7
|
|
};
|
|
|
|
/* Generic Control Queue Structures */
|
|
struct idpf_ctlq_reg {
|
|
/* used for queue tracking */
|
|
u32 head;
|
|
u32 tail;
|
|
/* Below applies only to default mb (if present) */
|
|
u32 len;
|
|
u32 bah;
|
|
u32 bal;
|
|
u32 len_mask;
|
|
u32 len_ena_mask;
|
|
u32 head_mask;
|
|
};
|
|
|
|
/* Generic queue msg structure */
|
|
struct idpf_ctlq_msg {
|
|
u8 vmvf_type; /* represents the source of the message on recv */
|
|
#define IDPF_VMVF_TYPE_VF 0
|
|
#define IDPF_VMVF_TYPE_VM 1
|
|
#define IDPF_VMVF_TYPE_PF 2
|
|
u8 host_id;
|
|
/* 3b field used only when sending a message to CP - to be used in
|
|
* combination with target func_id to route the message
|
|
*/
|
|
#define IDPF_HOST_ID_MASK 0x7
|
|
|
|
u16 opcode;
|
|
u16 data_len; /* data_len = 0 when no payload is attached */
|
|
union {
|
|
u16 func_id; /* when sending a message */
|
|
u16 status; /* when receiving a message */
|
|
};
|
|
union {
|
|
struct {
|
|
u32 chnl_opcode;
|
|
u32 chnl_retval;
|
|
} mbx;
|
|
} cookie;
|
|
union {
|
|
#define IDPF_DIRECT_CTX_SIZE 16
|
|
#define IDPF_INDIRECT_CTX_SIZE 8
|
|
/* 16 bytes of context can be provided or 8 bytes of context
|
|
* plus the address of a DMA buffer
|
|
*/
|
|
u8 direct[IDPF_DIRECT_CTX_SIZE];
|
|
struct {
|
|
u8 context[IDPF_INDIRECT_CTX_SIZE];
|
|
struct idpf_dma_mem *payload;
|
|
} indirect;
|
|
struct {
|
|
u32 rsvd;
|
|
u16 data;
|
|
u16 flags;
|
|
} sw_cookie;
|
|
} ctx;
|
|
};
|
|
|
|
/* Generic queue info structures */
|
|
/* MB, CONFIG and EVENT q do not have extended info */
|
|
struct idpf_ctlq_create_info {
|
|
enum idpf_ctlq_type type;
|
|
int id; /* absolute queue offset passed as input
|
|
* -1 for default mailbox if present
|
|
*/
|
|
u16 len; /* Queue length passed as input */
|
|
u16 buf_size; /* buffer size passed as input */
|
|
u64 base_address; /* output, HPA of the Queue start */
|
|
struct idpf_ctlq_reg reg; /* registers accessed by ctlqs */
|
|
|
|
int ext_info_size;
|
|
void *ext_info; /* Specific to q type */
|
|
};
|
|
|
|
/* Control Queue information */
|
|
struct idpf_ctlq_info {
|
|
struct list_head cq_list;
|
|
|
|
enum idpf_ctlq_type cq_type;
|
|
int q_id;
|
|
spinlock_t cq_lock; /* control queue lock */
|
|
/* used for interrupt processing */
|
|
u16 next_to_use;
|
|
u16 next_to_clean;
|
|
u16 next_to_post; /* starting descriptor to post buffers
|
|
* to after recev
|
|
*/
|
|
|
|
struct idpf_dma_mem desc_ring; /* descriptor ring memory
|
|
* idpf_dma_mem is defined in OSdep.h
|
|
*/
|
|
union {
|
|
struct idpf_dma_mem **rx_buff;
|
|
struct idpf_ctlq_msg **tx_msg;
|
|
} bi;
|
|
|
|
u16 buf_size; /* queue buffer size */
|
|
u16 ring_size; /* Number of descriptors */
|
|
struct idpf_ctlq_reg reg; /* registers accessed by ctlqs */
|
|
};
|
|
|
|
/**
|
|
* enum idpf_mbx_opc - PF/VF mailbox commands
|
|
* @idpf_mbq_opc_send_msg_to_cp: used by PF or VF to send a message to its CP
|
|
* @idpf_mbq_opc_send_msg_to_peer_drv: used by PF or VF to send a message to
|
|
* any peer driver
|
|
*/
|
|
enum idpf_mbx_opc {
|
|
idpf_mbq_opc_send_msg_to_cp = 0x0801,
|
|
idpf_mbq_opc_send_msg_to_peer_drv = 0x0804,
|
|
};
|
|
|
|
/* API supported for control queue management */
|
|
/* Will init all required q including default mb. "q_info" is an array of
|
|
* create_info structs equal to the number of control queues to be created.
|
|
*/
|
|
int idpf_ctlq_init(struct idpf_hw *hw, u8 num_q,
|
|
struct idpf_ctlq_create_info *q_info);
|
|
|
|
/* Allocate and initialize a single control queue, which will be added to the
|
|
* control queue list; returns a handle to the created control queue
|
|
*/
|
|
int idpf_ctlq_add(struct idpf_hw *hw,
|
|
struct idpf_ctlq_create_info *qinfo,
|
|
struct idpf_ctlq_info **cq);
|
|
|
|
/* Deinitialize and deallocate a single control queue */
|
|
void idpf_ctlq_remove(struct idpf_hw *hw,
|
|
struct idpf_ctlq_info *cq);
|
|
|
|
/* Sends messages to HW and will also free the buffer*/
|
|
int idpf_ctlq_send(struct idpf_hw *hw,
|
|
struct idpf_ctlq_info *cq,
|
|
u16 num_q_msg,
|
|
struct idpf_ctlq_msg q_msg[]);
|
|
|
|
/* Receives messages and called by interrupt handler/polling
|
|
* initiated by app/process. Also caller is supposed to free the buffers
|
|
*/
|
|
int idpf_ctlq_recv(struct idpf_ctlq_info *cq, u16 *num_q_msg,
|
|
struct idpf_ctlq_msg *q_msg);
|
|
|
|
/* Reclaims send descriptors on HW write back */
|
|
int idpf_ctlq_clean_sq(struct idpf_ctlq_info *cq, u16 *clean_count,
|
|
struct idpf_ctlq_msg *msg_status[]);
|
|
|
|
/* Indicate RX buffers are done being processed */
|
|
int idpf_ctlq_post_rx_buffs(struct idpf_hw *hw,
|
|
struct idpf_ctlq_info *cq,
|
|
u16 *buff_count,
|
|
struct idpf_dma_mem **buffs);
|
|
|
|
/* Will destroy all q including the default mb */
|
|
void idpf_ctlq_deinit(struct idpf_hw *hw);
|
|
|
|
#endif /* _IDPF_CONTROLQ_API_H_ */
|