From 02feda1758755f2b5dbed060bdffda5e5b0244ba Mon Sep 17 00:00:00 2001 From: Rajesh Borundia Date: Fri, 29 Mar 2013 05:46:33 +0000 Subject: qlcnic: Support SR-IOV enable and disable o Add QLCNIC_SRIOV to Kconfig. o Provide PCI sysfs hooks to enable and disable SR-IOV. o Allow enabling only when CONFIG_QLCNIC_SRIOV is defined. o qlcnic_sriov_pf.c has all the PF related SR-IOV functionality. o qlcnic_sriov_common.c has VF functionality and SR-IOV functionality which is common between VF and PF. o qlcnic_sriov.h is a common header file for SR-IOV defines. Signed-off-by: Manish Chopra Signed-off-by: Sucheta Chakraborty Signed-off-by: Rajesh Borundia Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index 5b8749eda11f..91db4ed0a58e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h @@ -83,6 +83,7 @@ enum qlcnic_regs { #define QLCNIC_CMD_CONFIG_PORT 0x2e #define QLCNIC_CMD_TEMP_SIZE 0x2f #define QLCNIC_CMD_GET_TEMP_HDR 0x30 +#define QLCNIC_CMD_CONFIG_VPORT 0x32 #define QLCNIC_CMD_GET_MAC_STATS 0x37 #define QLCNIC_CMD_SET_DRV_VER 0x38 #define QLCNIC_CMD_CONFIGURE_RSS 0x41 -- cgit v1.2.3-59-g8ed1b From f197a7aa62888f27c9a7976b18eb4f040f6606ce Mon Sep 17 00:00:00 2001 From: Rajesh Borundia Date: Fri, 29 Mar 2013 05:46:36 +0000 Subject: 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: Manish Chopra Signed-off-by: Sucheta Chakraborty Signed-off-by: Rajesh Borundia Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 1 + .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 14 +- .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 2 + drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | 2 + drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h | 111 +++ .../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 951 ++++++++++++++++++++- .../net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | 118 ++- 7 files changed, 1191 insertions(+), 8 deletions(-) (limited to 'drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 002f0bdc5b5e..78d1db686bdf 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -1360,6 +1360,7 @@ struct _cdrp_cmd { struct qlcnic_cmd_args { struct _cdrp_cmd req; struct _cdrp_cmd rsp; + int op_type; }; int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index c08974fd07e3..89dcea593646 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -14,6 +14,7 @@ #define QLCNIC_MAX_TX_QUEUES 1 #define RSS_HASHTYPE_IP_TCP 0x3 +#define QLC_83XX_FW_MBX_CMD 0 /* status descriptor mailbox data * @phy_addr_{low|high}: physical address of buffer @@ -211,6 +212,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { {QLCNIC_CMD_GET_LED_CONFIG, 1, 5}, {QLCNIC_CMD_ADD_RCV_RINGS, 130, 26}, {QLCNIC_CMD_CONFIG_VPORT, 4, 4}, + {QLCNIC_CMD_BC_EVENT_SETUP, 2, 1}, }; const u32 qlcnic_83xx_ext_reg_tbl[] = { @@ -824,7 +826,7 @@ static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter, } /* 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; u8 mac_cmd_rcode; @@ -838,7 +840,7 @@ static u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter) return 1; } -static u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter) +u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter) { u32 data; unsigned long wait_time = 0; @@ -953,6 +955,7 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx, size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl); for (i = 0; i < size; i++) { if (type == mbx_tbl[i].cmd) { + mbx->op_type = QLC_83XX_FW_MBX_CMD; mbx->req.num = mbx_tbl[i].in_args; mbx->rsp.num = mbx_tbl[i].out_args; mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32), @@ -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); temp = adapter->ahw->fw_hal_version << 29; 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) @@ -1029,6 +1032,9 @@ void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter) break; case QLCNIC_MBX_TIME_EXTEND_EVENT: break; + case QLCNIC_MBX_BC_EVENT: + qlcnic_sriov_handle_bc_event(adapter, event[1]); + break; case QLCNIC_MBX_SFP_INSERT_EVENT: dev_info(&adapter->pdev->dev, "SFP+ Insert AEN:0x%x.\n", QLCNIC_MBX_RSP(event[0])); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index da0fcc78407b..3e8dc0b136e6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -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_enable_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 diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index 91db4ed0a58e..d606e50d8902 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h @@ -83,6 +83,7 @@ enum qlcnic_regs { #define QLCNIC_CMD_CONFIG_PORT 0x2e #define QLCNIC_CMD_TEMP_SIZE 0x2f #define QLCNIC_CMD_GET_TEMP_HDR 0x30 +#define QLCNIC_CMD_BC_EVENT_SETUP 0x31 #define QLCNIC_CMD_CONFIG_VPORT 0x32 #define QLCNIC_CMD_GET_MAC_STATS 0x37 #define QLCNIC_CMD_SET_DRV_VER 0x38 @@ -115,6 +116,7 @@ enum qlcnic_regs { #define QLCNIC_SET_FAC_DEF_MAC 5 #define QLCNIC_MBX_LINK_EVENT 0x8001 +#define QLCNIC_MBX_BC_EVENT 0x8002 #define QLCNIC_MBX_COMP_EVENT 0x8100 #define QLCNIC_MBX_REQUEST_EVENT 0x8101 #define QLCNIC_MBX_TIME_EXTEND_EVENT 0x8102 diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h index e849939bbe5e..00053ad8bc3c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h @@ -15,6 +15,84 @@ extern const u32 qlcnic_83xx_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 { u16 num_tx_mac_filters; u16 num_rx_ucast_mac_filters; @@ -34,10 +112,36 @@ struct qlcnic_resources { 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 { u16 vp_handle; u8 num_vfs; struct qlcnic_resources ff_max; + struct qlcnic_back_channel bc; + struct qlcnic_vf_info *vf_info; }; int qlcnic_sriov_init(struct qlcnic_adapter *, int); @@ -46,6 +150,10 @@ void __qlcnic_sriov_cleanup(struct qlcnic_adapter *); void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *); int qlcnic_sriov_vf_init(struct qlcnic_adapter *, int); 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) { @@ -53,6 +161,9 @@ static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter) } #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_cleanup(struct qlcnic_adapter *); int qlcnic_pci_sriov_configure(struct pci_dev *, int); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 0e097f79a14a..0615086f4526 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -10,6 +10,20 @@ #include "qlcnic_83xx_hw.h" #include +#define QLC_BC_COMMAND 0 +#define QLC_BC_RESPONSE 1 + +#define QLC_MBOX_RESP_TIMEOUT (10 * HZ) +#define QLC_MBOX_CH_FREE_TIMEOUT (10 * HZ) + +#define QLC_BC_MSG 0 +#define QLC_BC_CFREE 1 +#define QLC_BC_HDR_SZ 16 +#define QLC_BC_PAYLOAD_SZ (1024 - QLC_BC_HDR_SZ) + +static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *, + struct qlcnic_cmd_args *); + static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = { .read_crb = qlcnic_83xx_read_crb, .write_crb = qlcnic_83xx_write_crb, @@ -18,6 +32,7 @@ static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = { .get_mac_address = qlcnic_83xx_get_mac_address, .setup_intr = qlcnic_83xx_setup_intr, .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args, + .mbx_cmd = qlcnic_sriov_vf_mbx_op, .get_func_no = qlcnic_83xx_get_func_no, .api_lock = qlcnic_83xx_cam_lock, .api_unlock = qlcnic_83xx_cam_unlock, @@ -49,9 +64,50 @@ static struct qlcnic_nic_template qlcnic_sriov_vf_ops = { .clear_legacy_intr = qlcnic_83xx_clear_legacy_intr, }; +static const struct qlcnic_mailbox_metadata qlcnic_sriov_bc_mbx_tbl[] = { + {QLCNIC_BC_CMD_CHANNEL_INIT, 2, 2}, + {QLCNIC_BC_CMD_CHANNEL_TERM, 2, 2}, +}; + +static inline bool qlcnic_sriov_bc_msg_check(u32 val) +{ + return (val & (1 << QLC_BC_MSG)) ? true : false; +} + +static inline bool qlcnic_sriov_channel_free_check(u32 val) +{ + return (val & (1 << QLC_BC_CFREE)) ? true : false; +} + +static inline u8 qlcnic_sriov_target_func_id(u32 val) +{ + return (val >> 4) & 0xff; +} + +static int qlcnic_sriov_virtid_fn(struct qlcnic_adapter *adapter, int vf_id) +{ + struct pci_dev *dev = adapter->pdev; + int pos; + u16 stride, offset; + + if (qlcnic_sriov_vf_check(adapter)) + return 0; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV); + pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset); + pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride); + + return (dev->devfn + offset + stride * vf_id) & 0xff; +} + int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs) { struct qlcnic_sriov *sriov; + struct qlcnic_back_channel *bc; + struct workqueue_struct *wq; + struct qlcnic_vport *vp; + struct qlcnic_vf_info *vf; + int err, i; if (!qlcnic_sriov_enable_check(adapter)) return -EIO; @@ -62,19 +118,84 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs) adapter->ahw->sriov = sriov; sriov->num_vfs = num_vfs; + bc = &sriov->bc; + sriov->vf_info = kzalloc(sizeof(struct qlcnic_vf_info) * + num_vfs, GFP_KERNEL); + if (!sriov->vf_info) { + err = -ENOMEM; + goto qlcnic_free_sriov; + } + + wq = create_singlethread_workqueue("bc-trans"); + if (wq == NULL) { + err = -ENOMEM; + dev_err(&adapter->pdev->dev, + "Cannot create bc-trans workqueue\n"); + goto qlcnic_free_vf_info; + } + + bc->bc_trans_wq = wq; + + for (i = 0; i < num_vfs; i++) { + vf = &sriov->vf_info[i]; + vf->adapter = adapter; + vf->pci_func = qlcnic_sriov_virtid_fn(adapter, i); + mutex_init(&vf->send_cmd_lock); + INIT_LIST_HEAD(&vf->rcv_act.wait_list); + INIT_LIST_HEAD(&vf->rcv_pend.wait_list); + spin_lock_init(&vf->rcv_act.lock); + spin_lock_init(&vf->rcv_pend.lock); + init_completion(&vf->ch_free_cmpl); + + if (qlcnic_sriov_pf_check(adapter)) { + vp = kzalloc(sizeof(struct qlcnic_vport), GFP_KERNEL); + if (!vp) { + err = -ENOMEM; + goto qlcnic_destroy_trans_wq; + } + sriov->vf_info[i].vp = vp; + random_ether_addr(vp->mac); + dev_info(&adapter->pdev->dev, + "MAC Address %pM is configured for VF %d\n", + vp->mac, i); + } + } + return 0; + +qlcnic_destroy_trans_wq: + destroy_workqueue(bc->bc_trans_wq); + +qlcnic_free_vf_info: + kfree(sriov->vf_info); + +qlcnic_free_sriov: + kfree(adapter->ahw->sriov); + return err; } void __qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter) { + struct qlcnic_sriov *sriov = adapter->ahw->sriov; + struct qlcnic_back_channel *bc = &sriov->bc; + int i; + if (!qlcnic_sriov_enable_check(adapter)) return; + destroy_workqueue(bc->bc_trans_wq); + + for (i = 0; i < sriov->num_vfs; i++) + kfree(sriov->vf_info[i].vp); + + kfree(sriov->vf_info); kfree(adapter->ahw->sriov); } static void qlcnic_sriov_vf_cleanup(struct qlcnic_adapter *adapter) { + qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM); + qlcnic_sriov_cfg_bc_intr(adapter, 0); __qlcnic_sriov_cleanup(adapter); } @@ -87,6 +208,103 @@ void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter) qlcnic_sriov_vf_cleanup(adapter); } +static int qlcnic_sriov_post_bc_msg(struct qlcnic_adapter *adapter, u32 *hdr, + u32 *pay, u8 pci_func, u8 size) +{ + struct qlcnic_hardware_context *ahw = adapter->ahw; + unsigned long flags; + u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, val; + u16 opcode; + u8 mbx_err_code; + int i, j; + + opcode = ((struct qlcnic_bc_hdr *)hdr)->cmd_op; + + if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) { + dev_info(&adapter->pdev->dev, + "Mailbox cmd attempted, 0x%x\n", opcode); + dev_info(&adapter->pdev->dev, "Mailbox detached\n"); + return 0; + } + + spin_lock_irqsave(&ahw->mbx_lock, flags); + + mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL); + if (mbx_val) { + QLCDB(adapter, DRV, "Mailbox cmd attempted, 0x%x\n", opcode); + spin_unlock_irqrestore(&ahw->mbx_lock, flags); + return QLCNIC_RCODE_TIMEOUT; + } + /* Fill in mailbox registers */ + val = size + (sizeof(struct qlcnic_bc_hdr) / sizeof(u32)); + mbx_cmd = 0x31 | (val << 16) | (adapter->ahw->fw_hal_version << 29); + + writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0)); + mbx_cmd = 0x1 | (1 << 4); + + if (qlcnic_sriov_pf_check(adapter)) + mbx_cmd |= (pci_func << 5); + + writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 1)); + for (i = 2, j = 0; j < (sizeof(struct qlcnic_bc_hdr) / sizeof(u32)); + i++, j++) { + writel(*(hdr++), QLCNIC_MBX_HOST(ahw, i)); + } + for (j = 0; j < size; j++, i++) + writel(*(pay++), QLCNIC_MBX_HOST(ahw, i)); + + /* Signal FW about the impending command */ + QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER); + + /* Waiting for the mailbox cmd to complete and while waiting here + * some AEN might arrive. If more than 5 seconds expire we can + * assume something is wrong. + */ +poll: + rsp = qlcnic_83xx_mbx_poll(adapter); + if (rsp != QLCNIC_RCODE_TIMEOUT) { + /* Get the FW response data */ + fw_data = readl(QLCNIC_MBX_FW(ahw, 0)); + if (fw_data & QLCNIC_MBX_ASYNC_EVENT) { + qlcnic_83xx_process_aen(adapter); + mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL); + if (mbx_val) + goto poll; + } + mbx_err_code = QLCNIC_MBX_STATUS(fw_data); + rsp_num = QLCNIC_MBX_NUM_REGS(fw_data); + opcode = QLCNIC_MBX_RSP(fw_data); + + switch (mbx_err_code) { + case QLCNIC_MBX_RSP_OK: + case QLCNIC_MBX_PORT_RSP_OK: + rsp = QLCNIC_RCODE_SUCCESS; + break; + default: + if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) { + rsp = qlcnic_83xx_mac_rcode(adapter); + if (!rsp) + goto out; + } + dev_err(&adapter->pdev->dev, + "MBX command 0x%x failed with err:0x%x\n", + opcode, mbx_err_code); + rsp = mbx_err_code; + break; + } + goto out; + } + + dev_err(&adapter->pdev->dev, "MBX command 0x%x timed out\n", + QLCNIC_MBX_RSP(mbx_cmd)); + rsp = QLCNIC_RCODE_TIMEOUT; +out: + /* clear fw mbx control register */ + QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER); + spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags); + return rsp; +} + static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, int pci_using_dac) { @@ -110,15 +328,29 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, if (err) goto err_out_disable_mbx_intr; - err = qlcnic_setup_netdev(adapter, adapter->netdev, pci_using_dac); + err = qlcnic_sriov_cfg_bc_intr(adapter, 1); if (err) goto err_out_cleanup_sriov; + err = qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_INIT); + if (err) + goto err_out_disable_bc_intr; + + err = qlcnic_setup_netdev(adapter, adapter->netdev, pci_using_dac); + if (err) + goto err_out_send_channel_term; + pci_set_drvdata(adapter->pdev, adapter); dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n", adapter->netdev->name); return 0; +err_out_send_channel_term: + qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM); + +err_out_disable_bc_intr: + qlcnic_sriov_cfg_bc_intr(adapter, 0); + err_out_cleanup_sriov: __qlcnic_sriov_cleanup(adapter); @@ -173,3 +405,720 @@ void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *ahw) ahw->reg_tbl = (u32 *)qlcnic_83xx_reg_tbl; ahw->ext_reg_tbl = (u32 *)qlcnic_83xx_ext_reg_tbl; } + +static u32 qlcnic_sriov_get_bc_paysize(u32 real_pay_size, u8 curr_frag) +{ + u32 pay_size; + + pay_size = real_pay_size / ((curr_frag + 1) * QLC_BC_PAYLOAD_SZ); + + if (pay_size) + pay_size = QLC_BC_PAYLOAD_SZ; + else + pay_size = real_pay_size % QLC_BC_PAYLOAD_SZ; + + return pay_size; +} + +int qlcnic_sriov_func_to_index(struct qlcnic_adapter *adapter, u8 pci_func) +{ + struct qlcnic_vf_info *vf_info = adapter->ahw->sriov->vf_info; + u8 i; + + if (qlcnic_sriov_vf_check(adapter)) + return 0; + + for (i = 0; i < adapter->ahw->sriov->num_vfs; i++) { + if (vf_info[i].pci_func == pci_func) + return i; + } + + return -EINVAL; +} + +static inline int qlcnic_sriov_alloc_bc_trans(struct qlcnic_bc_trans **trans) +{ + *trans = kzalloc(sizeof(struct qlcnic_bc_trans), GFP_ATOMIC); + if (!*trans) + return -ENOMEM; + + init_completion(&(*trans)->resp_cmpl); + return 0; +} + +static inline int qlcnic_sriov_alloc_bc_msg(struct qlcnic_bc_hdr **hdr, + u32 size) +{ + *hdr = kzalloc(sizeof(struct qlcnic_bc_hdr) * size, GFP_ATOMIC); + if (!*hdr) + return -ENOMEM; + + return 0; +} + +static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *mbx, u32 type) +{ + const struct qlcnic_mailbox_metadata *mbx_tbl; + int i, size; + + mbx_tbl = qlcnic_sriov_bc_mbx_tbl; + size = ARRAY_SIZE(qlcnic_sriov_bc_mbx_tbl); + + for (i = 0; i < size; i++) { + if (type == mbx_tbl[i].cmd) { + mbx->op_type = QLC_BC_CMD; + mbx->req.num = mbx_tbl[i].in_args; + mbx->rsp.num = mbx_tbl[i].out_args; + mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32), + GFP_ATOMIC); + if (!mbx->req.arg) + return -ENOMEM; + mbx->rsp.arg = kcalloc(mbx->rsp.num, sizeof(u32), + GFP_ATOMIC); + if (!mbx->rsp.arg) { + kfree(mbx->req.arg); + mbx->req.arg = NULL; + return -ENOMEM; + } + memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num); + memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num); + mbx->req.arg[0] = (type | (mbx->req.num << 16) | + (3 << 29)); + return 0; + } + } + return -EINVAL; +} + +static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans, + struct qlcnic_cmd_args *cmd, + u16 seq, u8 msg_type) +{ + struct qlcnic_bc_hdr *hdr; + int i; + u32 num_regs, bc_pay_sz; + u16 remainder; + u8 cmd_op, num_frags, t_num_frags; + + bc_pay_sz = QLC_BC_PAYLOAD_SZ; + if (msg_type == QLC_BC_COMMAND) { + trans->req_pay = (struct qlcnic_bc_payload *)cmd->req.arg; + trans->rsp_pay = (struct qlcnic_bc_payload *)cmd->rsp.arg; + num_regs = cmd->req.num; + trans->req_pay_size = (num_regs * 4); + num_regs = cmd->rsp.num; + trans->rsp_pay_size = (num_regs * 4); + cmd_op = cmd->req.arg[0] & 0xff; + remainder = (trans->req_pay_size) % (bc_pay_sz); + num_frags = (trans->req_pay_size) / (bc_pay_sz); + if (remainder) + num_frags++; + t_num_frags = num_frags; + if (qlcnic_sriov_alloc_bc_msg(&trans->req_hdr, num_frags)) + return -ENOMEM; + remainder = (trans->rsp_pay_size) % (bc_pay_sz); + num_frags = (trans->rsp_pay_size) / (bc_pay_sz); + if (remainder) + num_frags++; + if (qlcnic_sriov_alloc_bc_msg(&trans->rsp_hdr, num_frags)) + return -ENOMEM; + num_frags = t_num_frags; + hdr = trans->req_hdr; + } else { + cmd->req.arg = (u32 *)trans->req_pay; + cmd->rsp.arg = (u32 *)trans->rsp_pay; + cmd_op = cmd->req.arg[0] & 0xff; + remainder = (trans->rsp_pay_size) % (bc_pay_sz); + num_frags = (trans->rsp_pay_size) / (bc_pay_sz); + if (remainder) + num_frags++; + cmd->req.num = trans->req_pay_size / 4; + cmd->rsp.num = trans->rsp_pay_size / 4; + hdr = trans->rsp_hdr; + } + + trans->trans_id = seq; + trans->cmd_id = cmd_op; + for (i = 0; i < num_frags; i++) { + hdr[i].version = 2; + hdr[i].msg_type = msg_type; + hdr[i].op_type = cmd->op_type; + hdr[i].num_cmds = 1; + hdr[i].num_frags = num_frags; + hdr[i].frag_num = i + 1; + hdr[i].cmd_op = cmd_op; + hdr[i].seq_id = seq; + } + return 0; +} + +static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *trans) +{ + if (!trans) + return; + kfree(trans->req_hdr); + kfree(trans->rsp_hdr); + kfree(trans); +} + +static int qlcnic_sriov_clear_trans(struct qlcnic_vf_info *vf, + struct qlcnic_bc_trans *trans, u8 type) +{ + struct qlcnic_trans_list *t_list; + unsigned long flags; + int ret = 0; + + if (type == QLC_BC_RESPONSE) { + t_list = &vf->rcv_act; + spin_lock_irqsave(&t_list->lock, flags); + t_list->count--; + list_del(&trans->list); + if (t_list->count > 0) + ret = 1; + spin_unlock_irqrestore(&t_list->lock, flags); + } + if (type == QLC_BC_COMMAND) { + while (test_and_set_bit(QLC_BC_VF_SEND, &vf->state)) + msleep(100); + vf->send_cmd = NULL; + clear_bit(QLC_BC_VF_SEND, &vf->state); + } + return ret; +} + +static void qlcnic_sriov_schedule_bc_cmd(struct qlcnic_sriov *sriov, + struct qlcnic_vf_info *vf, + work_func_t func) +{ + INIT_WORK(&vf->trans_work, func); + queue_work(sriov->bc.bc_trans_wq, &vf->trans_work); +} + +static inline void qlcnic_sriov_wait_for_resp(struct qlcnic_bc_trans *trans) +{ + struct completion *cmpl = &trans->resp_cmpl; + + if (wait_for_completion_timeout(cmpl, QLC_MBOX_RESP_TIMEOUT)) + trans->trans_state = QLC_END; + else + trans->trans_state = QLC_ABORT; + + return; +} + +static void qlcnic_sriov_handle_multi_frags(struct qlcnic_bc_trans *trans, + u8 type) +{ + if (type == QLC_BC_RESPONSE) { + trans->curr_rsp_frag++; + if (trans->curr_rsp_frag < trans->rsp_hdr->num_frags) + trans->trans_state = QLC_INIT; + else + trans->trans_state = QLC_END; + } else { + trans->curr_req_frag++; + if (trans->curr_req_frag < trans->req_hdr->num_frags) + trans->trans_state = QLC_INIT; + else + trans->trans_state = QLC_WAIT_FOR_RESP; + } +} + +static void qlcnic_sriov_wait_for_channel_free(struct qlcnic_bc_trans *trans, + u8 type) +{ + struct qlcnic_vf_info *vf = trans->vf; + struct completion *cmpl = &vf->ch_free_cmpl; + + if (!wait_for_completion_timeout(cmpl, QLC_MBOX_CH_FREE_TIMEOUT)) { + trans->trans_state = QLC_ABORT; + return; + } + + clear_bit(QLC_BC_VF_CHANNEL, &vf->state); + qlcnic_sriov_handle_multi_frags(trans, type); +} + +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++) + *(pay++) = readl(QLCNIC_MBX_FW(ahw, i)); +} + +static int __qlcnic_sriov_issue_bc_post(struct qlcnic_vf_info *vf) +{ + int ret = -EBUSY; + u32 timeout = 10000; + + do { + if (!test_and_set_bit(QLC_BC_VF_CHANNEL, &vf->state)) { + ret = 0; + break; + } + mdelay(1); + } while (--timeout); + + return ret; +} + +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 *hdr, *pay; + int ret; + u8 pci_func = trans->func_id; + + if (__qlcnic_sriov_issue_bc_post(vf)) + return -EBUSY; + + 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)); + } + + ret = qlcnic_sriov_post_bc_msg(vf->adapter, hdr, pay, + pci_func, pay_size); + return ret; +} + +static int __qlcnic_sriov_send_bc_msg(struct qlcnic_bc_trans *trans, + struct qlcnic_vf_info *vf, u8 type) +{ + int err; + bool flag = true; + + while (flag) { + switch (trans->trans_state) { + case QLC_INIT: + trans->trans_state = QLC_WAIT_FOR_CHANNEL_FREE; + if (qlcnic_sriov_issue_bc_post(trans, type)) + trans->trans_state = QLC_ABORT; + break; + case QLC_WAIT_FOR_CHANNEL_FREE: + qlcnic_sriov_wait_for_channel_free(trans, type); + break; + case QLC_WAIT_FOR_RESP: + qlcnic_sriov_wait_for_resp(trans); + break; + case QLC_END: + err = 0; + flag = false; + break; + case QLC_ABORT: + err = -EIO; + flag = false; + clear_bit(QLC_BC_VF_CHANNEL, &vf->state); + break; + default: + err = -EIO; + flag = false; + } + } + return err; +} + +static int qlcnic_sriov_send_bc_cmd(struct qlcnic_adapter *adapter, + struct qlcnic_bc_trans *trans, int pci_func) +{ + struct qlcnic_vf_info *vf; + int err, index = qlcnic_sriov_func_to_index(adapter, pci_func); + + if (index < 0) + return -EIO; + + vf = &adapter->ahw->sriov->vf_info[index]; + trans->vf = vf; + trans->func_id = pci_func; + + if (!test_bit(QLC_BC_VF_STATE, &vf->state)) { + if (qlcnic_sriov_pf_check(adapter)) + return -EIO; + if (qlcnic_sriov_vf_check(adapter) && + trans->cmd_id != QLCNIC_BC_CMD_CHANNEL_INIT) + return -EIO; + } + + mutex_lock(&vf->send_cmd_lock); + vf->send_cmd = trans; + err = __qlcnic_sriov_send_bc_msg(trans, vf, QLC_BC_COMMAND); + qlcnic_sriov_clear_trans(vf, trans, QLC_BC_COMMAND); + mutex_unlock(&vf->send_cmd_lock); + return err; +} + +static void __qlcnic_sriov_process_bc_cmd(struct qlcnic_adapter *adapter, + struct qlcnic_bc_trans *trans, + struct qlcnic_cmd_args *cmd) +{ +#ifdef CONFIG_QLCNIC_SRIOV + if (qlcnic_sriov_pf_check(adapter)) { + qlcnic_sriov_pf_process_bc_cmd(adapter, trans, cmd); + return; + } +#endif + cmd->rsp.arg[0] |= (0x9 << 25); + return; +} + +static void qlcnic_sriov_process_bc_cmd(struct work_struct *work) +{ + struct qlcnic_vf_info *vf = container_of(work, struct qlcnic_vf_info, + trans_work); + struct qlcnic_bc_trans *trans = NULL; + struct qlcnic_adapter *adapter = vf->adapter; + struct qlcnic_cmd_args cmd; + u8 req; + + trans = list_first_entry(&vf->rcv_act.wait_list, + struct qlcnic_bc_trans, list); + adapter = vf->adapter; + + if (qlcnic_sriov_prepare_bc_hdr(trans, &cmd, trans->req_hdr->seq_id, + QLC_BC_RESPONSE)) + goto cleanup_trans; + + __qlcnic_sriov_process_bc_cmd(adapter, trans, &cmd); + trans->trans_state = QLC_INIT; + __qlcnic_sriov_send_bc_msg(trans, vf, QLC_BC_RESPONSE); + +cleanup_trans: + qlcnic_free_mbx_args(&cmd); + req = qlcnic_sriov_clear_trans(vf, trans, QLC_BC_RESPONSE); + qlcnic_sriov_cleanup_transaction(trans); + if (req) + qlcnic_sriov_schedule_bc_cmd(adapter->ahw->sriov, vf, + qlcnic_sriov_process_bc_cmd); +} + +static void qlcnic_sriov_handle_bc_resp(struct qlcnic_bc_hdr *hdr, + struct qlcnic_vf_info *vf) +{ + struct qlcnic_bc_trans *trans; + u32 pay_size; + + if (test_and_set_bit(QLC_BC_VF_SEND, &vf->state)) + return; + + trans = vf->send_cmd; + + if (trans == NULL) + goto clear_send; + + if (trans->trans_id != hdr->seq_id) + goto clear_send; + + pay_size = qlcnic_sriov_get_bc_paysize(trans->rsp_pay_size, + trans->curr_rsp_frag); + qlcnic_sriov_pull_bc_msg(vf->adapter, + (u32 *)(trans->rsp_hdr + trans->curr_rsp_frag), + (u32 *)(trans->rsp_pay + trans->curr_rsp_frag), + pay_size); + if (++trans->curr_rsp_frag < trans->rsp_hdr->num_frags) + goto clear_send; + + complete(&trans->resp_cmpl); + +clear_send: + clear_bit(QLC_BC_VF_SEND, &vf->state); +} + +static int qlcnic_sriov_add_act_list(struct qlcnic_sriov *sriov, + struct qlcnic_vf_info *vf, + struct qlcnic_bc_trans *trans) +{ + struct qlcnic_trans_list *t_list = &vf->rcv_act; + + spin_lock(&t_list->lock); + t_list->count++; + list_add_tail(&trans->list, &t_list->wait_list); + if (t_list->count == 1) + qlcnic_sriov_schedule_bc_cmd(sriov, vf, + qlcnic_sriov_process_bc_cmd); + spin_unlock(&t_list->lock); + return 0; +} + +static void qlcnic_sriov_handle_pending_trans(struct qlcnic_sriov *sriov, + struct qlcnic_vf_info *vf, + struct qlcnic_bc_hdr *hdr) +{ + struct qlcnic_bc_trans *trans = NULL; + struct list_head *node; + u32 pay_size, curr_frag; + u8 found = 0, active = 0; + + spin_lock(&vf->rcv_pend.lock); + if (vf->rcv_pend.count > 0) { + list_for_each(node, &vf->rcv_pend.wait_list) { + trans = list_entry(node, struct qlcnic_bc_trans, list); + if (trans->trans_id == hdr->seq_id) { + found = 1; + break; + } + } + } + + if (found) { + curr_frag = trans->curr_req_frag; + pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size, + curr_frag); + qlcnic_sriov_pull_bc_msg(vf->adapter, + (u32 *)(trans->req_hdr + curr_frag), + (u32 *)(trans->req_pay + curr_frag), + pay_size); + trans->curr_req_frag++; + if (trans->curr_req_frag >= hdr->num_frags) { + vf->rcv_pend.count--; + list_del(&trans->list); + active = 1; + } + } + spin_unlock(&vf->rcv_pend.lock); + + if (active) + if (qlcnic_sriov_add_act_list(sriov, vf, trans)) + qlcnic_sriov_cleanup_transaction(trans); + + return; +} + +static void qlcnic_sriov_handle_bc_cmd(struct qlcnic_sriov *sriov, + struct qlcnic_bc_hdr *hdr, + struct qlcnic_vf_info *vf) +{ + struct qlcnic_bc_trans *trans; + struct qlcnic_adapter *adapter = vf->adapter; + struct qlcnic_cmd_args cmd; + u32 pay_size; + int err; + u8 cmd_op; + + if (!test_bit(QLC_BC_VF_STATE, &vf->state) && + hdr->op_type != QLC_BC_CMD && + hdr->cmd_op != QLCNIC_BC_CMD_CHANNEL_INIT) + return; + + if (hdr->frag_num > 1) { + qlcnic_sriov_handle_pending_trans(sriov, vf, hdr); + return; + } + + cmd_op = hdr->cmd_op; + if (qlcnic_sriov_alloc_bc_trans(&trans)) + return; + + if (hdr->op_type == QLC_BC_CMD) + err = qlcnic_sriov_alloc_bc_mbx_args(&cmd, cmd_op); + else + err = qlcnic_alloc_mbx_args(&cmd, adapter, cmd_op); + + if (err) { + qlcnic_sriov_cleanup_transaction(trans); + return; + } + + cmd.op_type = hdr->op_type; + if (qlcnic_sriov_prepare_bc_hdr(trans, &cmd, hdr->seq_id, + QLC_BC_COMMAND)) { + qlcnic_free_mbx_args(&cmd); + qlcnic_sriov_cleanup_transaction(trans); + return; + } + + pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size, + trans->curr_req_frag); + qlcnic_sriov_pull_bc_msg(vf->adapter, + (u32 *)(trans->req_hdr + trans->curr_req_frag), + (u32 *)(trans->req_pay + trans->curr_req_frag), + pay_size); + trans->func_id = vf->pci_func; + trans->vf = vf; + trans->trans_id = hdr->seq_id; + trans->curr_req_frag++; + if (trans->curr_req_frag == trans->req_hdr->num_frags) { + if (qlcnic_sriov_add_act_list(sriov, vf, trans)) { + qlcnic_free_mbx_args(&cmd); + qlcnic_sriov_cleanup_transaction(trans); + } + } else { + spin_lock(&vf->rcv_pend.lock); + list_add_tail(&trans->list, &vf->rcv_pend.wait_list); + vf->rcv_pend.count++; + spin_unlock(&vf->rcv_pend.lock); + } +} + +static void qlcnic_sriov_handle_msg_event(struct qlcnic_sriov *sriov, + struct qlcnic_vf_info *vf) +{ + struct qlcnic_bc_hdr hdr; + u32 *ptr = (u32 *)&hdr; + u8 msg_type, i; + + for (i = 2; i < 6; i++) + ptr[i - 2] = readl(QLCNIC_MBX_FW(vf->adapter->ahw, i)); + msg_type = hdr.msg_type; + + switch (msg_type) { + case QLC_BC_COMMAND: + qlcnic_sriov_handle_bc_cmd(sriov, &hdr, vf); + break; + case QLC_BC_RESPONSE: + qlcnic_sriov_handle_bc_resp(&hdr, vf); + break; + } +} + +void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *adapter, u32 event) +{ + struct qlcnic_vf_info *vf; + struct qlcnic_sriov *sriov; + int index; + u8 pci_func; + + sriov = adapter->ahw->sriov; + pci_func = qlcnic_sriov_target_func_id(event); + index = qlcnic_sriov_func_to_index(adapter, pci_func); + + if (index < 0) + return; + + vf = &sriov->vf_info[index]; + vf->pci_func = pci_func; + + if (qlcnic_sriov_channel_free_check(event)) + complete(&vf->ch_free_cmpl); + + if (qlcnic_sriov_bc_msg_check(event)) + qlcnic_sriov_handle_msg_event(sriov, vf); +} + +int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *adapter, u8 enable) +{ + struct qlcnic_cmd_args cmd; + int err; + + if (!test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state)) + return 0; + + if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_BC_EVENT_SETUP)) + return -ENOMEM; + + if (enable) + cmd.req.arg[1] = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7); + + err = qlcnic_83xx_mbx_op(adapter, &cmd); + + if (err != QLCNIC_RCODE_SUCCESS) { + dev_err(&adapter->pdev->dev, + "Failed to %s bc events, err=%d\n", + (enable ? "enable" : "disable"), err); + } + + qlcnic_free_mbx_args(&cmd); + return err; +} + +static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *adapter, + struct qlcnic_cmd_args *cmd) +{ + struct qlcnic_bc_trans *trans; + int err; + u32 rsp_data, opcode, mbx_err_code, rsp; + u16 seq = ++adapter->ahw->sriov->bc.trans_counter; + + if (qlcnic_sriov_alloc_bc_trans(&trans)) + return -ENOMEM; + + if (qlcnic_sriov_prepare_bc_hdr(trans, cmd, seq, QLC_BC_COMMAND)) + return -ENOMEM; + + if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) { + rsp = -EIO; + QLCDB(adapter, DRV, "MBX not Ready!(cmd 0x%x) for VF 0x%x\n", + QLCNIC_MBX_RSP(cmd->req.arg[0]), adapter->ahw->pci_func); + goto err_out; + } + + err = qlcnic_sriov_send_bc_cmd(adapter, trans, adapter->ahw->pci_func); + if (err) { + dev_err(&adapter->pdev->dev, + "MBX command 0x%x timed out for VF %d\n", + (cmd->req.arg[0] & 0xffff), adapter->ahw->pci_func); + rsp = QLCNIC_RCODE_TIMEOUT; + goto err_out; + } + + rsp_data = cmd->rsp.arg[0]; + mbx_err_code = QLCNIC_MBX_STATUS(rsp_data); + opcode = QLCNIC_MBX_RSP(cmd->req.arg[0]); + + if ((mbx_err_code == QLCNIC_MBX_RSP_OK) || + (mbx_err_code == QLCNIC_MBX_PORT_RSP_OK)) { + rsp = QLCNIC_RCODE_SUCCESS; + } else { + rsp = mbx_err_code; + if (!rsp) + rsp = 1; + dev_err(&adapter->pdev->dev, + "MBX command 0x%x failed with err:0x%x for VF %d\n", + opcode, mbx_err_code, adapter->ahw->pci_func); + } + +err_out: + qlcnic_sriov_cleanup_transaction(trans); + return rsp; +} + +int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op) +{ + struct qlcnic_cmd_args cmd; + struct qlcnic_vf_info *vf = &adapter->ahw->sriov->vf_info[0]; + int ret; + + if (qlcnic_sriov_alloc_bc_mbx_args(&cmd, cmd_op)) + return -ENOMEM; + + ret = qlcnic_issue_cmd(adapter, &cmd); + if (ret) { + dev_err(&adapter->pdev->dev, + "Failed bc channel %s %d\n", cmd_op ? "term" : "init", + ret); + goto out; + } + + cmd_op = (cmd.rsp.arg[0] & 0xff); + if (cmd.rsp.arg[0] >> 25 == 2) + return 2; + if (cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) + set_bit(QLC_BC_VF_STATE, &vf->state); + else + clear_bit(QLC_BC_VF_STATE, &vf->state); + +out: + qlcnic_free_mbx_args(&cmd); + return ret; +} diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index aa5ba6ec4d87..87ff58d29155 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -13,6 +13,10 @@ 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, struct qlcnic_info *npar_info, u16 vport_id) @@ -174,27 +178,54 @@ static void qlcnic_sriov_pf_reset_vport_handle(struct qlcnic_adapter *adapter, u8 func) { 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; + } 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, u16 vport_handle, u8 func) { 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; + } 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, u8 func) { 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; + } 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; } @@ -273,6 +304,7 @@ void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) if (!qlcnic_sriov_enable_check(adapter)) return; + qlcnic_sriov_cfg_bc_intr(adapter, 0); qlcnic_sriov_pf_config_vport(adapter, 0, func); qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0); __qlcnic_sriov_cleanup(adapter); @@ -349,6 +381,10 @@ static int qlcnic_sriov_pf_init(struct qlcnic_adapter *adapter) if (err) 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->switch_mode = nic_info.switch_mode; ahw->max_mtu = nic_info.max_mtu; @@ -453,3 +489,79 @@ int qlcnic_pci_sriov_configure(struct pci_dev *dev, int num_vfs) clear_bit(__QLCNIC_RESETTING, &adapter->state); 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); +} -- cgit v1.2.3-59-g8ed1b From 7cb03b2347d5edace4fb8e7dd9d6c3889368a179 Mon Sep 17 00:00:00 2001 From: Rajesh Borundia Date: Fri, 29 Mar 2013 05:46:37 +0000 Subject: qlcnic: Support VF-PF communication channel commands. o Add support for commands from VF to PF. o PF validates the commands sent by the VF before sending it to adapter. o vPort is a container of resources. PF creates vPort for VFs and attach resources to it. vPort is transparent to the VF. o Separate 83xx TX and RX hardware resource cleanup from 82xx. Signed-off-by: Manish Chopra Signed-off-by: Sucheta Chakraborty Signed-off-by: Rajesh Borundia Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 14 + .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 288 +++++----- .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 150 +++++ drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c | 20 +- drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | 3 + drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 5 +- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 5 + drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h | 30 + .../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 45 ++ .../net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | 609 +++++++++++++++++++++ 10 files changed, 994 insertions(+), 175 deletions(-) (limited to 'drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 78d1db686bdf..e5f7695e8443 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -1584,6 +1584,9 @@ struct qlcnic_hardware_ops { int (*create_rx_ctx) (struct qlcnic_adapter *); int (*create_tx_ctx) (struct qlcnic_adapter *, struct qlcnic_host_tx_ring *, int); + void (*del_rx_ctx) (struct qlcnic_adapter *); + void (*del_tx_ctx) (struct qlcnic_adapter *, + struct qlcnic_host_tx_ring *); int (*setup_link_event) (struct qlcnic_adapter *, int); int (*get_nic_info) (struct qlcnic_adapter *, struct qlcnic_info *, u8); int (*get_pci_info) (struct qlcnic_adapter *, struct qlcnic_pci_info *); @@ -1703,6 +1706,17 @@ static inline int qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter, return adapter->ahw->hw_ops->create_tx_ctx(adapter, ptr, ring); } +static inline void qlcnic_fw_cmd_del_rx_ctx(struct qlcnic_adapter *adapter) +{ + return adapter->ahw->hw_ops->del_rx_ctx(adapter); +} + +static inline void qlcnic_fw_cmd_del_tx_ctx(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *ptr) +{ + return adapter->ahw->hw_ops->del_tx_ctx(adapter, ptr); +} + static inline int qlcnic_linkevent_request(struct qlcnic_adapter *adapter, int enable) { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 89dcea593646..374fa8a3791b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -16,153 +16,6 @@ #define RSS_HASHTYPE_IP_TCP 0x3 #define QLC_83XX_FW_MBX_CMD 0 -/* status descriptor mailbox data - * @phy_addr_{low|high}: physical address of buffer - * @sds_ring_size: buffer size - * @intrpt_id: interrupt id - * @intrpt_val: source of interrupt - */ -struct qlcnic_sds_mbx { - u32 phy_addr_low; - u32 phy_addr_high; - u32 rsvd1[4]; -#if defined(__LITTLE_ENDIAN) - u16 sds_ring_size; - u16 rsvd2; - u16 rsvd3[2]; - u16 intrpt_id; - u8 intrpt_val; - u8 rsvd4; -#elif defined(__BIG_ENDIAN) - u16 rsvd2; - u16 sds_ring_size; - u16 rsvd3[2]; - u8 rsvd4; - u8 intrpt_val; - u16 intrpt_id; -#endif - u32 rsvd5; -} __packed; - -/* receive descriptor buffer data - * phy_addr_reg_{low|high}: physical address of regular buffer - * phy_addr_jmb_{low|high}: physical address of jumbo buffer - * reg_ring_sz: size of regular buffer - * reg_ring_len: no. of entries in regular buffer - * jmb_ring_len: no. of entries in jumbo buffer - * jmb_ring_sz: size of jumbo buffer - */ -struct qlcnic_rds_mbx { - u32 phy_addr_reg_low; - u32 phy_addr_reg_high; - u32 phy_addr_jmb_low; - u32 phy_addr_jmb_high; -#if defined(__LITTLE_ENDIAN) - u16 reg_ring_sz; - u16 reg_ring_len; - u16 jmb_ring_sz; - u16 jmb_ring_len; -#elif defined(__BIG_ENDIAN) - u16 reg_ring_len; - u16 reg_ring_sz; - u16 jmb_ring_len; - u16 jmb_ring_sz; -#endif -} __packed; - -/* host producers for regular and jumbo rings */ -struct __host_producer_mbx { - u32 reg_buf; - u32 jmb_buf; -} __packed; - -/* Receive context mailbox data outbox registers - * @state: state of the context - * @vport_id: virtual port id - * @context_id: receive context id - * @num_pci_func: number of pci functions of the port - * @phy_port: physical port id - */ -struct qlcnic_rcv_mbx_out { -#if defined(__LITTLE_ENDIAN) - u8 rcv_num; - u8 sts_num; - u16 ctx_id; - u8 state; - u8 num_pci_func; - u8 phy_port; - u8 vport_id; -#elif defined(__BIG_ENDIAN) - u16 ctx_id; - u8 sts_num; - u8 rcv_num; - u8 vport_id; - u8 phy_port; - u8 num_pci_func; - u8 state; -#endif - u32 host_csmr[QLCNIC_MAX_RING_SETS]; - struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS]; -} __packed; - -struct qlcnic_add_rings_mbx_out { -#if defined(__LITTLE_ENDIAN) - u8 rcv_num; - u8 sts_num; - u16 ctx_id; -#elif defined(__BIG_ENDIAN) - u16 ctx_id; - u8 sts_num; - u8 rcv_num; -#endif - u32 host_csmr[QLCNIC_MAX_RING_SETS]; - struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS]; -} __packed; - -/* Transmit context mailbox inbox registers - * @phys_addr_{low|high}: DMA address of the transmit buffer - * @cnsmr_index_{low|high}: host consumer index - * @size: legth of transmit buffer ring - * @intr_id: interrput id - * @src: src of interrupt - */ -struct qlcnic_tx_mbx { - u32 phys_addr_low; - u32 phys_addr_high; - u32 cnsmr_index_low; - u32 cnsmr_index_high; -#if defined(__LITTLE_ENDIAN) - u16 size; - u16 intr_id; - u8 src; - u8 rsvd[3]; -#elif defined(__BIG_ENDIAN) - u16 intr_id; - u16 size; - u8 rsvd[3]; - u8 src; -#endif -} __packed; - -/* Transmit context mailbox outbox registers - * @host_prod: host producer index - * @ctx_id: transmit context id - * @state: state of the transmit context - */ - -struct qlcnic_tx_mbx_out { - u32 host_prod; -#if defined(__LITTLE_ENDIAN) - u16 ctx_id; - u8 state; - u8 rsvd; -#elif defined(__BIG_ENDIAN) - u8 rsvd; - u8 state; - u16 ctx_id; -#endif -} __packed; - static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { {QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1}, {QLCNIC_CMD_CONFIG_INTRPT, 18, 34}, @@ -304,6 +157,8 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = { .process_lb_rcv_ring_diag = qlcnic_83xx_process_rcv_ring_diag, .create_rx_ctx = qlcnic_83xx_create_rx_ctx, .create_tx_ctx = qlcnic_83xx_create_tx_ctx, + .del_rx_ctx = qlcnic_83xx_del_rx_ctx, + .del_tx_ctx = qlcnic_83xx_del_tx_ctx, .setup_link_event = qlcnic_83xx_setup_link_event, .get_nic_info = qlcnic_83xx_get_nic_info, .get_pci_info = qlcnic_83xx_get_pci_info, @@ -1126,6 +981,32 @@ out: return err; } +void qlcnic_83xx_del_rx_ctx(struct qlcnic_adapter *adapter) +{ + int err; + u32 temp = 0; + struct qlcnic_cmd_args cmd; + struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx; + + if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_RX_CTX)) + return; + + if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter)) + cmd.req.arg[0] |= (0x3 << 29); + + if (qlcnic_sriov_pf_check(adapter)) + qlcnic_pf_set_interface_id_del_rx_ctx(adapter, &temp); + + cmd.req.arg[1] = recv_ctx->context_id | temp; + err = qlcnic_issue_cmd(adapter, &cmd); + if (err) + dev_err(&adapter->pdev->dev, + "Failed to destroy rx ctx in firmware\n"); + + recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED; + qlcnic_free_mbx_args(&cmd); +} + int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter) { int i, err, index, sds_mbx_size, rds_mbx_size; @@ -1156,9 +1037,17 @@ int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter) /* set mailbox hdr and capabilities */ qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_RX_CTX); + + if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter)) + cmd.req.arg[0] |= (0x3 << 29); + cmd.req.arg[1] = cap; cmd.req.arg[5] = 1 | (num_rds << 5) | (num_sds << 8) | (QLC_83XX_HOST_RDS_MODE_UNIQUE << 16); + + if (qlcnic_sriov_pf_check(adapter)) + qlcnic_pf_set_interface_id_create_rx_ctx(adapter, + &cmd.req.arg[6]); /* set up status rings, mbx 8-57/87 */ index = QLC_83XX_HOST_SDS_MBX_IDX; for (i = 0; i < num_sds; i++) { @@ -1242,12 +1131,34 @@ out: return err; } +void qlcnic_83xx_del_tx_ctx(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) +{ + struct qlcnic_cmd_args cmd; + u32 temp = 0; + + if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX)) + return; + + if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter)) + cmd.req.arg[0] |= (0x3 << 29); + + if (qlcnic_sriov_pf_check(adapter)) + qlcnic_pf_set_interface_id_del_tx_ctx(adapter, &temp); + + cmd.req.arg[1] = tx_ring->ctx_id | temp; + if (qlcnic_issue_cmd(adapter, &cmd)) + dev_err(&adapter->pdev->dev, + "Failed to destroy tx ctx in firmware\n"); + qlcnic_free_mbx_args(&cmd); +} + int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter, struct qlcnic_host_tx_ring *tx, int ring) { int err; u16 msix_id; - u32 *buf, intr_mask; + u32 *buf, intr_mask, temp = 0; struct qlcnic_cmd_args cmd; struct qlcnic_tx_mbx mbx; struct qlcnic_tx_mbx_out *mbx_out; @@ -1284,8 +1195,15 @@ int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter, mbx.src = 0; qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX); + + if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter)) + cmd.req.arg[0] |= (0x3 << 29); + + if (qlcnic_sriov_pf_check(adapter)) + qlcnic_pf_set_interface_id_create_tx_ctx(adapter, &temp); + cmd.req.arg[1] = QLCNIC_CAP0_LEGACY_CONTEXT; - cmd.req.arg[5] = QLCNIC_MAX_TX_QUEUES; + cmd.req.arg[5] = QLCNIC_MAX_TX_QUEUES | temp; buf = &cmd.req.arg[6]; memcpy(buf, &mbx, sizeof(struct qlcnic_tx_mbx)); /* send the mailbox command*/ @@ -1578,24 +1496,35 @@ int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *adapter, int enable) return err; } +static void qlcnic_83xx_set_interface_id_promisc(struct qlcnic_adapter *adapter, + u32 *interface_id) +{ + if (qlcnic_sriov_pf_check(adapter)) { + qlcnic_pf_set_interface_id_promisc(adapter, interface_id); + } else { + if (!qlcnic_sriov_vf_check(adapter)) + *interface_id = adapter->recv_ctx->context_id << 16; + } +} + int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) { int err; - u32 temp; + u32 temp = 0; struct qlcnic_cmd_args cmd; if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED) return -EIO; qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_MAC_RX_MODE); - temp = adapter->recv_ctx->context_id << 16; + qlcnic_83xx_set_interface_id_promisc(adapter, &temp); cmd.req.arg[1] = (mode ? 1 : 0) | temp; err = qlcnic_issue_cmd(adapter, &cmd); if (err) dev_info(&adapter->pdev->dev, "Promiscous mode config failed\n"); - qlcnic_free_mbx_args(&cmd); + qlcnic_free_mbx_args(&cmd); return err; } @@ -1735,21 +1664,31 @@ int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode) return status; } +static void qlcnic_83xx_set_interface_id_ipaddr(struct qlcnic_adapter *adapter, + u32 *interface_id) +{ + if (qlcnic_sriov_pf_check(adapter)) { + qlcnic_pf_set_interface_id_ipaddr(adapter, interface_id); + } else { + if (!qlcnic_sriov_vf_check(adapter)) + *interface_id = adapter->recv_ctx->context_id << 16; + } +} + void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int mode) { int err; - u32 temp, temp_ip; + u32 temp = 0, temp_ip; struct qlcnic_cmd_args cmd; qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_IP_ADDR); - if (mode == QLCNIC_IP_UP) { - temp = adapter->recv_ctx->context_id << 16; + qlcnic_83xx_set_interface_id_ipaddr(adapter, &temp); + + if (mode == QLCNIC_IP_UP) cmd.req.arg[1] = 1 | temp; - } else { - temp = adapter->recv_ctx->context_id << 16; + else cmd.req.arg[1] = 2 | temp; - } /* * Adapter needs IP address in network byte order. @@ -1766,6 +1705,7 @@ void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, dev_err(&adapter->netdev->dev, "could not notify %s IP 0x%x request\n", (mode == QLCNIC_IP_UP) ? "Add" : "Remove", ip); + qlcnic_free_mbx_args(&cmd); } @@ -1832,11 +1772,22 @@ int qlcnic_83xx_config_rss(struct qlcnic_adapter *adapter, int enable) } +static void qlcnic_83xx_set_interface_id_macaddr(struct qlcnic_adapter *adapter, + u32 *interface_id) +{ + if (qlcnic_sriov_pf_check(adapter)) { + qlcnic_pf_set_interface_id_macaddr(adapter, interface_id); + } else { + if (!qlcnic_sriov_vf_check(adapter)) + *interface_id = adapter->recv_ctx->context_id << 16; + } +} + int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, __le16 vlan_id, u8 op) { int err; - u32 *buf; + u32 *buf, temp = 0; struct qlcnic_cmd_args cmd; struct qlcnic_macvlan_mbx mv; @@ -1846,9 +1797,10 @@ int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN); if (err) return err; - cmd.req.arg[1] = op | (1 << 8) | - (adapter->recv_ctx->context_id << 16); + cmd.req.arg[1] = op | (1 << 8); + qlcnic_83xx_set_interface_id_macaddr(adapter, &temp); + cmd.req.arg[1] |= temp; mv.vlan = le16_to_cpu(vlan_id); mv.mac_addr0 = addr[0]; mv.mac_addr1 = addr[1]; @@ -2151,6 +2103,10 @@ int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *adapter, bool op_type) max_ints = adapter->ahw->num_msix - 1; qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTRPT); cmd.req.arg[1] = max_ints; + + if (qlcnic_sriov_vf_check(adapter)) + cmd.req.arg[1] |= (adapter->ahw->pci_func << 8) | BIT_16; + for (i = 0, index = 2; i < max_ints; i++) { type = op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL; val = type | (adapter->ahw->intr_tbl[i].type << 4); @@ -2757,13 +2713,19 @@ int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr, int qlcnic_83xx_test_link(struct qlcnic_adapter *adapter) { + u8 pci_func; int err; u32 config = 0, state; struct qlcnic_cmd_args cmd; struct qlcnic_hardware_context *ahw = adapter->ahw; - state = readl(ahw->pci_base0 + QLC_83XX_LINK_STATE(ahw->pci_func)); - if (!QLC_83xx_FUNC_VAL(state, ahw->pci_func)) { + if (qlcnic_sriov_vf_check(adapter)) + pci_func = adapter->portnum; + else + pci_func = ahw->pci_func; + + state = readl(ahw->pci_base0 + QLC_83XX_LINK_STATE(pci_func)); + if (!QLC_83xx_FUNC_VAL(state, pci_func)) { dev_info(&adapter->pdev->dev, "link state down\n"); return config; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 3e8dc0b136e6..32ed4b4c4976 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -88,6 +88,153 @@ #define QLC_83XX_MAX_RESET_SEQ_ENTRIES 16 +/* status descriptor mailbox data + * @phy_addr_{low|high}: physical address of buffer + * @sds_ring_size: buffer size + * @intrpt_id: interrupt id + * @intrpt_val: source of interrupt + */ +struct qlcnic_sds_mbx { + u32 phy_addr_low; + u32 phy_addr_high; + u32 rsvd1[4]; +#if defined(__LITTLE_ENDIAN) + u16 sds_ring_size; + u16 rsvd2; + u16 rsvd3[2]; + u16 intrpt_id; + u8 intrpt_val; + u8 rsvd4; +#elif defined(__BIG_ENDIAN) + u16 rsvd2; + u16 sds_ring_size; + u16 rsvd3[2]; + u8 rsvd4; + u8 intrpt_val; + u16 intrpt_id; +#endif + u32 rsvd5; +} __packed; + +/* receive descriptor buffer data + * phy_addr_reg_{low|high}: physical address of regular buffer + * phy_addr_jmb_{low|high}: physical address of jumbo buffer + * reg_ring_sz: size of regular buffer + * reg_ring_len: no. of entries in regular buffer + * jmb_ring_len: no. of entries in jumbo buffer + * jmb_ring_sz: size of jumbo buffer + */ +struct qlcnic_rds_mbx { + u32 phy_addr_reg_low; + u32 phy_addr_reg_high; + u32 phy_addr_jmb_low; + u32 phy_addr_jmb_high; +#if defined(__LITTLE_ENDIAN) + u16 reg_ring_sz; + u16 reg_ring_len; + u16 jmb_ring_sz; + u16 jmb_ring_len; +#elif defined(__BIG_ENDIAN) + u16 reg_ring_len; + u16 reg_ring_sz; + u16 jmb_ring_len; + u16 jmb_ring_sz; +#endif +} __packed; + +/* host producers for regular and jumbo rings */ +struct __host_producer_mbx { + u32 reg_buf; + u32 jmb_buf; +} __packed; + +/* Receive context mailbox data outbox registers + * @state: state of the context + * @vport_id: virtual port id + * @context_id: receive context id + * @num_pci_func: number of pci functions of the port + * @phy_port: physical port id + */ +struct qlcnic_rcv_mbx_out { +#if defined(__LITTLE_ENDIAN) + u8 rcv_num; + u8 sts_num; + u16 ctx_id; + u8 state; + u8 num_pci_func; + u8 phy_port; + u8 vport_id; +#elif defined(__BIG_ENDIAN) + u16 ctx_id; + u8 sts_num; + u8 rcv_num; + u8 vport_id; + u8 phy_port; + u8 num_pci_func; + u8 state; +#endif + u32 host_csmr[QLCNIC_MAX_RING_SETS]; + struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS]; +} __packed; + +struct qlcnic_add_rings_mbx_out { +#if defined(__LITTLE_ENDIAN) + u8 rcv_num; + u8 sts_num; + u16 ctx_id; +#elif defined(__BIG_ENDIAN) + u16 ctx_id; + u8 sts_num; + u8 rcv_num; +#endif + u32 host_csmr[QLCNIC_MAX_RING_SETS]; + struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS]; +} __packed; + +/* Transmit context mailbox inbox registers + * @phys_addr_{low|high}: DMA address of the transmit buffer + * @cnsmr_index_{low|high}: host consumer index + * @size: legth of transmit buffer ring + * @intr_id: interrput id + * @src: src of interrupt + */ +struct qlcnic_tx_mbx { + u32 phys_addr_low; + u32 phys_addr_high; + u32 cnsmr_index_low; + u32 cnsmr_index_high; +#if defined(__LITTLE_ENDIAN) + u16 size; + u16 intr_id; + u8 src; + u8 rsvd[3]; +#elif defined(__BIG_ENDIAN) + u16 intr_id; + u16 size; + u8 rsvd[3]; + u8 src; +#endif +} __packed; + +/* Transmit context mailbox outbox registers + * @host_prod: host producer index + * @ctx_id: transmit context id + * @state: state of the transmit context + */ + +struct qlcnic_tx_mbx_out { + u32 host_prod; +#if defined(__LITTLE_ENDIAN) + u16 ctx_id; + u8 state; + u8 rsvd; +#elif defined(__BIG_ENDIAN) + u8 rsvd; + u8 state; + u16 ctx_id; +#endif +} __packed; + struct qlcnic_intrpt_config { u8 type; u8 enabled; @@ -369,6 +516,9 @@ int qlcnic_ind_rd(struct qlcnic_adapter *, u32); int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *); int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *, struct qlcnic_host_tx_ring *, int); +void qlcnic_83xx_del_rx_ctx(struct qlcnic_adapter *); +void qlcnic_83xx_del_tx_ctx(struct qlcnic_adapter *, + struct qlcnic_host_tx_ring *); int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8); int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *, int); void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index c645c94b072d..43562c256379 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -382,8 +382,7 @@ out_free_rq: return err; } -static void -qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter) +void qlcnic_82xx_fw_cmd_del_rx_ctx(struct qlcnic_adapter *adapter) { int err; struct qlcnic_cmd_args cmd; @@ -484,13 +483,13 @@ out_free_rq: return err; } -static void -qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter, - struct qlcnic_host_tx_ring *tx_ring) +void qlcnic_82xx_fw_cmd_del_tx_ctx(struct qlcnic_adapter *adapter, + struct qlcnic_host_tx_ring *tx_ring) { struct qlcnic_cmd_args cmd; qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX); + cmd.req.arg[1] = tx_ring->ctx_id; if (qlcnic_issue_cmd(adapter, &cmd)) dev_err(&adapter->pdev->dev, @@ -605,13 +604,12 @@ int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev) &dev->tx_ring[ring], ring); if (err) { - qlcnic_fw_cmd_destroy_rx_ctx(dev); + qlcnic_fw_cmd_del_rx_ctx(dev); if (ring == 0) goto err_out; for (i = 0; i < ring; i++) - qlcnic_fw_cmd_destroy_tx_ctx(dev, - &dev->tx_ring[i]); + qlcnic_fw_cmd_del_tx_ctx(dev, &dev->tx_ring[i]); goto err_out; } @@ -633,10 +631,10 @@ void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter) int ring; if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) { - qlcnic_fw_cmd_destroy_rx_ctx(adapter); + qlcnic_fw_cmd_del_rx_ctx(adapter); for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) - qlcnic_fw_cmd_destroy_tx_ctx(adapter, - &adapter->tx_ring[ring]); + qlcnic_fw_cmd_del_tx_ctx(adapter, + &adapter->tx_ring[ring]); if (qlcnic_83xx_check(adapter) && (adapter->flags & QLCNIC_MSIX_ENABLED)) { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index d606e50d8902..e862a77a626b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h @@ -178,6 +178,9 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter, int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *); int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *, struct qlcnic_host_tx_ring *tx_ring, int); +void qlcnic_82xx_fw_cmd_del_rx_ctx(struct qlcnic_adapter *); +void qlcnic_82xx_fw_cmd_del_tx_ctx(struct qlcnic_adapter *, + struct qlcnic_host_tx_ring *); int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, __le16, u8); int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *, u8*); int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 25b61884585a..a85ca63a2c9e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -147,7 +147,10 @@ static inline u8 qlcnic_mac_hash(u64 mac) static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter, u16 handle, u8 ring_id) { - if (adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE834X) + unsigned short device = adapter->pdev->device; + + if ((device == PCI_DEVICE_ID_QLOGIC_QLE834X) || + (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X)) return handle | (ring_id << 15); else return handle; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index f67e8c65350e..7d5727c80b41 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -226,6 +226,9 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p) struct qlcnic_adapter *adapter = netdev_priv(netdev); struct sockaddr *addr = p; + if (qlcnic_sriov_vf_check(adapter)) + return -EINVAL; + if ((adapter->flags & QLCNIC_MAC_OVERRIDE_DISABLED)) return -EOPNOTSUPP; @@ -379,6 +382,8 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = { .process_lb_rcv_ring_diag = qlcnic_82xx_process_rcv_ring_diag, .create_rx_ctx = qlcnic_82xx_fw_cmd_create_rx_ctx, .create_tx_ctx = qlcnic_82xx_fw_cmd_create_tx_ctx, + .del_rx_ctx = qlcnic_82xx_fw_cmd_del_rx_ctx, + .del_tx_ctx = qlcnic_82xx_fw_cmd_del_tx_ctx, .setup_link_event = qlcnic_82xx_linkevent_request, .get_nic_info = qlcnic_82xx_get_nic_info, .get_pci_info = qlcnic_82xx_get_pci_info, diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h index 00053ad8bc3c..3c05f170801d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h @@ -119,6 +119,8 @@ struct qlcnic_vport { struct qlcnic_vf_info { u8 pci_func; + u16 rx_ctx_id; + u16 tx_ctx_id; unsigned long state; struct completion ch_free_cmpl; struct work_struct trans_work; @@ -167,9 +169,37 @@ void qlcnic_sriov_pf_process_bc_cmd(struct qlcnic_adapter *, void qlcnic_sriov_pf_disable(struct qlcnic_adapter *); void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *); int qlcnic_pci_sriov_configure(struct pci_dev *, int); +void qlcnic_pf_set_interface_id_create_rx_ctx(struct qlcnic_adapter *, u32 *); +void qlcnic_pf_set_interface_id_create_tx_ctx(struct qlcnic_adapter *, u32 *); +void qlcnic_pf_set_interface_id_del_rx_ctx(struct qlcnic_adapter *, u32 *); +void qlcnic_pf_set_interface_id_del_tx_ctx(struct qlcnic_adapter *, u32 *); +void qlcnic_pf_set_interface_id_promisc(struct qlcnic_adapter *, u32 *); +void qlcnic_pf_set_interface_id_ipaddr(struct qlcnic_adapter *, u32 *); +void qlcnic_pf_set_interface_id_macaddr(struct qlcnic_adapter *, u32 *); #else static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {} static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {} +static inline void +qlcnic_pf_set_interface_id_create_rx_ctx(struct qlcnic_adapter *adapter, + u32 *int_id) {} +static inline void +qlcnic_pf_set_interface_id_create_tx_ctx(struct qlcnic_adapter *adapter, + u32 *int_id) {} +static inline void +qlcnic_pf_set_interface_id_del_rx_ctx(struct qlcnic_adapter *adapter, + u32 *int_id) {} +static inline void +qlcnic_pf_set_interface_id_del_tx_ctx(struct qlcnic_adapter *adapter, + u32 *int_id) {} +static inline void +qlcnic_pf_set_interface_id_ipaddr(struct qlcnic_adapter *adapter, u32 *int_id) +{} +static inline void +qlcnic_pf_set_interface_id_macaddr(struct qlcnic_adapter *adapter, u32 *int_id) +{} +static inline void +qlcnic_pf_set_interface_id_promisc(struct qlcnic_adapter *adapter, u32 *int_id) +{} #endif #endif diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 0615086f4526..6e927f2eb3c7 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -21,6 +21,9 @@ #define QLC_BC_HDR_SZ 16 #define QLC_BC_PAYLOAD_SZ (1024 - QLC_BC_HDR_SZ) +#define QLC_DEFAULT_RCV_DESCRIPTORS_SRIOV_VF 2048 +#define QLC_DEFAULT_JUMBO_RCV_DESCRIPTORS_SRIOV_VF 512 + static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *, struct qlcnic_cmd_args *); @@ -39,6 +42,8 @@ static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = { .process_lb_rcv_ring_diag = qlcnic_83xx_process_rcv_ring_diag, .create_rx_ctx = qlcnic_83xx_create_rx_ctx, .create_tx_ctx = qlcnic_83xx_create_tx_ctx, + .del_rx_ctx = qlcnic_83xx_del_rx_ctx, + .del_tx_ctx = qlcnic_83xx_del_tx_ctx, .setup_link_event = qlcnic_83xx_setup_link_event, .get_nic_info = qlcnic_83xx_get_nic_info, .get_pci_info = qlcnic_83xx_get_pci_info, @@ -305,6 +310,42 @@ out: return rsp; } +static void qlcnic_sriov_vf_cfg_buff_desc(struct qlcnic_adapter *adapter) +{ + adapter->num_rxd = QLC_DEFAULT_RCV_DESCRIPTORS_SRIOV_VF; + adapter->max_rxd = MAX_RCV_DESCRIPTORS_10G; + adapter->num_jumbo_rxd = QLC_DEFAULT_JUMBO_RCV_DESCRIPTORS_SRIOV_VF; + adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G; + adapter->num_txd = MAX_CMD_DESCRIPTORS; + adapter->max_rds_rings = MAX_RDS_RINGS; +} + +static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter) +{ + struct qlcnic_info nic_info; + struct qlcnic_hardware_context *ahw = adapter->ahw; + int err; + + err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func); + if (err) + return -EIO; + + if (qlcnic_83xx_get_port_info(adapter)) + return -EIO; + + qlcnic_sriov_vf_cfg_buff_desc(adapter); + adapter->flags |= QLCNIC_ADAPTER_INITIALIZED; + dev_info(&adapter->pdev->dev, "HAL Version: %d\n", + adapter->ahw->fw_hal_version); + + ahw->physical_port = (u8) nic_info.phys_port; + ahw->switch_mode = nic_info.switch_mode; + ahw->max_mtu = nic_info.max_mtu; + ahw->op_mode = nic_info.op_mode; + ahw->capabilities = nic_info.capabilities; + return 0; +} + static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, int pci_using_dac) { @@ -336,6 +377,10 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, if (err) goto err_out_disable_bc_intr; + err = qlcnic_sriov_vf_init_driver(adapter); + if (err) + goto err_out_send_channel_term; + err = qlcnic_setup_netdev(adapter, adapter->netdev, pci_using_dac); if (err) goto err_out_send_channel_term; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index 87ff58d29155..d6ac7dcef1e4 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -17,6 +17,11 @@ struct qlcnic_sriov_cmd_handler { int (*fn) (struct qlcnic_bc_trans *, struct qlcnic_cmd_args *); }; +struct qlcnic_sriov_fw_cmd_handler { + u32 cmd; + int (*fn) (struct qlcnic_bc_trans *, struct qlcnic_cmd_args *); +}; + static int qlcnic_sriov_pf_set_vport_info(struct qlcnic_adapter *adapter, struct qlcnic_info *npar_info, u16 vport_id) @@ -542,11 +547,528 @@ err_out: return err; } +static int qlcnic_sriov_cfg_vf_def_mac(struct qlcnic_adapter *adapter, + struct qlcnic_vport *vp, + u16 func, __le16 vlan, u8 op) +{ + struct qlcnic_cmd_args cmd; + struct qlcnic_macvlan_mbx mv; + u8 *addr; + int err; + u32 *buf; + int vpid; + + if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN)) + return -ENOMEM; + + vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func); + if (vpid < 0) { + err = -EINVAL; + goto out; + } + + if (vlan) + op = ((op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ? + QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL); + + cmd.req.arg[1] = op | (1 << 8) | (3 << 6); + cmd.req.arg[1] |= ((vpid & 0xffff) << 16) | BIT_31; + + addr = vp->mac; + mv.vlan = le16_to_cpu(vlan); + mv.mac_addr0 = addr[0]; + mv.mac_addr1 = addr[1]; + mv.mac_addr2 = addr[2]; + mv.mac_addr3 = addr[3]; + mv.mac_addr4 = addr[4]; + mv.mac_addr5 = addr[5]; + buf = &cmd.req.arg[2]; + memcpy(buf, &mv, sizeof(struct qlcnic_macvlan_mbx)); + + err = qlcnic_issue_cmd(adapter, &cmd); + + if (err) + dev_err(&adapter->pdev->dev, + "MAC-VLAN %s to CAM failed, err=%d.\n", + ((op == 1) ? "add " : "delete "), err); + +out: + qlcnic_free_mbx_args(&cmd); + return err; +} + +static int qlcnic_sriov_validate_create_rx_ctx(struct qlcnic_cmd_args *cmd) +{ + if ((cmd->req.arg[0] >> 29) != 0x3) + return -EINVAL; + + return 0; +} + +static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran, + struct qlcnic_cmd_args *cmd) +{ + struct qlcnic_vf_info *vf = tran->vf; + struct qlcnic_adapter *adapter = vf->adapter; + struct qlcnic_rcv_mbx_out *mbx_out; + int err; + + err = qlcnic_sriov_validate_create_rx_ctx(cmd); + if (err) { + cmd->rsp.arg[0] |= (0x6 << 25); + return err; + } + + cmd->req.arg[6] = vf->vp->handle; + err = qlcnic_issue_cmd(adapter, cmd); + + if (!err) { + mbx_out = (struct qlcnic_rcv_mbx_out *)&cmd->rsp.arg[1]; + vf->rx_ctx_id = mbx_out->ctx_id; + qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func, + 0, QLCNIC_MAC_ADD); + } else { + vf->rx_ctx_id = 0; + } + + return err; +} + +static int qlcnic_sriov_pf_mac_address_cmd(struct qlcnic_bc_trans *trans, + struct qlcnic_cmd_args *cmd) +{ + struct qlcnic_vf_info *vf = trans->vf; + u8 type, *mac; + + type = cmd->req.arg[1]; + switch (type) { + case QLCNIC_SET_STATION_MAC: + case QLCNIC_SET_FAC_DEF_MAC: + cmd->rsp.arg[0] = (2 << 25); + break; + case QLCNIC_GET_CURRENT_MAC: + cmd->rsp.arg[0] = (1 << 25); + mac = vf->vp->mac; + cmd->rsp.arg[2] = mac[1] | ((mac[0] << 8) & 0xff00); + cmd->rsp.arg[1] = mac[5] | ((mac[4] << 8) & 0xff00) | + ((mac[3]) << 16 & 0xff0000) | + ((mac[2]) << 24 & 0xff000000); + } + + return 0; +} + +static int qlcnic_sriov_validate_create_tx_ctx(struct qlcnic_cmd_args *cmd) +{ + if ((cmd->req.arg[0] >> 29) != 0x3) + return -EINVAL; + + return 0; +} + +static int qlcnic_sriov_pf_create_tx_ctx_cmd(struct qlcnic_bc_trans *trans, + struct qlcnic_cmd_args *cmd) +{ + struct qlcnic_vf_info *vf = trans->vf; + struct qlcnic_adapter *adapter = vf->adapter; + struct qlcnic_tx_mbx_out *mbx_out; + int err; + + err = qlcnic_sriov_validate_create_tx_ctx(cmd); + if (err) { + cmd->rsp.arg[0] |= (0x6 << 25); + return err; + } + + cmd->req.arg[5] |= vf->vp->handle << 16; + err = qlcnic_issue_cmd(adapter, cmd); + if (!err) { + mbx_out = (struct qlcnic_tx_mbx_out *)&cmd->rsp.arg[2]; + vf->tx_ctx_id = mbx_out->ctx_id; + } else { + vf->tx_ctx_id = 0; + } + + return err; +} + +static int qlcnic_sriov_validate_del_rx_ctx(struct qlcnic_vf_info *vf, + struct qlcnic_cmd_args *cmd) +{ + if ((cmd->req.arg[0] >> 29) != 0x3) + return -EINVAL; + + if ((cmd->req.arg[1] & 0xffff) != vf->rx_ctx_id) + return -EINVAL; + + return 0; +} + +static int qlcnic_sriov_pf_del_rx_ctx_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; + + err = qlcnic_sriov_validate_del_rx_ctx(vf, cmd); + if (err) { + cmd->rsp.arg[0] |= (0x6 << 25); + return err; + } + + qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func, + 0, QLCNIC_MAC_DEL); + cmd->req.arg[1] |= vf->vp->handle << 16; + err = qlcnic_issue_cmd(adapter, cmd); + + if (!err) + vf->rx_ctx_id = 0; + + return err; +} + +static int qlcnic_sriov_validate_del_tx_ctx(struct qlcnic_vf_info *vf, + struct qlcnic_cmd_args *cmd) +{ + if ((cmd->req.arg[0] >> 29) != 0x3) + return -EINVAL; + + if ((cmd->req.arg[1] & 0xffff) != vf->tx_ctx_id) + return -EINVAL; + + return 0; +} + +static int qlcnic_sriov_pf_del_tx_ctx_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; + + err = qlcnic_sriov_validate_del_tx_ctx(vf, cmd); + if (err) { + cmd->rsp.arg[0] |= (0x6 << 25); + return err; + } + + cmd->req.arg[1] |= vf->vp->handle << 16; + err = qlcnic_issue_cmd(adapter, cmd); + + if (!err) + vf->tx_ctx_id = 0; + + return err; +} + +static int qlcnic_sriov_validate_cfg_lro(struct qlcnic_vf_info *vf, + struct qlcnic_cmd_args *cmd) +{ + if ((cmd->req.arg[1] >> 16) != vf->rx_ctx_id) + return -EINVAL; + + return 0; +} + +static int qlcnic_sriov_pf_cfg_lro_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; + + err = qlcnic_sriov_validate_cfg_lro(vf, cmd); + if (err) { + cmd->rsp.arg[0] |= (0x6 << 25); + return err; + } + + err = qlcnic_issue_cmd(adapter, cmd); + return err; +} + +static int qlcnic_sriov_pf_cfg_ip_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 = -EIO; + u8 op; + + op = cmd->req.arg[1] & 0xff; + + cmd->req.arg[1] |= vf->vp->handle << 16; + cmd->req.arg[1] |= BIT_31; + + err = qlcnic_issue_cmd(adapter, cmd); + return err; +} + +static int qlcnic_sriov_validate_cfg_intrpt(struct qlcnic_vf_info *vf, + struct qlcnic_cmd_args *cmd) +{ + if (((cmd->req.arg[1] >> 8) & 0xff) != vf->pci_func) + return -EINVAL; + + if (!(cmd->req.arg[1] & BIT_16)) + return -EINVAL; + + if ((cmd->req.arg[1] & 0xff) != 0x1) + return -EINVAL; + + return 0; +} + +static int qlcnic_sriov_pf_cfg_intrpt_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; + + err = qlcnic_sriov_validate_cfg_intrpt(vf, cmd); + if (err) + cmd->rsp.arg[0] |= (0x6 << 25); + else + err = qlcnic_issue_cmd(adapter, cmd); + + return err; +} + +static int qlcnic_sriov_validate_mtu(struct qlcnic_adapter *adapter, + struct qlcnic_vf_info *vf, + struct qlcnic_cmd_args *cmd) +{ + if (cmd->req.arg[1] != vf->rx_ctx_id) + return -EINVAL; + + if (cmd->req.arg[2] > adapter->ahw->max_mtu) + return -EINVAL; + + return 0; +} + +static int qlcnic_sriov_pf_set_mtu_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; + + err = qlcnic_sriov_validate_mtu(adapter, vf, cmd); + if (err) + cmd->rsp.arg[0] |= (0x6 << 25); + else + err = qlcnic_issue_cmd(adapter, cmd); + + return err; +} + +static int qlcnic_sriov_validate_get_nic_info(struct qlcnic_vf_info *vf, + struct qlcnic_cmd_args *cmd) +{ + if (cmd->req.arg[1] & BIT_31) { + if (((cmd->req.arg[1] >> 16) & 0x7fff) != vf->pci_func) + return -EINVAL; + } else { + cmd->req.arg[1] |= vf->vp->handle << 16; + } + + return 0; +} + +static int qlcnic_sriov_pf_get_nic_info_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; + + err = qlcnic_sriov_validate_get_nic_info(vf, cmd); + if (err) { + cmd->rsp.arg[0] |= (0x6 << 25); + return err; + } + + err = qlcnic_issue_cmd(adapter, cmd); + return err; +} + +static int qlcnic_sriov_validate_cfg_rss(struct qlcnic_vf_info *vf, + struct qlcnic_cmd_args *cmd) +{ + if (cmd->req.arg[1] != vf->rx_ctx_id) + return -EINVAL; + + return 0; +} + +static int qlcnic_sriov_pf_cfg_rss_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; + + err = qlcnic_sriov_validate_cfg_rss(vf, cmd); + if (err) + cmd->rsp.arg[0] |= (0x6 << 25); + else + err = qlcnic_issue_cmd(adapter, cmd); + + return err; +} + +static int qlcnic_sriov_validate_cfg_intrcoal(struct qlcnic_adapter *adapter, + struct qlcnic_vf_info *vf, + struct qlcnic_cmd_args *cmd) +{ + struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal; + u16 ctx_id, pkts, time; + + ctx_id = cmd->req.arg[1] >> 16; + pkts = cmd->req.arg[2] & 0xffff; + time = cmd->req.arg[2] >> 16; + + if (ctx_id != vf->rx_ctx_id) + return -EINVAL; + if (pkts > coal->rx_packets) + return -EINVAL; + if (time < coal->rx_time_us) + return -EINVAL; + + return 0; +} + +static int qlcnic_sriov_pf_cfg_intrcoal_cmd(struct qlcnic_bc_trans *tran, + struct qlcnic_cmd_args *cmd) +{ + struct qlcnic_vf_info *vf = tran->vf; + struct qlcnic_adapter *adapter = vf->adapter; + int err; + + err = qlcnic_sriov_validate_cfg_intrcoal(adapter, vf, cmd); + if (err) { + cmd->rsp.arg[0] |= (0x6 << 25); + return err; + } + + err = qlcnic_issue_cmd(adapter, cmd); + return err; +} + +static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter, + struct qlcnic_vf_info *vf, + struct qlcnic_cmd_args *cmd) +{ + struct qlcnic_macvlan_mbx *macvlan; + + if (!(cmd->req.arg[1] & BIT_8)) + return -EINVAL; + + cmd->req.arg[1] |= (vf->vp->handle << 16); + cmd->req.arg[1] |= BIT_31; + + macvlan = (struct qlcnic_macvlan_mbx *)&cmd->req.arg[2]; + if (!(macvlan->mac_addr0 & BIT_0)) { + dev_err(&adapter->pdev->dev, + "MAC address change is not allowed from VF %d", + vf->pci_func); + return -EINVAL; + } + + return 0; +} + +static int qlcnic_sriov_pf_cfg_macvlan_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; + + err = qlcnic_sriov_validate_cfg_macvlan(adapter, vf, cmd); + if (err) { + cmd->rsp.arg[0] |= (0x6 << 25); + return err; + } + + err = qlcnic_issue_cmd(adapter, cmd); + return err; +} + +static int qlcnic_sriov_validate_linkevent(struct qlcnic_vf_info *vf, + struct qlcnic_cmd_args *cmd) +{ + if ((cmd->req.arg[1] >> 16) != vf->rx_ctx_id) + return -EINVAL; + + if (!(cmd->req.arg[1] & BIT_8)) + return -EINVAL; + + return 0; +} + +static int qlcnic_sriov_pf_linkevent_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; + + err = qlcnic_sriov_validate_linkevent(vf, cmd); + if (err) { + cmd->rsp.arg[0] |= (0x6 << 25); + return err; + } + + err = qlcnic_issue_cmd(adapter, cmd); + return err; +} + +static int qlcnic_sriov_pf_cfg_promisc_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; + + cmd->req.arg[1] |= vf->vp->handle << 16; + cmd->req.arg[1] |= BIT_31; + err = qlcnic_issue_cmd(adapter, cmd); + return err; +} + +static const int qlcnic_pf_passthru_supp_cmds[] = { + QLCNIC_CMD_GET_STATISTICS, + QLCNIC_CMD_GET_PORT_CONFIG, + QLCNIC_CMD_GET_LINK_STATUS, +}; + 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}, }; +static const struct qlcnic_sriov_fw_cmd_handler qlcnic_pf_fw_cmd_hdlr[] = { + {QLCNIC_CMD_CREATE_RX_CTX, qlcnic_sriov_pf_create_rx_ctx_cmd}, + {QLCNIC_CMD_CREATE_TX_CTX, qlcnic_sriov_pf_create_tx_ctx_cmd}, + {QLCNIC_CMD_MAC_ADDRESS, qlcnic_sriov_pf_mac_address_cmd}, + {QLCNIC_CMD_DESTROY_RX_CTX, qlcnic_sriov_pf_del_rx_ctx_cmd}, + {QLCNIC_CMD_DESTROY_TX_CTX, qlcnic_sriov_pf_del_tx_ctx_cmd}, + {QLCNIC_CMD_CONFIGURE_HW_LRO, qlcnic_sriov_pf_cfg_lro_cmd}, + {QLCNIC_CMD_CONFIGURE_IP_ADDR, qlcnic_sriov_pf_cfg_ip_cmd}, + {QLCNIC_CMD_CONFIG_INTRPT, qlcnic_sriov_pf_cfg_intrpt_cmd}, + {QLCNIC_CMD_SET_MTU, qlcnic_sriov_pf_set_mtu_cmd}, + {QLCNIC_CMD_GET_NIC_INFO, qlcnic_sriov_pf_get_nic_info_cmd}, + {QLCNIC_CMD_CONFIGURE_RSS, qlcnic_sriov_pf_cfg_rss_cmd}, + {QLCNIC_CMD_CONFIG_INTR_COAL, qlcnic_sriov_pf_cfg_intrcoal_cmd}, + {QLCNIC_CMD_CONFIG_MAC_VLAN, qlcnic_sriov_pf_cfg_macvlan_cmd}, + {QLCNIC_CMD_GET_LINK_EVENT, qlcnic_sriov_pf_linkevent_cmd}, + {QLCNIC_CMD_CONFIGURE_MAC_RX_MODE, qlcnic_sriov_pf_cfg_promisc_cmd}, +}; + void qlcnic_sriov_pf_process_bc_cmd(struct qlcnic_adapter *adapter, struct qlcnic_bc_trans *trans, struct qlcnic_cmd_args *cmd) @@ -561,7 +1083,94 @@ void qlcnic_sriov_pf_process_bc_cmd(struct qlcnic_adapter *adapter, qlcnic_pf_bc_cmd_hdlr[cmd_op].fn(trans, cmd); return; } + } else { + int i; + size = ARRAY_SIZE(qlcnic_pf_fw_cmd_hdlr); + for (i = 0; i < size; i++) { + if (cmd_op == qlcnic_pf_fw_cmd_hdlr[i].cmd) { + qlcnic_pf_fw_cmd_hdlr[i].fn(trans, cmd); + return; + } + } + + size = ARRAY_SIZE(qlcnic_pf_passthru_supp_cmds); + for (i = 0; i < size; i++) { + if (cmd_op == qlcnic_pf_passthru_supp_cmds[i]) { + qlcnic_issue_cmd(adapter, cmd); + return; + } + } } cmd->rsp.arg[0] |= (0x9 << 25); } + +void qlcnic_pf_set_interface_id_create_rx_ctx(struct qlcnic_adapter *adapter, + u32 *int_id) +{ + u16 vpid; + + vpid = qlcnic_sriov_pf_get_vport_handle(adapter, + adapter->ahw->pci_func); + *int_id |= vpid; +} + +void qlcnic_pf_set_interface_id_del_rx_ctx(struct qlcnic_adapter *adapter, + u32 *int_id) +{ + u16 vpid; + + vpid = qlcnic_sriov_pf_get_vport_handle(adapter, + adapter->ahw->pci_func); + *int_id |= vpid << 16; +} + +void qlcnic_pf_set_interface_id_create_tx_ctx(struct qlcnic_adapter *adapter, + u32 *int_id) +{ + int vpid; + + vpid = qlcnic_sriov_pf_get_vport_handle(adapter, + adapter->ahw->pci_func); + *int_id |= vpid << 16; +} + +void qlcnic_pf_set_interface_id_del_tx_ctx(struct qlcnic_adapter *adapter, + u32 *int_id) +{ + u16 vpid; + + vpid = qlcnic_sriov_pf_get_vport_handle(adapter, + adapter->ahw->pci_func); + *int_id |= vpid << 16; +} + +void qlcnic_pf_set_interface_id_promisc(struct qlcnic_adapter *adapter, + u32 *int_id) +{ + u16 vpid; + + vpid = qlcnic_sriov_pf_get_vport_handle(adapter, + adapter->ahw->pci_func); + *int_id |= (vpid << 16) | BIT_31; +} + +void qlcnic_pf_set_interface_id_ipaddr(struct qlcnic_adapter *adapter, + u32 *int_id) +{ + u16 vpid; + + vpid = qlcnic_sriov_pf_get_vport_handle(adapter, + adapter->ahw->pci_func); + *int_id |= (vpid << 16) | BIT_31; +} + +void qlcnic_pf_set_interface_id_macaddr(struct qlcnic_adapter *adapter, + u32 *int_id) +{ + u16 vpid; + + vpid = qlcnic_sriov_pf_get_vport_handle(adapter, + adapter->ahw->pci_func); + *int_id |= (vpid << 16) | BIT_31; +} -- cgit v1.2.3-59-g8ed1b From f80bc8fe6d44f1f0ebd90d4e698189c5b9ad25e7 Mon Sep 17 00:00:00 2001 From: Rajesh Borundia Date: Fri, 19 Apr 2013 07:01:08 +0000 Subject: qlcnic: Change 82xx adapter VLAN id endian type. o 82xx adapter requires VLAN id in little endian format. Instead of passing vlan id parameter as __le16, pass the parameter as u16 and use cpu_to_le16 at appropriate places. Signed-off-by: Rajesh Borundia Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 13 ++++++------- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 6 +++--- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 4 ++-- drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 4 ++-- drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | 4 ++-- drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 20 ++++++++------------ drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | 4 ++-- 7 files changed, 25 insertions(+), 30 deletions(-) (limited to 'drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index ef55718d06ba..43311ffdf361 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -939,7 +939,7 @@ struct qlcnic_ipaddr { struct qlcnic_filter { struct hlist_node fnode; u8 faddr[ETH_ALEN]; - __le16 vlan_id; + u16 vlan_id; unsigned long ftime; }; @@ -1524,8 +1524,7 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *); int qlcnic_set_default_offload_settings(struct qlcnic_adapter *); int qlcnic_reset_npar_config(struct qlcnic_adapter *); int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *); -void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int, - __le16); +void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int, u16); int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter); int qlcnic_read_mac_addr(struct qlcnic_adapter *); int qlcnic_setup_netdev(struct qlcnic_adapter *, struct net_device *, int); @@ -1595,7 +1594,7 @@ struct qlcnic_hardware_ops { int (*get_nic_info) (struct qlcnic_adapter *, struct qlcnic_info *, u8); int (*get_pci_info) (struct qlcnic_adapter *, struct qlcnic_pci_info *); int (*set_nic_info) (struct qlcnic_adapter *, struct qlcnic_info *); - int (*change_macvlan) (struct qlcnic_adapter *, u8*, __le16, u8); + int (*change_macvlan) (struct qlcnic_adapter *, u8*, u16, u8); void (*napi_enable) (struct qlcnic_adapter *); void (*napi_disable) (struct qlcnic_adapter *); void (*config_intr_coal) (struct qlcnic_adapter *); @@ -1604,7 +1603,7 @@ struct qlcnic_hardware_ops { int (*config_loopback) (struct qlcnic_adapter *, u8); int (*clear_loopback) (struct qlcnic_adapter *, u8); int (*config_promisc_mode) (struct qlcnic_adapter *, u32); - void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, __le16); + void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, u16); int (*get_board_info) (struct qlcnic_adapter *); }; @@ -1746,7 +1745,7 @@ static inline int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, } static inline int qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, - u8 *addr, __le16 id, u8 cmd) + u8 *addr, u16 id, u8 cmd) { return adapter->ahw->hw_ops->change_macvlan(adapter, addr, id, cmd); } @@ -1805,7 +1804,7 @@ static inline int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, } static inline void qlcnic_change_filter(struct qlcnic_adapter *adapter, - u64 *addr, __le16 id) + u64 *addr, u16 id) { adapter->ahw->hw_ops->change_l2_filter(adapter, addr, id); } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 374fa8a3791b..2f4691cbd7d1 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -1784,7 +1784,7 @@ static void qlcnic_83xx_set_interface_id_macaddr(struct qlcnic_adapter *adapter, } int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, - __le16 vlan_id, u8 op) + u16 vlan_id, u8 op) { int err; u32 *buf, temp = 0; @@ -1801,7 +1801,7 @@ int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, cmd.req.arg[1] = op | (1 << 8); qlcnic_83xx_set_interface_id_macaddr(adapter, &temp); cmd.req.arg[1] |= temp; - mv.vlan = le16_to_cpu(vlan_id); + mv.vlan = vlan_id; mv.mac_addr0 = addr[0]; mv.mac_addr1 = addr[1]; mv.mac_addr2 = addr[2]; @@ -1820,7 +1820,7 @@ int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, } void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr, - __le16 vlan_id) + u16 vlan_id) { u8 mac[ETH_ALEN]; memcpy(&mac, addr, ETH_ALEN); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 32ed4b4c4976..7e201cd617ea 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -501,7 +501,7 @@ int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *, u8); int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *, int); int qlcnic_83xx_config_rss(struct qlcnic_adapter *, int); int qlcnic_83xx_config_intr_coalesce(struct qlcnic_adapter *); -void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, __le16); +void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, u16); int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info *); int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *); void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *, int); @@ -523,7 +523,7 @@ int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8); int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *, int); void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *); int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *, bool); -int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, __le16, u8); +int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, u16, u8); int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *, u8 *); void qlcnic_83xx_configure_mac(struct qlcnic_adapter *, u8 *, u8, struct qlcnic_cmd_args *); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index 253b3ac16046..c3cbfaea97c3 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -423,7 +423,7 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter, } int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, - __le16 vlan_id, u8 op) + u16 vlan_id, u8 op) { struct qlcnic_nic_req req; struct qlcnic_mac_req *mac_req; @@ -441,7 +441,7 @@ int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, memcpy(mac_req->mac_addr, addr, 6); vlan_req = (struct qlcnic_vlan_req *)&req.words[1]; - vlan_req->vlan_id = vlan_id; + vlan_req->vlan_id = cpu_to_le16(vlan_id); return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index e862a77a626b..95b1b5732838 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h @@ -159,7 +159,7 @@ int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32); int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev); void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, - u64 *uaddr, __le16 vlan_id); + u64 *uaddr, u16 vlan_id); void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter); int qlcnic_82xx_config_rss(struct qlcnic_adapter *adapter, int); void qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter, @@ -181,7 +181,7 @@ int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *, void qlcnic_82xx_fw_cmd_del_rx_ctx(struct qlcnic_adapter *); void qlcnic_82xx_fw_cmd_del_tx_ctx(struct qlcnic_adapter *, struct qlcnic_host_tx_ring *); -int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, __le16, u8); +int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, u16, u8); int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *, u8*); int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8); int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 56223a6aa408..f3fe31e8f6bd 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -162,7 +162,7 @@ static inline int qlcnic_82xx_is_lb_pkt(u64 sts_data) } void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb, - int loopback_pkt, __le16 vlan_id) + int loopback_pkt, u16 vlan_id) { struct ethhdr *phdr = (struct ethhdr *)(skb->data); struct qlcnic_filter *fil, *tmp_fil; @@ -240,7 +240,7 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb, } void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr, - __le16 vlan_id) + u16 vlan_id) { struct cmd_desc_type0 *hwdesc; struct qlcnic_nic_req *req; @@ -265,7 +265,7 @@ void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr, memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN); vlan_req = (struct qlcnic_vlan_req *)&req->words[1]; - vlan_req->vlan_id = vlan_id; + vlan_req->vlan_id = cpu_to_le16(vlan_id); tx_ring->producer = get_next_index(producer, tx_ring->num_desc); smp_mb(); @@ -281,7 +281,7 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, struct net_device *netdev = adapter->netdev; struct ethhdr *phdr = (struct ethhdr *)(skb->data); u64 src_addr = 0; - __le16 vlan_id = 0; + u16 vlan_id = 0; u8 hindex; if (ether_addr_equal(phdr->h_source, adapter->mac_addr)) @@ -1029,8 +1029,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter, (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { t_vid = 0; is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0); - qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, - cpu_to_le16(t_vid)); + qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); } if (length > rds_ring->skb_size) @@ -1107,8 +1106,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { t_vid = 0; is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0); - qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, - cpu_to_le16(t_vid)); + qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); } if (timestamp) @@ -1500,8 +1498,7 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter, (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { t_vid = 0; is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0); - qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, - cpu_to_le16(t_vid)); + qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); } if (length > rds_ring->skb_size) @@ -1570,8 +1567,7 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter, (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { t_vid = 0; is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1); - qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, - cpu_to_le16(t_vid)); + qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); } if (qlcnic_83xx_is_tstamp(sts_data[1])) data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index bed505606a2d..3a86e1682456 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -548,7 +548,7 @@ err_out: static int qlcnic_sriov_cfg_vf_def_mac(struct qlcnic_adapter *adapter, struct qlcnic_vport *vp, - u16 func, __le16 vlan, u8 op) + u16 func, u16 vlan, u8 op) { struct qlcnic_cmd_args cmd; struct qlcnic_macvlan_mbx mv; @@ -574,7 +574,7 @@ static int qlcnic_sriov_cfg_vf_def_mac(struct qlcnic_adapter *adapter, cmd.req.arg[1] |= ((vpid & 0xffff) << 16) | BIT_31; addr = vp->mac; - mv.vlan = le16_to_cpu(vlan); + mv.vlan = vlan; mv.mac_addr0 = addr[0]; mv.mac_addr1 = addr[1]; mv.mac_addr2 = addr[2]; -- cgit v1.2.3-59-g8ed1b