Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c70001a9 authored by Sony Chacko's avatar Sony Chacko Committed by David S. Miller
Browse files

qlcnic: create file qlcnic_io.c for datapath routines



Physical refactoring of 82xx adapter data path routines.

Move data path code to new file qlcnic_io.c
Existing data path code has coding stye issues, the code is
moved to the new file without fixing the style issues.

There is a seperate patch to fix the style issues in qlcnic_io.c

Signed-off-by: default avatarSony Chacko <sony.chacko@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3a858a86
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -5,4 +5,4 @@
obj-$(CONFIG_QLCNIC) := qlcnic.o
obj-$(CONFIG_QLCNIC) := qlcnic.o


qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
	qlcnic_ethtool.o qlcnic_ctx.o
	qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o
+24 −91
Original line number Original line Diff line number Diff line
@@ -89,16 +89,6 @@
#define QLCNIC_CT_DEFAULT_RX_BUF_LEN	2048
#define QLCNIC_CT_DEFAULT_RX_BUF_LEN	2048
#define QLCNIC_LRO_BUFFER_EXTRA		2048
#define QLCNIC_LRO_BUFFER_EXTRA		2048


/* Opcodes to be used with the commands */
#define TX_ETHER_PKT	0x01
#define TX_TCP_PKT	0x02
#define TX_UDP_PKT	0x03
#define TX_IP_PKT	0x04
#define TX_TCP_LSO	0x05
#define TX_TCP_LSO6	0x06
#define TX_TCPV6_PKT	0x0b
#define TX_UDPV6_PKT	0x0c

/* Tx defines */
/* Tx defines */
#define QLCNIC_MAX_FRAGS_PER_TX	14
#define QLCNIC_MAX_FRAGS_PER_TX	14
#define MAX_TSO_HEADER_DESC	2
#define MAX_TSO_HEADER_DESC	2
@@ -147,28 +137,6 @@
 * Added fileds of tcpHdrSize and ipHdrSize, The driver needs to do it only when
 * Added fileds of tcpHdrSize and ipHdrSize, The driver needs to do it only when
 * we are doing LSO (above the 1500 size packet) only.
 * we are doing LSO (above the 1500 size packet) only.
 */
 */

#define FLAGS_VLAN_TAGGED	0x10
#define FLAGS_VLAN_OOB		0x40

#define qlcnic_set_tx_vlan_tci(cmd_desc, v)	\
	(cmd_desc)->vlan_TCI = cpu_to_le16(v);
#define qlcnic_set_cmd_desc_port(cmd_desc, var)	\
	((cmd_desc)->port_ctxid |= ((var) & 0x0F))
#define qlcnic_set_cmd_desc_ctxid(cmd_desc, var)	\
	((cmd_desc)->port_ctxid |= ((var) << 4 & 0xF0))

#define qlcnic_set_tx_port(_desc, _port) \
	((_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0))

#define qlcnic_set_tx_flags_opcode(_desc, _flags, _opcode) \
	((_desc)->flags_opcode |= \
	cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7)))

#define qlcnic_set_tx_frags_len(_desc, _frags, _len) \
	((_desc)->nfrags__length = \
	cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8)))

struct cmd_desc_type0 {
struct cmd_desc_type0 {
	u8 tcp_hdr_offset;	/* For LSO only */
	u8 tcp_hdr_offset;	/* For LSO only */
	u8 ip_hdr_offset;	/* For LSO only */
	u8 ip_hdr_offset;	/* For LSO only */
@@ -203,65 +171,6 @@ struct rcv_desc {
	__le64 addr_buffer;
	__le64 addr_buffer;
} __packed;
} __packed;


/* opcode field in status_desc */
#define QLCNIC_SYN_OFFLOAD	0x03
#define QLCNIC_RXPKT_DESC  	0x04
#define QLCNIC_OLD_RXPKT_DESC	0x3f
#define QLCNIC_RESPONSE_DESC	0x05
#define QLCNIC_LRO_DESC  	0x12

/* for status field in status_desc */
#define STATUS_CKSUM_LOOP	0
#define STATUS_CKSUM_OK		2

/* owner bits of status_desc */
#define STATUS_OWNER_HOST	(0x1ULL << 56)
#define STATUS_OWNER_PHANTOM	(0x2ULL << 56)

/* Status descriptor:
   0-3 port, 4-7 status, 8-11 type, 12-27 total_length
   28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset
   53-55 desc_cnt, 56-57 owner, 58-63 opcode
 */
#define qlcnic_get_sts_port(sts_data)	\
	((sts_data) & 0x0F)
#define qlcnic_get_sts_status(sts_data)	\
	(((sts_data) >> 4) & 0x0F)
#define qlcnic_get_sts_type(sts_data)	\
	(((sts_data) >> 8) & 0x0F)
#define qlcnic_get_sts_totallength(sts_data)	\
	(((sts_data) >> 12) & 0xFFFF)
#define qlcnic_get_sts_refhandle(sts_data)	\
	(((sts_data) >> 28) & 0xFFFF)
#define qlcnic_get_sts_prot(sts_data)	\
	(((sts_data) >> 44) & 0x0F)
#define qlcnic_get_sts_pkt_offset(sts_data)	\
	(((sts_data) >> 48) & 0x1F)
#define qlcnic_get_sts_desc_cnt(sts_data)	\
	(((sts_data) >> 53) & 0x7)
#define qlcnic_get_sts_opcode(sts_data)	\
	(((sts_data) >> 58) & 0x03F)

#define qlcnic_get_lro_sts_refhandle(sts_data) 	\
	((sts_data) & 0x0FFFF)
#define qlcnic_get_lro_sts_length(sts_data)	\
	(((sts_data) >> 16) & 0x0FFFF)
#define qlcnic_get_lro_sts_l2_hdr_offset(sts_data)	\
	(((sts_data) >> 32) & 0x0FF)
#define qlcnic_get_lro_sts_l4_hdr_offset(sts_data)	\
	(((sts_data) >> 40) & 0x0FF)
#define qlcnic_get_lro_sts_timestamp(sts_data)	\
	(((sts_data) >> 48) & 0x1)
#define qlcnic_get_lro_sts_type(sts_data)	\
	(((sts_data) >> 49) & 0x7)
#define qlcnic_get_lro_sts_push_flag(sts_data)		\
	(((sts_data) >> 52) & 0x1)
#define qlcnic_get_lro_sts_seq_number(sts_data)		\
	((sts_data) & 0x0FFFFFFFF)
#define qlcnic_get_lro_sts_mss(sts_data1)		\
	((sts_data1 >> 32) & 0x0FFFF)


struct status_desc {
struct status_desc {
	__le64 status_desc_data[2];
	__le64 status_desc_data[2];
} __attribute__ ((aligned(16)));
} __attribute__ ((aligned(16)));
@@ -1648,6 +1557,15 @@ int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, u8, u8, u8);
int qlcnic_get_mac_stats(struct qlcnic_adapter *, struct qlcnic_mac_statistics *);
int qlcnic_get_mac_stats(struct qlcnic_adapter *, struct qlcnic_mac_statistics *);
extern int qlcnic_config_tso;
extern int qlcnic_config_tso;


int qlcnic_napi_add(struct qlcnic_adapter *, struct net_device *);
void qlcnic_napi_del(struct qlcnic_adapter *adapter);
void qlcnic_napi_enable(struct qlcnic_adapter *adapter);
void qlcnic_napi_disable(struct qlcnic_adapter *adapter);
int qlcnic_alloc_sds_rings(struct qlcnic_recv_context *, int);
void qlcnic_free_sds_rings(struct qlcnic_recv_context *);
void qlcnic_free_tx_rings(struct qlcnic_adapter *);
int qlcnic_alloc_tx_rings(struct qlcnic_adapter *, struct net_device *);

/*
/*
 * QLOGIC Board information
 * QLOGIC Board information
 */
 */
@@ -1694,6 +1612,21 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
				tx_ring->producer;
				tx_ring->producer;
}
}


static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)
{
	writel(0, sds_ring->crb_intr_mask);
}

static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
{
	struct qlcnic_adapter *adapter = sds_ring->adapter;

	writel(0x1, sds_ring->crb_intr_mask);

	if (!QLCNIC_IS_MSI_FAMILY(adapter))
		writel(0xfbff, adapter->tgt_mask_reg);
}

extern const struct ethtool_ops qlcnic_ethtool_ops;
extern const struct ethtool_ops qlcnic_ethtool_ops;
extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
extern const struct ethtool_ops qlcnic_ethtool_failed_ops;


+0 −630
Original line number Original line Diff line number Diff line
@@ -25,10 +25,6 @@ static unsigned int crb_addr_xform[QLCNIC_MAX_CRB_XFORM];


#define QLCNIC_ADDR_ERROR (0xffffffff)
#define QLCNIC_ADDR_ERROR (0xffffffff)


static void
qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
		struct qlcnic_host_rds_ring *rds_ring);

static int
static int
qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter);
qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter);


@@ -1332,629 +1328,3 @@ qlcnic_release_firmware(struct qlcnic_adapter *adapter)
	release_firmware(adapter->fw);
	release_firmware(adapter->fw);
	adapter->fw = NULL;
	adapter->fw = NULL;
}
}

static void
qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
				struct qlcnic_fw_msg *msg)
{
	u32 cable_OUI;
	u16 cable_len;
	u16 link_speed;
	u8  link_status, module, duplex, autoneg;
	u8 lb_status = 0;
	struct net_device *netdev = adapter->netdev;

	adapter->has_link_events = 1;

	cable_OUI = msg->body[1] & 0xffffffff;
	cable_len = (msg->body[1] >> 32) & 0xffff;
	link_speed = (msg->body[1] >> 48) & 0xffff;

	link_status = msg->body[2] & 0xff;
	duplex = (msg->body[2] >> 16) & 0xff;
	autoneg = (msg->body[2] >> 24) & 0xff;
	lb_status = (msg->body[2] >> 32) & 0x3;

	module = (msg->body[2] >> 8) & 0xff;
	if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE)
		dev_info(&netdev->dev, "unsupported cable: OUI 0x%x, "
				"length %d\n", cable_OUI, cable_len);
	else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN)
		dev_info(&netdev->dev, "unsupported cable length %d\n",
				cable_len);

	if (!link_status && (lb_status == QLCNIC_ILB_MODE ||
	    lb_status == QLCNIC_ELB_MODE))
		adapter->ahw->loopback_state |= QLCNIC_LINKEVENT;

	qlcnic_advert_link_change(adapter, link_status);

	if (duplex == LINKEVENT_FULL_DUPLEX)
		adapter->link_duplex = DUPLEX_FULL;
	else
		adapter->link_duplex = DUPLEX_HALF;

	adapter->module_type = module;
	adapter->link_autoneg = autoneg;

	if (link_status) {
		adapter->link_speed = link_speed;
	} else {
		adapter->link_speed = SPEED_UNKNOWN;
		adapter->link_duplex = DUPLEX_UNKNOWN;
	}
}

static void
qlcnic_handle_fw_message(int desc_cnt, int index,
		struct qlcnic_host_sds_ring *sds_ring)
{
	struct qlcnic_fw_msg msg;
	struct status_desc *desc;
	struct qlcnic_adapter *adapter;
	struct device *dev;
	int i = 0, opcode, ret;

	while (desc_cnt > 0 && i < 8) {
		desc = &sds_ring->desc_head[index];
		msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]);
		msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]);

		index = get_next_index(index, sds_ring->num_desc);
		desc_cnt--;
	}

	adapter = sds_ring->adapter;
	dev = &adapter->pdev->dev;
	opcode = qlcnic_get_nic_msg_opcode(msg.body[0]);

	switch (opcode) {
	case QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE:
		qlcnic_handle_linkevent(adapter, &msg);
		break;
	case QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK:
		ret = (u32)(msg.body[1]);
		switch (ret) {
		case 0:
			adapter->ahw->loopback_state |= QLCNIC_LB_RESPONSE;
			break;
		case 1:
			dev_info(dev, "loopback already in progress\n");
			adapter->diag_cnt = -QLCNIC_TEST_IN_PROGRESS;
			break;
		case 2:
			dev_info(dev, "loopback cable is not connected\n");
			adapter->diag_cnt = -QLCNIC_LB_CABLE_NOT_CONN;
			break;
		default:
			dev_info(dev, "loopback configure request failed,"
					" ret %x\n", ret);
			adapter->diag_cnt = -QLCNIC_UNDEFINED_ERROR;
			break;
		}
		break;
	default:
		break;
	}
}

static int
qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
		struct qlcnic_host_rds_ring *rds_ring,
		struct qlcnic_rx_buffer *buffer)
{
	struct sk_buff *skb;
	dma_addr_t dma;
	struct pci_dev *pdev = adapter->pdev;

	skb = netdev_alloc_skb(adapter->netdev, rds_ring->skb_size);
	if (!skb) {
		adapter->stats.skb_alloc_failure++;
		return -ENOMEM;
	}

	skb_reserve(skb, NET_IP_ALIGN);

	dma = pci_map_single(pdev, skb->data,
			rds_ring->dma_size, PCI_DMA_FROMDEVICE);

	if (pci_dma_mapping_error(pdev, dma)) {
		adapter->stats.rx_dma_map_error++;
		dev_kfree_skb_any(skb);
		return -ENOMEM;
	}

	buffer->skb = skb;
	buffer->dma = dma;

	return 0;
}

static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
		struct qlcnic_host_rds_ring *rds_ring, u16 index, u16 cksum)
{
	struct qlcnic_rx_buffer *buffer;
	struct sk_buff *skb;

	buffer = &rds_ring->rx_buf_arr[index];

	if (unlikely(buffer->skb == NULL)) {
		WARN_ON(1);
		return NULL;
	}

	pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
			PCI_DMA_FROMDEVICE);

	skb = buffer->skb;

	if (likely((adapter->netdev->features & NETIF_F_RXCSUM) &&
	    (cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) {
		adapter->stats.csummed++;
		skb->ip_summed = CHECKSUM_UNNECESSARY;
	} else {
		skb_checksum_none_assert(skb);
	}

	buffer->skb = NULL;

	return skb;
}

static inline int
qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb,
			u16 *vlan_tag)
{
	struct ethhdr *eth_hdr;

	if (!__vlan_get_tag(skb, vlan_tag)) {
		eth_hdr = (struct ethhdr *) skb->data;
		memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
		skb_pull(skb, VLAN_HLEN);
	}
	if (!adapter->pvid)
		return 0;

	if (*vlan_tag == adapter->pvid) {
		/* Outer vlan tag. Packet should follow non-vlan path */
		*vlan_tag = 0xffff;
		return 0;
	}
	if (adapter->flags & QLCNIC_TAGGING_ENABLED)
		return 0;

	return -EINVAL;
}

static struct qlcnic_rx_buffer *
qlcnic_process_rcv(struct qlcnic_adapter *adapter,
		struct qlcnic_host_sds_ring *sds_ring,
		int ring, u64 sts_data0)
{
	struct net_device *netdev = adapter->netdev;
	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
	struct qlcnic_rx_buffer *buffer;
	struct sk_buff *skb;
	struct qlcnic_host_rds_ring *rds_ring;
	int index, length, cksum, pkt_offset;
	u16 vid = 0xffff;

	if (unlikely(ring >= adapter->max_rds_rings))
		return NULL;

	rds_ring = &recv_ctx->rds_rings[ring];

	index = qlcnic_get_sts_refhandle(sts_data0);
	if (unlikely(index >= rds_ring->num_desc))
		return NULL;

	buffer = &rds_ring->rx_buf_arr[index];

	length = qlcnic_get_sts_totallength(sts_data0);
	cksum  = qlcnic_get_sts_status(sts_data0);
	pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);

	skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
	if (!skb)
		return buffer;

	if (length > rds_ring->skb_size)
		skb_put(skb, rds_ring->skb_size);
	else
		skb_put(skb, length);

	if (pkt_offset)
		skb_pull(skb, pkt_offset);

	if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
		adapter->stats.rxdropped++;
		dev_kfree_skb(skb);
		return buffer;
	}

	skb->protocol = eth_type_trans(skb, netdev);

	if (vid != 0xffff)
		__vlan_hwaccel_put_tag(skb, vid);

	napi_gro_receive(&sds_ring->napi, skb);

	adapter->stats.rx_pkts++;
	adapter->stats.rxbytes += length;

	return buffer;
}

#define QLC_TCP_HDR_SIZE            20
#define QLC_TCP_TS_OPTION_SIZE      12
#define QLC_TCP_TS_HDR_SIZE         (QLC_TCP_HDR_SIZE + QLC_TCP_TS_OPTION_SIZE)

static struct qlcnic_rx_buffer *
qlcnic_process_lro(struct qlcnic_adapter *adapter,
		int ring, u64 sts_data0, u64 sts_data1)
{
	struct net_device *netdev = adapter->netdev;
	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
	struct qlcnic_rx_buffer *buffer;
	struct sk_buff *skb;
	struct qlcnic_host_rds_ring *rds_ring;
	struct iphdr *iph;
	struct tcphdr *th;
	bool push, timestamp;
	int l2_hdr_offset, l4_hdr_offset;
	int index;
	u16 lro_length, length, data_offset;
	u32 seq_number;
	u16 vid = 0xffff;

	if (unlikely(ring > adapter->max_rds_rings))
		return NULL;

	rds_ring = &recv_ctx->rds_rings[ring];

	index = qlcnic_get_lro_sts_refhandle(sts_data0);
	if (unlikely(index > rds_ring->num_desc))
		return NULL;

	buffer = &rds_ring->rx_buf_arr[index];

	timestamp = qlcnic_get_lro_sts_timestamp(sts_data0);
	lro_length = qlcnic_get_lro_sts_length(sts_data0);
	l2_hdr_offset = qlcnic_get_lro_sts_l2_hdr_offset(sts_data0);
	l4_hdr_offset = qlcnic_get_lro_sts_l4_hdr_offset(sts_data0);
	push = qlcnic_get_lro_sts_push_flag(sts_data0);
	seq_number = qlcnic_get_lro_sts_seq_number(sts_data1);

	skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
	if (!skb)
		return buffer;

	if (timestamp)
		data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE;
	else
		data_offset = l4_hdr_offset + QLC_TCP_HDR_SIZE;

	skb_put(skb, lro_length + data_offset);

	skb_pull(skb, l2_hdr_offset);

	if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
		adapter->stats.rxdropped++;
		dev_kfree_skb(skb);
		return buffer;
	}

	skb->protocol = eth_type_trans(skb, netdev);

	iph = (struct iphdr *)skb->data;
	th = (struct tcphdr *)(skb->data + (iph->ihl << 2));

	length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
	iph->tot_len = htons(length);
	iph->check = 0;
	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
	th->psh = push;
	th->seq = htonl(seq_number);

	length = skb->len;

	if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
		skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1);

	if (vid != 0xffff)
		__vlan_hwaccel_put_tag(skb, vid);
	netif_receive_skb(skb);

	adapter->stats.lro_pkts++;
	adapter->stats.lrobytes += length;

	return buffer;
}

int
qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
{
	struct qlcnic_adapter *adapter = sds_ring->adapter;
	struct list_head *cur;
	struct status_desc *desc;
	struct qlcnic_rx_buffer *rxbuf;
	u64 sts_data0, sts_data1;

	int count = 0;
	int opcode, ring, desc_cnt;
	u32 consumer = sds_ring->consumer;

	while (count < max) {
		desc = &sds_ring->desc_head[consumer];
		sts_data0 = le64_to_cpu(desc->status_desc_data[0]);

		if (!(sts_data0 & STATUS_OWNER_HOST))
			break;

		desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
		opcode = qlcnic_get_sts_opcode(sts_data0);

		switch (opcode) {
		case QLCNIC_RXPKT_DESC:
		case QLCNIC_OLD_RXPKT_DESC:
		case QLCNIC_SYN_OFFLOAD:
			ring = qlcnic_get_sts_type(sts_data0);
			rxbuf = qlcnic_process_rcv(adapter, sds_ring,
					ring, sts_data0);
			break;
		case QLCNIC_LRO_DESC:
			ring = qlcnic_get_lro_sts_type(sts_data0);
			sts_data1 = le64_to_cpu(desc->status_desc_data[1]);
			rxbuf = qlcnic_process_lro(adapter, ring, sts_data0,
						   sts_data1);
			break;
		case QLCNIC_RESPONSE_DESC:
			qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
		default:
			goto skip;
		}

		WARN_ON(desc_cnt > 1);

		if (likely(rxbuf))
			list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
		else
			adapter->stats.null_rxbuf++;

skip:
		for (; desc_cnt > 0; desc_cnt--) {
			desc = &sds_ring->desc_head[consumer];
			desc->status_desc_data[0] =
				cpu_to_le64(STATUS_OWNER_PHANTOM);
			consumer = get_next_index(consumer, sds_ring->num_desc);
		}
		count++;
	}

	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
		struct qlcnic_host_rds_ring *rds_ring =
			&adapter->recv_ctx->rds_rings[ring];

		if (!list_empty(&sds_ring->free_list[ring])) {
			list_for_each(cur, &sds_ring->free_list[ring]) {
				rxbuf = list_entry(cur,
						struct qlcnic_rx_buffer, list);
				qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf);
			}
			spin_lock(&rds_ring->lock);
			list_splice_tail_init(&sds_ring->free_list[ring],
						&rds_ring->free_list);
			spin_unlock(&rds_ring->lock);
		}

		qlcnic_post_rx_buffers_nodb(adapter, rds_ring);
	}

	if (count) {
		sds_ring->consumer = consumer;
		writel(consumer, sds_ring->crb_sts_consumer);
	}

	return count;
}

void
qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
	struct qlcnic_host_rds_ring *rds_ring)
{
	struct rcv_desc *pdesc;
	struct qlcnic_rx_buffer *buffer;
	int count = 0;
	u32 producer;
	struct list_head *head;

	producer = rds_ring->producer;

	head = &rds_ring->free_list;
	while (!list_empty(head)) {

		buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);

		if (!buffer->skb) {
			if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
				break;
		}

		count++;
		list_del(&buffer->list);

		/* make a rcv descriptor  */
		pdesc = &rds_ring->desc_head[producer];
		pdesc->addr_buffer = cpu_to_le64(buffer->dma);
		pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
		pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);

		producer = get_next_index(producer, rds_ring->num_desc);
	}

	if (count) {
		rds_ring->producer = producer;
		writel((producer-1) & (rds_ring->num_desc-1),
				rds_ring->crb_rcv_producer);
	}
}

static void
qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
		struct qlcnic_host_rds_ring *rds_ring)
{
	struct rcv_desc *pdesc;
	struct qlcnic_rx_buffer *buffer;
	int  count = 0;
	uint32_t producer;
	struct list_head *head;

	if (!spin_trylock(&rds_ring->lock))
		return;

	producer = rds_ring->producer;

	head = &rds_ring->free_list;
	while (!list_empty(head)) {

		buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);

		if (!buffer->skb) {
			if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
				break;
		}

		count++;
		list_del(&buffer->list);

		/* make a rcv descriptor  */
		pdesc = &rds_ring->desc_head[producer];
		pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
		pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
		pdesc->addr_buffer = cpu_to_le64(buffer->dma);

		producer = get_next_index(producer, rds_ring->num_desc);
	}

	if (count) {
		rds_ring->producer = producer;
		writel((producer - 1) & (rds_ring->num_desc - 1),
				rds_ring->crb_rcv_producer);
	}
	spin_unlock(&rds_ring->lock);
}

static void dump_skb(struct sk_buff *skb, struct qlcnic_adapter *adapter)
{
	int i;
	unsigned char *data = skb->data;

	printk(KERN_INFO "\n");
	for (i = 0; i < skb->len; i++) {
		QLCDB(adapter, DRV, "%02x ", data[i]);
		if ((i & 0x0f) == 8)
			printk(KERN_INFO "\n");
	}
}

static void qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter, int ring,
				    u64 sts_data0)
{
	struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
	struct sk_buff *skb;
	struct qlcnic_host_rds_ring *rds_ring;
	int index, length, cksum, pkt_offset;

	if (unlikely(ring >= adapter->max_rds_rings))
		return;

	rds_ring = &recv_ctx->rds_rings[ring];

	index = qlcnic_get_sts_refhandle(sts_data0);
	length = qlcnic_get_sts_totallength(sts_data0);
	if (unlikely(index >= rds_ring->num_desc))
		return;

	cksum  = qlcnic_get_sts_status(sts_data0);
	pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);

	skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
	if (!skb)
		return;

	if (length > rds_ring->skb_size)
		skb_put(skb, rds_ring->skb_size);
	else
		skb_put(skb, length);

	if (pkt_offset)
		skb_pull(skb, pkt_offset);

	if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr))
		adapter->diag_cnt++;
	else
		dump_skb(skb, adapter);

	dev_kfree_skb_any(skb);
	adapter->stats.rx_pkts++;
	adapter->stats.rxbytes += length;

	return;
}

void
qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
{
	struct qlcnic_adapter *adapter = sds_ring->adapter;
	struct status_desc *desc;
	u64 sts_data0;
	int ring, opcode, desc_cnt;

	u32 consumer = sds_ring->consumer;

	desc = &sds_ring->desc_head[consumer];
	sts_data0 = le64_to_cpu(desc->status_desc_data[0]);

	if (!(sts_data0 & STATUS_OWNER_HOST))
		return;

	desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
	opcode = qlcnic_get_sts_opcode(sts_data0);
	switch (opcode) {
	case QLCNIC_RESPONSE_DESC:
		qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
		break;
	default:
		ring = qlcnic_get_sts_type(sts_data0);
		qlcnic_process_rcv_diag(adapter, ring, sts_data0);
		break;
	}

	for (; desc_cnt > 0; desc_cnt--) {
		desc = &sds_ring->desc_head[consumer];
		desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
		consumer = get_next_index(consumer, sds_ring->num_desc);
	}

	sds_ring->consumer = consumer;
	writel(consumer, sds_ring->crb_sts_consumer);
}

void qlcnic_fetch_mac(u32 off1, u32 off2, u8 alt_mac, u8 *mac)
{
	u32 mac_low, mac_high;
	int i;

	mac_low = off1;
	mac_high = off2;

	if (alt_mac) {
		mac_low |= (mac_low >> 16) | (mac_high << 16);
		mac_high >>= 16;
	}

	for (i = 0; i < 2; i++)
		mac[i] = (u8)(mac_high >> ((1 - i) * 8));
	for (i = 2; i < 6; i++)
		mac[i] = (u8)(mac_low >> ((5 - i) * 8));
}
+1346 −0

File added.

Preview size limit exceeded, changes collapsed.

+2 −654

File changed.

Preview size limit exceeded, changes collapsed.