static int handle_service()

in lanai.c [1616:1695]


static int handle_service(struct lanai_dev *lanai, u32 s)
{
	vci_t vci = SERVICE_GET_VCI(s);
	struct lanai_vcc *lvcc;
	read_lock(&vcc_sklist_lock);
	lvcc = lanai->vccs[vci];
	if (unlikely(lvcc == NULL)) {
		read_unlock(&vcc_sklist_lock);
		DPRINTK("(itf %d) got service entry 0x%X for nonexistent "
		    "vcc %d\n", lanai->number, (unsigned int) s, vci);
		if (s & SERVICE_TX)
			lanai->stats.service_notx++;
		else
			lanai->stats.service_norx++;
		return 0;
	}
	if (s & SERVICE_TX) {			/* segmentation interrupt */
		if (unlikely(lvcc->tx.atmvcc == NULL)) {
			read_unlock(&vcc_sklist_lock);
			DPRINTK("(itf %d) got service entry 0x%X for non-TX "
			    "vcc %d\n", lanai->number, (unsigned int) s, vci);
			lanai->stats.service_notx++;
			return 0;
		}
		__set_bit(vci, lanai->transmit_ready);
		lvcc->tx.endptr = SERVICE_GET_END(s);
		read_unlock(&vcc_sklist_lock);
		return 1;
	}
	if (unlikely(lvcc->rx.atmvcc == NULL)) {
		read_unlock(&vcc_sklist_lock);
		DPRINTK("(itf %d) got service entry 0x%X for non-RX "
		    "vcc %d\n", lanai->number, (unsigned int) s, vci);
		lanai->stats.service_norx++;
		return 0;
	}
	if (unlikely(lvcc->rx.atmvcc->qos.aal != ATM_AAL5)) {
		read_unlock(&vcc_sklist_lock);
		DPRINTK("(itf %d) got RX service entry 0x%X for non-AAL5 "
		    "vcc %d\n", lanai->number, (unsigned int) s, vci);
		lanai->stats.service_rxnotaal5++;
		atomic_inc(&lvcc->rx.atmvcc->stats->rx_err);
		return 0;
	}
	if (likely(!(s & (SERVICE_TRASH | SERVICE_STREAM | SERVICE_CRCERR)))) {
		vcc_rx_aal5(lvcc, SERVICE_GET_END(s));
		read_unlock(&vcc_sklist_lock);
		return 0;
	}
	if (s & SERVICE_TRASH) {
		int bytes;
		read_unlock(&vcc_sklist_lock);
		DPRINTK("got trashed rx pdu on vci %d\n", vci);
		atomic_inc(&lvcc->rx.atmvcc->stats->rx_err);
		lvcc->stats.x.aal5.service_trash++;
		bytes = (SERVICE_GET_END(s) * 16) -
		    (((unsigned long) lvcc->rx.buf.ptr) -
		    ((unsigned long) lvcc->rx.buf.start)) + 47;
		if (bytes < 0)
			bytes += lanai_buf_size(&lvcc->rx.buf);
		lanai->stats.ovfl_trash += (bytes / 48);
		return 0;
	}
	if (s & SERVICE_STREAM) {
		read_unlock(&vcc_sklist_lock);
		atomic_inc(&lvcc->rx.atmvcc->stats->rx_err);
		lvcc->stats.x.aal5.service_stream++;
		printk(KERN_ERR DEV_LABEL "(itf %d): Got AAL5 stream "
		    "PDU on VCI %d!\n", lanai->number, vci);
		lanai_reset(lanai);
		return 0;
	}
	DPRINTK("got rx crc error on vci %d\n", vci);
	atomic_inc(&lvcc->rx.atmvcc->stats->rx_err);
	lvcc->stats.x.aal5.service_rxcrc++;
	lvcc->rx.buf.ptr = &lvcc->rx.buf.start[SERVICE_GET_END(s) * 4];
	cardvcc_write(lvcc, SERVICE_GET_END(s), vcc_rxreadptr);
	read_unlock(&vcc_sklist_lock);
	return 0;
}