示例#1
0
文件: ql_isr.c 项目: mulichao/freebsd
/*
 * Name: ql_rcv_isr
 * Function: Main Interrupt Service Routine
 */
uint32_t
ql_rcv_isr(qla_host_t *ha, uint32_t sds_idx, uint32_t count)
{
	device_t dev;
	qla_hw_t *hw;
	uint32_t comp_idx, c_idx = 0, desc_count = 0, opcode;
	volatile q80_stat_desc_t *sdesc, *sdesc0 = NULL;
	uint32_t ret = 0;
	qla_sgl_comp_t sgc;
	uint16_t nhandles;
	uint32_t sds_replenish_threshold = 0;
	uint32_t r_idx = 0;
	qla_sds_t *sdsp;

	dev = ha->pci_dev;
	hw = &ha->hw;

	hw->sds[sds_idx].rcv_active = 1;
	if (ha->flags.stop_rcv) {
		hw->sds[sds_idx].rcv_active = 0;
		return 0;
	}

	QL_DPRINT2(ha, (dev, "%s: [%d]enter\n", __func__, sds_idx));

	/*
	 * receive interrupts
	 */
	comp_idx = hw->sds[sds_idx].sdsr_next;

	while (count-- && !ha->flags.stop_rcv) {

		sdesc = (q80_stat_desc_t *)
				&hw->sds[sds_idx].sds_ring_base[comp_idx];

		opcode = Q8_STAT_DESC_OPCODE((sdesc->data[1]));

		if (!opcode)
			break;

		hw->sds[sds_idx].intr_count++;
		switch (opcode) {

		case Q8_STAT_DESC_OPCODE_RCV_PKT:

			desc_count = 1;

			bzero(&sgc, sizeof(qla_sgl_comp_t));

			sgc.rcv.pkt_length =
				Q8_STAT_DESC_TOTAL_LENGTH((sdesc->data[0]));
			sgc.rcv.num_handles = 1;
			sgc.rcv.handle[0] =
				Q8_STAT_DESC_HANDLE((sdesc->data[0]));
			sgc.rcv.chksum_status =
				Q8_STAT_DESC_STATUS((sdesc->data[1]));

			sgc.rcv.rss_hash =
				Q8_STAT_DESC_RSS_HASH((sdesc->data[0]));

			if (Q8_STAT_DESC_VLAN((sdesc->data[1]))) {
				sgc.rcv.vlan_tag =
					Q8_STAT_DESC_VLAN_ID((sdesc->data[1]));
			}
			qla_rx_intr(ha, &sgc.rcv, sds_idx);
			break;

		case Q8_STAT_DESC_OPCODE_SGL_RCV:

			desc_count =
				Q8_STAT_DESC_COUNT_SGL_RCV((sdesc->data[1]));

			if (desc_count > 1) {
				c_idx = (comp_idx + desc_count -1) &
						(NUM_STATUS_DESCRIPTORS-1);
				sdesc0 = (q80_stat_desc_t *)
					&hw->sds[sds_idx].sds_ring_base[c_idx];

				if (Q8_STAT_DESC_OPCODE((sdesc0->data[1])) !=
						Q8_STAT_DESC_OPCODE_CONT) {
					desc_count = 0;
					break;
				}
			}

			bzero(&sgc, sizeof(qla_sgl_comp_t));

			sgc.rcv.pkt_length =
				Q8_STAT_DESC_TOTAL_LENGTH_SGL_RCV(\
					(sdesc->data[0]));
			sgc.rcv.chksum_status =
				Q8_STAT_DESC_STATUS((sdesc->data[1]));

			sgc.rcv.rss_hash =
				Q8_STAT_DESC_RSS_HASH((sdesc->data[0]));

			if (Q8_STAT_DESC_VLAN((sdesc->data[1]))) {
				sgc.rcv.vlan_tag =
					Q8_STAT_DESC_VLAN_ID((sdesc->data[1]));
			}

			QL_ASSERT(ha, (desc_count <= 2) ,\
				("%s: [sds_idx, data0, data1]="\
				"%d, %p, %p]\n", __func__, sds_idx,\
				(void *)sdesc->data[0],\
				(void *)sdesc->data[1]));

			sgc.rcv.num_handles = 1;
			sgc.rcv.handle[0] = 
				Q8_STAT_DESC_HANDLE((sdesc->data[0]));
			
			if (qla_rcv_cont_sds(ha, sds_idx, comp_idx, desc_count,
				&sgc.rcv.handle[1], &nhandles)) {
				device_printf(dev,
					"%s: [sds_idx, dcount, data0, data1]="
					 "[%d, %d, 0x%llx, 0x%llx]\n",
					__func__, sds_idx, desc_count,
					(long long unsigned int)sdesc->data[0],
					(long long unsigned int)sdesc->data[1]);
				desc_count = 0;
				break;	
			}

			sgc.rcv.num_handles += nhandles;

			qla_rx_intr(ha, &sgc.rcv, sds_idx);
			
			break;

		case Q8_STAT_DESC_OPCODE_SGL_LRO:

			desc_count =
				Q8_STAT_DESC_COUNT_SGL_LRO((sdesc->data[1]));

			if (desc_count > 1) {
				c_idx = (comp_idx + desc_count -1) &
						(NUM_STATUS_DESCRIPTORS-1);
				sdesc0 = (q80_stat_desc_t *)
					&hw->sds[sds_idx].sds_ring_base[c_idx];

				if (Q8_STAT_DESC_OPCODE((sdesc0->data[1])) !=
						Q8_STAT_DESC_OPCODE_CONT) {
					desc_count = 0;
					break;
				}
			}
			bzero(&sgc, sizeof(qla_sgl_comp_t));

			sgc.lro.payload_length =
			Q8_STAT_DESC_TOTAL_LENGTH_SGL_RCV((sdesc->data[0]));
				
			sgc.lro.rss_hash =
				Q8_STAT_DESC_RSS_HASH((sdesc->data[0]));
			
			sgc.lro.num_handles = 1;
			sgc.lro.handle[0] =
				Q8_STAT_DESC_HANDLE((sdesc->data[0]));

			if (Q8_SGL_LRO_STAT_TS((sdesc->data[1])))
				sgc.lro.flags |= Q8_LRO_COMP_TS;

			if (Q8_SGL_LRO_STAT_PUSH_BIT((sdesc->data[1])))
				sgc.lro.flags |= Q8_LRO_COMP_PUSH_BIT;

			sgc.lro.l2_offset =
				Q8_SGL_LRO_STAT_L2_OFFSET((sdesc->data[1]));
			sgc.lro.l4_offset =
				Q8_SGL_LRO_STAT_L4_OFFSET((sdesc->data[1]));

			if (Q8_STAT_DESC_VLAN((sdesc->data[1]))) {
				sgc.lro.vlan_tag =
					Q8_STAT_DESC_VLAN_ID((sdesc->data[1]));
			}

			QL_ASSERT(ha, (desc_count <= 7) ,\
				("%s: [sds_idx, data0, data1]="\
				 "[%d, 0x%llx, 0x%llx]\n",\
				__func__, sds_idx,\
				(long long unsigned int)sdesc->data[0],\
				(long long unsigned int)sdesc->data[1]));
				
			if (qla_rcv_cont_sds(ha, sds_idx, comp_idx, 
				desc_count, &sgc.lro.handle[1], &nhandles)) {
				device_printf(dev,
				"%s: [sds_idx, data0, data1]="\
				 "[%d, 0x%llx, 0x%llx]\n",\
				__func__, sds_idx,\
				(long long unsigned int)sdesc->data[0],\
				(long long unsigned int)sdesc->data[1]);

				desc_count = 0;
				break;	
			}

			sgc.lro.num_handles += nhandles;

			if (qla_lro_intr(ha, &sgc.lro, sds_idx)) {
				device_printf(dev,
				"%s: [sds_idx, data0, data1]="\
				 "[%d, 0x%llx, 0x%llx]\n",\
				__func__, sds_idx,\
				(long long unsigned int)sdesc->data[0],\
				(long long unsigned int)sdesc->data[1]);
				device_printf(dev,
				"%s: [comp_idx, c_idx, dcount, nhndls]="\
				 "[%d, %d, %d, %d]\n",\
				__func__, comp_idx, c_idx, desc_count,
				sgc.lro.num_handles);
				if (desc_count > 1) {
				device_printf(dev,
				"%s: [sds_idx, data0, data1]="\
				 "[%d, 0x%llx, 0x%llx]\n",\
				__func__, sds_idx,\
				(long long unsigned int)sdesc0->data[0],\
				(long long unsigned int)sdesc0->data[1]);
				}
			}
			
			break;

		default:
			device_printf(dev, "%s: default 0x%llx!\n", __func__,
					(long long unsigned int)sdesc->data[0]);
			break;
		}

		if (desc_count == 0)
			break;

		sds_replenish_threshold += desc_count;


		while (desc_count--) {
			sdesc->data[0] = 0ULL;
			sdesc->data[1] = 0ULL;
			comp_idx = (comp_idx + 1) & (NUM_STATUS_DESCRIPTORS-1);
			sdesc = (q80_stat_desc_t *)
				&hw->sds[sds_idx].sds_ring_base[comp_idx];
		}

		if (sds_replenish_threshold > ha->hw.sds_cidx_thres) {
			sds_replenish_threshold = 0;
			if (hw->sds[sds_idx].sdsr_next != comp_idx) {
				QL_UPDATE_SDS_CONSUMER_INDEX(ha, sds_idx,\
					comp_idx);
			}
			hw->sds[sds_idx].sdsr_next = comp_idx;
		}
	}

	if (ha->hw.enable_soft_lro) {
		struct lro_ctrl		*lro;

		lro = &ha->hw.sds[sds_idx].lro;

#if (__FreeBSD_version >= 1100101)

		tcp_lro_flush_all(lro);

#else
		struct lro_entry *queued;

		while ((!SLIST_EMPTY(&lro->lro_active))) {
			queued = SLIST_FIRST(&lro->lro_active);
			SLIST_REMOVE_HEAD(&lro->lro_active, next);
			tcp_lro_flush(lro, queued);
		}

#endif /* #if (__FreeBSD_version >= 1100101) */

	}

	if (ha->flags.stop_rcv)
		goto ql_rcv_isr_exit;

	if (hw->sds[sds_idx].sdsr_next != comp_idx) {
		QL_UPDATE_SDS_CONSUMER_INDEX(ha, sds_idx, comp_idx);
		hw->sds[sds_idx].sdsr_next = comp_idx;
	} else {
		hw->sds[sds_idx].spurious_intr_count++;

		if (ha->hw.num_rds_rings > 1)
			r_idx = sds_idx;

		sdsp = &ha->hw.sds[sds_idx];

		if (sdsp->rx_free > ha->std_replenish)
			qla_replenish_normal_rx(ha, sdsp, r_idx);
	}

	sdesc = (q80_stat_desc_t *)&hw->sds[sds_idx].sds_ring_base[comp_idx];
	opcode = Q8_STAT_DESC_OPCODE((sdesc->data[1]));

	if (opcode)
		ret = -1;

ql_rcv_isr_exit:
	hw->sds[sds_idx].rcv_active = 0;

	return (ret);
}
示例#2
0
/*
 * Name: qla_isr
 * Function: Main Interrupt Service Routine
 */
static uint32_t
qla_rcv_isr(qla_host_t *ha, uint32_t sds_idx, uint32_t count)
{
	device_t dev;
	qla_hw_t *hw;
	uint32_t comp_idx, desc_count;
	q80_stat_desc_t *sdesc;
	struct lro_ctrl *lro;
	uint32_t ret = 0;

	dev = ha->pci_dev;
	hw = &ha->hw;

	hw->sds[sds_idx].rcv_active = 1;
	if (ha->flags.stop_rcv) {
		hw->sds[sds_idx].rcv_active = 0;
		return 0;
	}

	QL_DPRINT2((dev, "%s: [%d]enter\n", __func__, sds_idx));

	/*
	 * receive interrupts
	 */
	comp_idx = hw->sds[sds_idx].sdsr_next;
	lro = &hw->sds[sds_idx].lro;

	while (count--) {

		sdesc = (q80_stat_desc_t *)
				&hw->sds[sds_idx].sds_ring_base[comp_idx];

		if (Q8_STAT_DESC_OWNER((sdesc->data[0])) !=
			Q8_STAT_DESC_OWNER_HOST) {
			QL_DPRINT2((dev, "%s:  data %p sdsr_next 0x%08x\n",
				__func__, (void *)sdesc->data[0], comp_idx));
			break;
		}

		desc_count = Q8_STAT_DESC_COUNT((sdesc->data[0]));

		switch (Q8_STAT_DESC_OPCODE((sdesc->data[0]))) {

		case Q8_STAT_DESC_OPCODE_RCV_PKT:
		case Q8_STAT_DESC_OPCODE_SYN_OFFLOAD:
			qla_rx_intr(ha, (sdesc->data[0]), sds_idx, lro);
			
			break;

		default:
			device_printf(dev, "%s: default 0x%llx!\n", __func__,
					(long long unsigned int)sdesc->data[0]);
			break;
		}

		while (desc_count--) {
			sdesc->data[0] =
				Q8_STAT_DESC_SET_OWNER(Q8_STAT_DESC_OWNER_FW);
			comp_idx = (comp_idx + 1) & (NUM_STATUS_DESCRIPTORS-1);
			sdesc = (q80_stat_desc_t *)
				&hw->sds[sds_idx].sds_ring_base[comp_idx];
		}
	}

	tcp_lro_flush_all(lro);

	if (hw->sds[sds_idx].sdsr_next != comp_idx) {
		QL_UPDATE_SDS_CONSUMER_INDEX(ha, sds_idx, comp_idx);
	}
	hw->sds[sds_idx].sdsr_next = comp_idx;

	sdesc = (q80_stat_desc_t *)&hw->sds[sds_idx].sds_ring_base[comp_idx];
	if ((sds_idx == 0) && (Q8_STAT_DESC_OWNER((sdesc->data[0])) ==
					Q8_STAT_DESC_OWNER_HOST)) {
		ret = -1;
	}

	hw->sds[sds_idx].rcv_active = 0;
	return (ret);
}