static int ia_pkt_tx()

in iphase.c [2886:3064]


static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
        IADEV *iadev;
        struct dle *wr_ptr;
        struct tx_buf_desc __iomem *buf_desc_ptr;
        int desc;
        int comp_code;
        int total_len;
        struct cpcs_trailer *trailer;
        struct ia_vcc *iavcc;

        iadev = INPH_IA_DEV(vcc->dev);  
        iavcc = INPH_IA_VCC(vcc);
        if (!iavcc->txing) {
           printk("discard packet on closed VC\n");
           if (vcc->pop)
		vcc->pop(vcc, skb);
           else
		dev_kfree_skb_any(skb);
	   return 0;
        }

        if (skb->len > iadev->tx_buf_sz - 8) {
           printk("Transmit size over tx buffer size\n");
           if (vcc->pop)
                 vcc->pop(vcc, skb);
           else
                 dev_kfree_skb_any(skb);
          return 0;
        }
        if ((unsigned long)skb->data & 3) {
           printk("Misaligned SKB\n");
           if (vcc->pop)
                 vcc->pop(vcc, skb);
           else
                 dev_kfree_skb_any(skb);
           return 0;
        }       
	/* Get a descriptor number from our free descriptor queue  
	   We get the descr number from the TCQ now, since I am using  
	   the TCQ as a free buffer queue. Initially TCQ will be   
	   initialized with all the descriptors and is hence, full.  
	*/
	desc = get_desc (iadev, iavcc);
	if (desc == 0xffff) 
	    return 1;
	comp_code = desc >> 13;  
	desc &= 0x1fff;  
  
	if ((desc == 0) || (desc > iadev->num_tx_desc))  
	{  
		IF_ERR(printk(DEV_LABEL "invalid desc for send: %d\n", desc);) 
                atomic_inc(&vcc->stats->tx);
		if (vcc->pop)   
		    vcc->pop(vcc, skb);   
		else  
		    dev_kfree_skb_any(skb);
		return 0;   /* return SUCCESS */
	}  
  
	if (comp_code)  
	{  
	    IF_ERR(printk(DEV_LABEL "send desc:%d completion code %d error\n", 
                                                            desc, comp_code);)  
	}  
       
        /* remember the desc and vcc mapping */
        iavcc->vc_desc_cnt++;
        iadev->desc_tbl[desc-1].iavcc = iavcc;
        iadev->desc_tbl[desc-1].txskb = skb;
        IA_SKB_STATE(skb) = 0;

        iadev->ffL.tcq_rd += 2;
        if (iadev->ffL.tcq_rd > iadev->ffL.tcq_ed)
	  	iadev->ffL.tcq_rd  = iadev->ffL.tcq_st;
	writew(iadev->ffL.tcq_rd, iadev->seg_reg+TCQ_RD_PTR);
  
	/* Put the descriptor number in the packet ready queue  
		and put the updated write pointer in the DLE field   
	*/   
	*(u16*)(iadev->seg_ram+iadev->ffL.prq_wr) = desc; 

 	iadev->ffL.prq_wr += 2;
        if (iadev->ffL.prq_wr > iadev->ffL.prq_ed)
                iadev->ffL.prq_wr = iadev->ffL.prq_st;
	  
	/* Figure out the exact length of the packet and padding required to 
           make it  aligned on a 48 byte boundary.  */
	total_len = skb->len + sizeof(struct cpcs_trailer);  
	total_len = ((total_len + 47) / 48) * 48;
	IF_TX(printk("ia packet len:%d padding:%d\n", total_len, total_len - skb->len);)  
 
	/* Put the packet in a tx buffer */   
	trailer = iadev->tx_buf[desc-1].cpcs;
        IF_TX(printk("Sent: skb = 0x%p skb->data: 0x%p len: %d, desc: %d\n",
                  skb, skb->data, skb->len, desc);)
	trailer->control = 0; 
        /*big endian*/ 
	trailer->length = ((skb->len & 0xff) << 8) | ((skb->len & 0xff00) >> 8);
	trailer->crc32 = 0;	/* not needed - dummy bytes */  

	/* Display the packet */  
	IF_TXPKT(printk("Sent data: len = %d MsgNum = %d\n", 
                                                        skb->len, tcnter++);  
        xdump(skb->data, skb->len, "TX: ");
        printk("\n");)

	/* Build the buffer descriptor */  
	buf_desc_ptr = iadev->seg_ram+TX_DESC_BASE;
	buf_desc_ptr += desc;	/* points to the corresponding entry */  
	buf_desc_ptr->desc_mode = AAL5 | EOM_EN | APP_CRC32 | CMPL_INT;   
	/* Huh ? p.115 of users guide describes this as a read-only register */
        writew(TRANSMIT_DONE, iadev->seg_reg+SEG_INTR_STATUS_REG);
	buf_desc_ptr->vc_index = vcc->vci;
	buf_desc_ptr->bytes = total_len;  

        if (vcc->qos.txtp.traffic_class == ATM_ABR)  
	   clear_lockup (vcc, iadev);

	/* Build the DLE structure */  
	wr_ptr = iadev->tx_dle_q.write;  
	memset((caddr_t)wr_ptr, 0, sizeof(*wr_ptr));  
	wr_ptr->sys_pkt_addr = dma_map_single(&iadev->pci->dev, skb->data,
					      skb->len, DMA_TO_DEVICE);
	wr_ptr->local_pkt_addr = (buf_desc_ptr->buf_start_hi << 16) | 
                                                  buf_desc_ptr->buf_start_lo;  
	/* wr_ptr->bytes = swap_byte_order(total_len); didn't seem to affect?? */
	wr_ptr->bytes = skb->len;  

        /* hw bug - DLEs of 0x2d, 0x2e, 0x2f cause DMA lockup */
        if ((wr_ptr->bytes >> 2) == 0xb)
           wr_ptr->bytes = 0x30;

	wr_ptr->mode = TX_DLE_PSI; 
	wr_ptr->prq_wr_ptr_data = 0;
  
	/* end is not to be used for the DLE q */  
	if (++wr_ptr == iadev->tx_dle_q.end)  
		wr_ptr = iadev->tx_dle_q.start;  
        
        /* Build trailer dle */
        wr_ptr->sys_pkt_addr = iadev->tx_buf[desc-1].dma_addr;
        wr_ptr->local_pkt_addr = ((buf_desc_ptr->buf_start_hi << 16) | 
          buf_desc_ptr->buf_start_lo) + total_len - sizeof(struct cpcs_trailer);

        wr_ptr->bytes = sizeof(struct cpcs_trailer);
        wr_ptr->mode = DMA_INT_ENABLE; 
        wr_ptr->prq_wr_ptr_data = iadev->ffL.prq_wr;
        
        /* end is not to be used for the DLE q */
        if (++wr_ptr == iadev->tx_dle_q.end)  
                wr_ptr = iadev->tx_dle_q.start;

	iadev->tx_dle_q.write = wr_ptr;  
        ATM_DESC(skb) = vcc->vci;
        skb_queue_tail(&iadev->tx_dma_q, skb);

        atomic_inc(&vcc->stats->tx);
        iadev->tx_pkt_cnt++;
	/* Increment transaction counter */  
	writel(2, iadev->dma+IPHASE5575_TX_COUNTER);  
        
#if 0        
        /* add flow control logic */ 
        if (atomic_read(&vcc->stats->tx) % 20 == 0) {
          if (iavcc->vc_desc_cnt > 10) {
             vcc->tx_quota =  vcc->tx_quota * 3 / 4;
            printk("Tx1:  vcc->tx_quota = %d \n", (u32)vcc->tx_quota );
              iavcc->flow_inc = -1;
              iavcc->saved_tx_quota = vcc->tx_quota;
           } else if ((iavcc->flow_inc < 0) && (iavcc->vc_desc_cnt < 3)) {
             // vcc->tx_quota = 3 * iavcc->saved_tx_quota / 4;
             printk("Tx2:  vcc->tx_quota = %d \n", (u32)vcc->tx_quota ); 
              iavcc->flow_inc = 0;
           }
        }
#endif
	IF_TX(printk("ia send done\n");)  
	return 0;  
}