Skip to content

Commit

Permalink
qlcnic: multi protocol internal loopback support added.
Browse files Browse the repository at this point in the history
Driver will generate loopback traffic pattern and do the test. And
returns result of the test to application.

Updated driver version to 5.0.19.

Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Sucheta Chakraborty authored and David S. Miller committed Jun 24, 2011
1 parent 9d6a644 commit 22c8c93
Show file tree
Hide file tree
Showing 5 changed files with 322 additions and 5 deletions.
22 changes: 20 additions & 2 deletions drivers/net/qlcnic/qlcnic.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@

#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 0
#define _QLCNIC_LINUX_SUBVERSION 18
#define QLCNIC_LINUX_VERSIONID "5.0.18"
#define _QLCNIC_LINUX_SUBVERSION 19
#define QLCNIC_LINUX_VERSIONID "5.0.19"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
Expand Down Expand Up @@ -451,6 +451,7 @@ struct qlcnic_hardware_context {
u8 revision_id;
u8 pci_func;
u8 linkup;
u8 loopback_state;
u16 port_type;
u16 board_type;

Expand Down Expand Up @@ -780,6 +781,13 @@ struct qlcnic_mac_list_s {
#define QLCNIC_IP_UP 2
#define QLCNIC_IP_DOWN 3

#define QLCNIC_ILB_MODE 0x1

#define QLCNIC_LINKEVENT 0x1
#define QLCNIC_LB_RESPONSE 0x2
#define QLCNIC_IS_LB_CONFIGURED(VAL) \
(VAL == (QLCNIC_LINKEVENT | QLCNIC_LB_RESPONSE))

/*
* Driver --> Firmware
*/
Expand All @@ -789,13 +797,17 @@ struct qlcnic_mac_list_s {
#define QLCNIC_H2C_OPCODE_LRO_REQUEST 0x7
#define QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE 0xc
#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR 0x12

#define QLCNIC_H2C_OPCODE_GET_LINKEVENT 0x15
#define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING 0x17
#define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO 0x18
#define QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK 0x13

/*
* Firmware --> Driver
*/

#define QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK 0x8f
#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE 141

#define VPORT_MISS_MODE_DROP 0 /* drop all unmatched */
Expand Down Expand Up @@ -1430,6 +1442,12 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx_ring);
void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *);
void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter);
int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode);

/* Functions from qlcnic_ethtool.c */
int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[]);

/* Functions from qlcnic_main.c */
int qlcnic_reset_context(struct qlcnic_adapter *);
Expand Down
123 changes: 122 additions & 1 deletion drivers/net/qlcnic/qlcnic_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ static const char qlcnic_device_gstrings_stats[][ETH_GSTRING_LEN] = {
static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
"Register_Test_on_offline",
"Link_Test_on_offline",
"Interrupt_Test_offline"
"Interrupt_Test_offline",
"Loopback_Test_offline"
};

#define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test)
Expand Down Expand Up @@ -685,6 +686,123 @@ static int qlcnic_irq_test(struct net_device *netdev)
return ret;
}

#define QLCNIC_ILB_PKT_SIZE 64
#define QLCNIC_NUM_ILB_PKT 16
#define QLCNIC_ILB_MAX_RCV_LOOP 10

static void qlcnic_create_loopback_buff(unsigned char *data, u8 mac[])
{
unsigned char random_data[] = {0xa8, 0x06, 0x45, 0x00};

memset(data, 0x4e, QLCNIC_ILB_PKT_SIZE);

memcpy(data, mac, ETH_ALEN);
memcpy(data + ETH_ALEN, mac, ETH_ALEN);

memcpy(data + 2 * ETH_ALEN, random_data, sizeof(random_data));
}

int qlcnic_check_loopback_buff(unsigned char *data, u8 mac[])
{
unsigned char buff[QLCNIC_ILB_PKT_SIZE];
qlcnic_create_loopback_buff(buff, mac);
return memcmp(data, buff, QLCNIC_ILB_PKT_SIZE);
}

static int qlcnic_do_ilb_test(struct qlcnic_adapter *adapter)
{
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
struct qlcnic_host_sds_ring *sds_ring = &recv_ctx->sds_rings[0];
struct sk_buff *skb;
int i, loop, cnt = 0;

for (i = 0; i < QLCNIC_NUM_ILB_PKT; i++) {
skb = dev_alloc_skb(QLCNIC_ILB_PKT_SIZE);
qlcnic_create_loopback_buff(skb->data, adapter->mac_addr);
skb_put(skb, QLCNIC_ILB_PKT_SIZE);

adapter->diag_cnt = 0;
qlcnic_xmit_frame(skb, adapter->netdev);

loop = 0;
do {
msleep(1);
qlcnic_process_rcv_ring_diag(sds_ring);
if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
break;
} while (!adapter->diag_cnt);

dev_kfree_skb_any(skb);

if (!adapter->diag_cnt)
dev_warn(&adapter->pdev->dev, "ILB Test: %dth packet"
" not recevied\n", i + 1);
else
cnt++;
}
if (cnt != i) {
dev_warn(&adapter->pdev->dev, "ILB Test failed\n");
return -1;
}
return 0;
}

static int qlcnic_iloopback_test(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
int max_sds_rings = adapter->max_sds_rings;
struct qlcnic_host_sds_ring *sds_ring;
int loop = 0;
int ret;

netdev_info(netdev, "%s: in progress\n", __func__);
if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
netdev_warn(netdev, "Loopback test not supported for non "
"privilege function\n");
return 0;
}

if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
return -EIO;


ret = qlcnic_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
if (ret)
goto clear_it;

sds_ring = &adapter->recv_ctx->sds_rings[0];

ret = qlcnic_set_lb_mode(adapter, QLCNIC_ILB_MODE);
if (ret)
goto free_res;

do {
msleep(500);
qlcnic_process_rcv_ring_diag(sds_ring);
if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
break;
} while (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state));

if (!QLCNIC_IS_LB_CONFIGURED(adapter->ahw->loopback_state)) {
netdev_info(netdev, "firmware didnt respond to loopback "
"configure request\n");
ret = adapter->ahw->loopback_state;
goto free_res;
}

ret = qlcnic_do_ilb_test(adapter);

qlcnic_clear_lb_mode(adapter);

free_res:
qlcnic_diag_free_res(netdev, max_sds_rings);

clear_it:
adapter->max_sds_rings = max_sds_rings;
clear_bit(__QLCNIC_RESETTING, &adapter->state);
return ret;
}

static void
qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
u64 *data)
Expand All @@ -704,6 +822,9 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
if (data[2])
eth_test->flags |= ETH_TEST_FL_FAILED;

data[3] = qlcnic_iloopback_test(dev);
if (data[3])
eth_test->flags |= ETH_TEST_FL_FAILED;

}
}
Expand Down
50 changes: 50 additions & 0 deletions drivers/net/qlcnic/qlcnic_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,56 @@ void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
}
}

int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u8 flag)
{
struct qlcnic_nic_req req;
int rv;

memset(&req, 0, sizeof(struct qlcnic_nic_req));

req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
req.req_hdr = cpu_to_le64(QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK |
((u64) adapter->portnum << 16) | ((u64) 0x1 << 32));

req.words[0] = cpu_to_le64(flag);

rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
if (rv != 0)
dev_err(&adapter->pdev->dev, "%sting loopback mode failed\n",
flag ? "Set" : "Reset");
return rv;
}

int qlcnic_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
{
if (qlcnic_set_fw_loopback(adapter, mode))
return -EIO;

if (qlcnic_nic_set_promisc(adapter, VPORT_MISS_MODE_ACCEPT_ALL)) {
qlcnic_set_fw_loopback(adapter, mode);
return -EIO;
}

msleep(1000);
return 0;
}

void qlcnic_clear_lb_mode(struct qlcnic_adapter *adapter)
{
int mode = VPORT_MISS_MODE_DROP;
struct net_device *netdev = adapter->netdev;

qlcnic_set_fw_loopback(adapter, 0);

if (netdev->flags & IFF_PROMISC)
mode = VPORT_MISS_MODE_ACCEPT_ALL;
else if (netdev->flags & IFF_ALLMULTI)
mode = VPORT_MISS_MODE_ACCEPT_MULTI;

qlcnic_nic_set_promisc(adapter, mode);
msleep(1000);
}

/*
* Send the interrupt coalescing parameter set by ethtool to the card.
*/
Expand Down
Loading

0 comments on commit 22c8c93

Please sign in to comment.