Commit f197a7aa authored by Rajesh Borundia's avatar Rajesh Borundia Committed by David S. Miller

qlcnic: VF-PF communication channel implementation

o Adapter provides communication channel between VF and PF.
  Any control commands from the VF driver are sent to the PF driver
  through this communication channel. PF driver validates the
  commands before sending them to the adapter. Similarly PF driver
  forwards any control command responses  to the VF driver
  through this communication channel.  Adapter sends message pending
  event to VF or PF when there is an outstanding response or a command
  for VF or PF respectively. When a command or a response is sent over
  a channel VF or PF cannot send another command or a response
  until adapter sends a channel free event. Adapter allocates 1K area to
  VF and  PF each for this communication.
o Commands and  responses are encapsulated in a header. Header determines
  sequence id, number of fragments, fragment number etc.
Signed-off-by: default avatarManish Chopra <manish.chopra@qlogic.com>
Signed-off-by: default avatarSucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: default avatarRajesh Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent da6c8063
...@@ -1360,6 +1360,7 @@ struct _cdrp_cmd { ...@@ -1360,6 +1360,7 @@ struct _cdrp_cmd {
struct qlcnic_cmd_args { struct qlcnic_cmd_args {
struct _cdrp_cmd req; struct _cdrp_cmd req;
struct _cdrp_cmd rsp; struct _cdrp_cmd rsp;
int op_type;
}; };
int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter); int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#define QLCNIC_MAX_TX_QUEUES 1 #define QLCNIC_MAX_TX_QUEUES 1
#define RSS_HASHTYPE_IP_TCP 0x3 #define RSS_HASHTYPE_IP_TCP 0x3
#define QLC_83XX_FW_MBX_CMD 0
/* status descriptor mailbox data /* status descriptor mailbox data
* @phy_addr_{low|high}: physical address of buffer * @phy_addr_{low|high}: physical address of buffer
...@@ -211,6 +212,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { ...@@ -211,6 +212,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
{QLCNIC_CMD_GET_LED_CONFIG, 1, 5}, {QLCNIC_CMD_GET_LED_CONFIG, 1, 5},
{QLCNIC_CMD_ADD_RCV_RINGS, 130, 26}, {QLCNIC_CMD_ADD_RCV_RINGS, 130, 26},
{QLCNIC_CMD_CONFIG_VPORT, 4, 4}, {QLCNIC_CMD_CONFIG_VPORT, 4, 4},
{QLCNIC_CMD_BC_EVENT_SETUP, 2, 1},
}; };
const u32 qlcnic_83xx_ext_reg_tbl[] = { const u32 qlcnic_83xx_ext_reg_tbl[] = {
...@@ -824,7 +826,7 @@ static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter, ...@@ -824,7 +826,7 @@ static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter,
} }
/* Mailbox response for mac rcode */ /* Mailbox response for mac rcode */
static u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter) u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter)
{ {
u32 fw_data; u32 fw_data;
u8 mac_cmd_rcode; u8 mac_cmd_rcode;
...@@ -838,7 +840,7 @@ static u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter) ...@@ -838,7 +840,7 @@ static u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter)
return 1; return 1;
} }
static u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter) u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter)
{ {
u32 data; u32 data;
unsigned long wait_time = 0; unsigned long wait_time = 0;
...@@ -953,6 +955,7 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx, ...@@ -953,6 +955,7 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl); size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl);
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
if (type == mbx_tbl[i].cmd) { if (type == mbx_tbl[i].cmd) {
mbx->op_type = QLC_83XX_FW_MBX_CMD;
mbx->req.num = mbx_tbl[i].in_args; mbx->req.num = mbx_tbl[i].in_args;
mbx->rsp.num = mbx_tbl[i].out_args; mbx->rsp.num = mbx_tbl[i].out_args;
mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32), mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32),
...@@ -970,10 +973,10 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx, ...@@ -970,10 +973,10 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num); memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
temp = adapter->ahw->fw_hal_version << 29; temp = adapter->ahw->fw_hal_version << 29;
mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp); mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp);
break; return 0;
} }
} }
return 0; return -EINVAL;
} }
void qlcnic_83xx_idc_aen_work(struct work_struct *work) void qlcnic_83xx_idc_aen_work(struct work_struct *work)
...@@ -1029,6 +1032,9 @@ void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter) ...@@ -1029,6 +1032,9 @@ void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
break; break;
case QLCNIC_MBX_TIME_EXTEND_EVENT: case QLCNIC_MBX_TIME_EXTEND_EVENT:
break; break;
case QLCNIC_MBX_BC_EVENT:
qlcnic_sriov_handle_bc_event(adapter, event[1]);
break;
case QLCNIC_MBX_SFP_INSERT_EVENT: case QLCNIC_MBX_SFP_INSERT_EVENT:
dev_info(&adapter->pdev->dev, "SFP+ Insert AEN:0x%x.\n", dev_info(&adapter->pdev->dev, "SFP+ Insert AEN:0x%x.\n",
QLCNIC_MBX_RSP(event[0])); QLCNIC_MBX_RSP(event[0]));
......
...@@ -456,4 +456,6 @@ int qlcnic_83xx_set_led(struct net_device *, enum ethtool_phys_id_state); ...@@ -456,4 +456,6 @@ int qlcnic_83xx_set_led(struct net_device *, enum ethtool_phys_id_state);
int qlcnic_83xx_flash_test(struct qlcnic_adapter *); int qlcnic_83xx_flash_test(struct qlcnic_adapter *);
int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *); int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *);
int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *); int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *);
u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *);
u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *);
#endif #endif
...@@ -83,6 +83,7 @@ enum qlcnic_regs { ...@@ -83,6 +83,7 @@ enum qlcnic_regs {
#define QLCNIC_CMD_CONFIG_PORT 0x2e #define QLCNIC_CMD_CONFIG_PORT 0x2e
#define QLCNIC_CMD_TEMP_SIZE 0x2f #define QLCNIC_CMD_TEMP_SIZE 0x2f
#define QLCNIC_CMD_GET_TEMP_HDR 0x30 #define QLCNIC_CMD_GET_TEMP_HDR 0x30
#define QLCNIC_CMD_BC_EVENT_SETUP 0x31
#define QLCNIC_CMD_CONFIG_VPORT 0x32 #define QLCNIC_CMD_CONFIG_VPORT 0x32
#define QLCNIC_CMD_GET_MAC_STATS 0x37 #define QLCNIC_CMD_GET_MAC_STATS 0x37
#define QLCNIC_CMD_SET_DRV_VER 0x38 #define QLCNIC_CMD_SET_DRV_VER 0x38
...@@ -115,6 +116,7 @@ enum qlcnic_regs { ...@@ -115,6 +116,7 @@ enum qlcnic_regs {
#define QLCNIC_SET_FAC_DEF_MAC 5 #define QLCNIC_SET_FAC_DEF_MAC 5
#define QLCNIC_MBX_LINK_EVENT 0x8001 #define QLCNIC_MBX_LINK_EVENT 0x8001
#define QLCNIC_MBX_BC_EVENT 0x8002
#define QLCNIC_MBX_COMP_EVENT 0x8100 #define QLCNIC_MBX_COMP_EVENT 0x8100
#define QLCNIC_MBX_REQUEST_EVENT 0x8101 #define QLCNIC_MBX_REQUEST_EVENT 0x8101
#define QLCNIC_MBX_TIME_EXTEND_EVENT 0x8102 #define QLCNIC_MBX_TIME_EXTEND_EVENT 0x8102
......
...@@ -15,6 +15,84 @@ ...@@ -15,6 +15,84 @@
extern const u32 qlcnic_83xx_reg_tbl[]; extern const u32 qlcnic_83xx_reg_tbl[];
extern const u32 qlcnic_83xx_ext_reg_tbl[]; extern const u32 qlcnic_83xx_ext_reg_tbl[];
struct qlcnic_bc_payload {
u64 payload[126];
};
struct qlcnic_bc_hdr {
#if defined(__LITTLE_ENDIAN)
u8 version;
u8 msg_type:4;
u8 rsvd1:3;
u8 op_type:1;
u8 num_cmds;
u8 num_frags;
u8 frag_num;
u8 cmd_op;
u16 seq_id;
u64 rsvd3;
#elif defined(__BIG_ENDIAN)
u8 num_frags;
u8 num_cmds;
u8 op_type:1;
u8 rsvd1:3;
u8 msg_type:4;
u8 version;
u16 seq_id;
u8 cmd_op;
u8 frag_num;
u64 rsvd3;
#endif
};
enum qlcnic_bc_commands {
QLCNIC_BC_CMD_CHANNEL_INIT = 0x0,
QLCNIC_BC_CMD_CHANNEL_TERM = 0x1,
};
#define QLC_BC_CMD 1
struct qlcnic_trans_list {
/* Lock for manipulating list */
spinlock_t lock;
struct list_head wait_list;
int count;
};
enum qlcnic_trans_state {
QLC_INIT = 0,
QLC_WAIT_FOR_CHANNEL_FREE,
QLC_WAIT_FOR_RESP,
QLC_ABORT,
QLC_END,
};
struct qlcnic_bc_trans {
u8 func_id;
u8 active;
u8 curr_rsp_frag;
u8 curr_req_frag;
u16 cmd_id;
u16 req_pay_size;
u16 rsp_pay_size;
u32 trans_id;
enum qlcnic_trans_state trans_state;
struct list_head list;
struct qlcnic_bc_hdr *req_hdr;
struct qlcnic_bc_hdr *rsp_hdr;
struct qlcnic_bc_payload *req_pay;
struct qlcnic_bc_payload *rsp_pay;
struct completion resp_cmpl;
struct qlcnic_vf_info *vf;
};
enum qlcnic_vf_state {
QLC_BC_VF_SEND = 0,
QLC_BC_VF_RECV,
QLC_BC_VF_CHANNEL,
QLC_BC_VF_STATE,
};
struct qlcnic_resources { struct qlcnic_resources {
u16 num_tx_mac_filters; u16 num_tx_mac_filters;
u16 num_rx_ucast_mac_filters; u16 num_rx_ucast_mac_filters;
...@@ -34,10 +112,36 @@ struct qlcnic_resources { ...@@ -34,10 +112,36 @@ struct qlcnic_resources {
u16 max_remote_ipv6_addrs; u16 max_remote_ipv6_addrs;
}; };
struct qlcnic_vport {
u16 handle;
u8 mac[6];
};
struct qlcnic_vf_info {
u8 pci_func;
unsigned long state;
struct completion ch_free_cmpl;
struct work_struct trans_work;
/* It synchronizes commands sent from VF */
struct mutex send_cmd_lock;
struct qlcnic_bc_trans *send_cmd;
struct qlcnic_trans_list rcv_act;
struct qlcnic_trans_list rcv_pend;
struct qlcnic_adapter *adapter;
struct qlcnic_vport *vp;
};
struct qlcnic_back_channel {
u16 trans_counter;
struct workqueue_struct *bc_trans_wq;
};
struct qlcnic_sriov { struct qlcnic_sriov {
u16 vp_handle; u16 vp_handle;
u8 num_vfs; u8 num_vfs;
struct qlcnic_resources ff_max; struct qlcnic_resources ff_max;
struct qlcnic_back_channel bc;
struct qlcnic_vf_info *vf_info;
}; };
int qlcnic_sriov_init(struct qlcnic_adapter *, int); int qlcnic_sriov_init(struct qlcnic_adapter *, int);
...@@ -46,6 +150,10 @@ void __qlcnic_sriov_cleanup(struct qlcnic_adapter *); ...@@ -46,6 +150,10 @@ void __qlcnic_sriov_cleanup(struct qlcnic_adapter *);
void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *); void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *);
int qlcnic_sriov_vf_init(struct qlcnic_adapter *, int); int qlcnic_sriov_vf_init(struct qlcnic_adapter *, int);
void qlcnic_sriov_vf_set_ops(struct qlcnic_adapter *); void qlcnic_sriov_vf_set_ops(struct qlcnic_adapter *);
int qlcnic_sriov_func_to_index(struct qlcnic_adapter *, u8);
int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *, u8);
void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *, u32);
int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *, u8);
static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter) static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter)
{ {
...@@ -53,6 +161,9 @@ static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter) ...@@ -53,6 +161,9 @@ static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter)
} }
#ifdef CONFIG_QLCNIC_SRIOV #ifdef CONFIG_QLCNIC_SRIOV
void qlcnic_sriov_pf_process_bc_cmd(struct qlcnic_adapter *,
struct qlcnic_bc_trans *,
struct qlcnic_cmd_args *);
void qlcnic_sriov_pf_disable(struct qlcnic_adapter *); void qlcnic_sriov_pf_disable(struct qlcnic_adapter *);
void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *); void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *);
int qlcnic_pci_sriov_configure(struct pci_dev *, int); int qlcnic_pci_sriov_configure(struct pci_dev *, int);
......
...@@ -13,6 +13,10 @@ ...@@ -13,6 +13,10 @@
static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8); static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8);
struct qlcnic_sriov_cmd_handler {
int (*fn) (struct qlcnic_bc_trans *, struct qlcnic_cmd_args *);
};
static int qlcnic_sriov_pf_set_vport_info(struct qlcnic_adapter *adapter, static int qlcnic_sriov_pf_set_vport_info(struct qlcnic_adapter *adapter,
struct qlcnic_info *npar_info, struct qlcnic_info *npar_info,
u16 vport_id) u16 vport_id)
...@@ -174,27 +178,54 @@ static void qlcnic_sriov_pf_reset_vport_handle(struct qlcnic_adapter *adapter, ...@@ -174,27 +178,54 @@ static void qlcnic_sriov_pf_reset_vport_handle(struct qlcnic_adapter *adapter,
u8 func) u8 func)
{ {
struct qlcnic_sriov *sriov = adapter->ahw->sriov; struct qlcnic_sriov *sriov = adapter->ahw->sriov;
struct qlcnic_vport *vp;
int index;
if (adapter->ahw->pci_func == func) if (adapter->ahw->pci_func == func) {
sriov->vp_handle = 0; sriov->vp_handle = 0;
} else {
index = qlcnic_sriov_func_to_index(adapter, func);
if (index < 0)
return;
vp = sriov->vf_info[index].vp;
vp->handle = 0;
}
} }
static void qlcnic_sriov_pf_set_vport_handle(struct qlcnic_adapter *adapter, static void qlcnic_sriov_pf_set_vport_handle(struct qlcnic_adapter *adapter,
u16 vport_handle, u8 func) u16 vport_handle, u8 func)
{ {
struct qlcnic_sriov *sriov = adapter->ahw->sriov; struct qlcnic_sriov *sriov = adapter->ahw->sriov;
struct qlcnic_vport *vp;
int index;
if (adapter->ahw->pci_func == func) if (adapter->ahw->pci_func == func) {
sriov->vp_handle = vport_handle; sriov->vp_handle = vport_handle;
} else {
index = qlcnic_sriov_func_to_index(adapter, func);
if (index < 0)
return;
vp = sriov->vf_info[index].vp;
vp->handle = vport_handle;
}
} }
static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *adapter, static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *adapter,
u8 func) u8 func)
{ {
struct qlcnic_sriov *sriov = adapter->ahw->sriov; struct qlcnic_sriov *sriov = adapter->ahw->sriov;
struct qlcnic_vf_info *vf_info;
int index;
if (adapter->ahw->pci_func == func) if (adapter->ahw->pci_func == func) {
return sriov->vp_handle; return sriov->vp_handle;
} else {
index = qlcnic_sriov_func_to_index(adapter, func);
if (index >= 0) {
vf_info = &sriov->vf_info[index];
return vf_info->vp->handle;
}
}
return -EINVAL; return -EINVAL;
} }
...@@ -273,6 +304,7 @@ void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) ...@@ -273,6 +304,7 @@ void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter)
if (!qlcnic_sriov_enable_check(adapter)) if (!qlcnic_sriov_enable_check(adapter))
return; return;
qlcnic_sriov_cfg_bc_intr(adapter, 0);
qlcnic_sriov_pf_config_vport(adapter, 0, func); qlcnic_sriov_pf_config_vport(adapter, 0, func);
qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0); qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0);
__qlcnic_sriov_cleanup(adapter); __qlcnic_sriov_cleanup(adapter);
...@@ -349,6 +381,10 @@ static int qlcnic_sriov_pf_init(struct qlcnic_adapter *adapter) ...@@ -349,6 +381,10 @@ static int qlcnic_sriov_pf_init(struct qlcnic_adapter *adapter)
if (err) if (err)
goto delete_vport; goto delete_vport;
err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
if (err)
goto delete_vport;
ahw->physical_port = (u8) nic_info.phys_port; ahw->physical_port = (u8) nic_info.phys_port;
ahw->switch_mode = nic_info.switch_mode; ahw->switch_mode = nic_info.switch_mode;
ahw->max_mtu = nic_info.max_mtu; ahw->max_mtu = nic_info.max_mtu;
...@@ -453,3 +489,79 @@ int qlcnic_pci_sriov_configure(struct pci_dev *dev, int num_vfs) ...@@ -453,3 +489,79 @@ int qlcnic_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
clear_bit(__QLCNIC_RESETTING, &adapter->state); clear_bit(__QLCNIC_RESETTING, &adapter->state);
return err; return err;
} }
static int qlcnic_sriov_set_vf_vport_info(struct qlcnic_adapter *adapter,
u16 func)
{
struct qlcnic_info defvp_info;
int err;
err = qlcnic_sriov_pf_cal_res_limit(adapter, &defvp_info, func);
if (err)
return -EIO;
return 0;
}
static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,
struct qlcnic_cmd_args *cmd)
{
struct qlcnic_vf_info *vf = trans->vf;
struct qlcnic_adapter *adapter = vf->adapter;
int err;
u16 func = vf->pci_func;
cmd->rsp.arg[0] = trans->req_hdr->cmd_op;
cmd->rsp.arg[0] |= (1 << 16);
if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) {
err = qlcnic_sriov_pf_config_vport(adapter, 1, func);
if (!err) {
err = qlcnic_sriov_set_vf_vport_info(adapter, func);
if (err)
qlcnic_sriov_pf_config_vport(adapter, 0, func);
}
} else {
err = qlcnic_sriov_pf_config_vport(adapter, 0, func);
}
if (err)
goto err_out;
cmd->rsp.arg[0] |= (1 << 25);
if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT)
set_bit(QLC_BC_VF_STATE, &vf->state);
else
clear_bit(QLC_BC_VF_STATE, &vf->state);
return err;
err_out:
cmd->rsp.arg[0] |= (2 << 25);
return err;
}
static const struct qlcnic_sriov_cmd_handler qlcnic_pf_bc_cmd_hdlr[] = {
[QLCNIC_BC_CMD_CHANNEL_INIT] = {&qlcnic_sriov_pf_channel_cfg_cmd},
[QLCNIC_BC_CMD_CHANNEL_TERM] = {&qlcnic_sriov_pf_channel_cfg_cmd},
};
void qlcnic_sriov_pf_process_bc_cmd(struct qlcnic_adapter *adapter,
struct qlcnic_bc_trans *trans,
struct qlcnic_cmd_args *cmd)
{
u8 size, cmd_op;
cmd_op = trans->req_hdr->cmd_op;
if (trans->req_hdr->op_type == QLC_BC_CMD) {
size = ARRAY_SIZE(qlcnic_pf_bc_cmd_hdlr);
if (cmd_op < size) {
qlcnic_pf_bc_cmd_hdlr[cmd_op].fn(trans, cmd);
return;
}
}
cmd->rsp.arg[0] |= (0x9 << 25);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment