/**
 * Get back the descriptor from DMA after data has been received.
 * When the DMA indicates that the data is received (interrupt is generated), this function should be
 * called to get the descriptor and hence the data buffers received. With successful return from this
 * function caller gets the descriptor fields for processing. check the parameters to understand the
 * fields returned.`
 * @param[in] pointer to synopGMACdevice.
 * @param[out] pointer to hold the status of DMA.
 * @param[out] Dma-able buffer1 pointer.
 * @param[out] pointer to hold length of buffer1 (Max is 2048).
 * @param[out] virtual pointer for buffer1.
 * @param[out] Dma-able buffer2 pointer.
 * @param[out] pointer to hold length of buffer2 (Max is 2048).
 * @param[out] virtual pointer for buffer2.
 * \return returns present rx descriptor index on success. Negative value if error.
 */
s32 synopGMAC_get_rx_qptr(synopGMACdevice *gmacdev, u32 *Status, u32 *Buffer1, u32 *Length1, u32 *Data1, u32 *Buffer2, u32 *Length2, u32 *Data2)
{
	u32 rxnext      = gmacdev->RxBusy;	// index of descriptor the DMA just completed. May be useful when data is spread over multiple buffers/descriptors
	DmaDesc *rxdesc = gmacdev->RxBusyDesc;

	if(synopGMAC_is_desc_owned_by_dma(rxdesc))
		return -1;
	if(synopGMAC_is_desc_empty(rxdesc))
		return -1;

	if(Status != 0)
		*Status = rxdesc->status;// send the status of this descriptor

	if(Length1 != 0)
		*Length1 = (rxdesc->length & DescSize1Mask) >> DescSize1Shift;
	if(Buffer1 != 0)
		*Buffer1 = rxdesc->buffer1;
	if(Data1 != 0)
		*Data1 = rxdesc->data1;

	if(Length2 != 0)
		*Length2 = (rxdesc->length & DescSize2Mask) >> DescSize2Shift;
	if(Buffer2 != 0)
		*Buffer2 = rxdesc->buffer2;
	if(Data1 != 0)
		*Data2 = rxdesc->data2;

	gmacdev->RxBusy = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? 0 : rxnext + 1;

	if(synopGMAC_is_rx_desc_chained(rxdesc)){
	   gmacdev->RxBusyDesc = (DmaDesc *)rxdesc->data2;
		synopGMAC_rx_desc_init_chain(rxdesc);
//		synopGMAC_desc_init_chain(rxdesc, synopGMAC_is_last_rx_desc(gmacdev,rxdesc),0,0);
	}
	else{
		gmacdev->RxBusyDesc = synopGMAC_is_last_rx_desc(gmacdev,rxdesc) ? gmacdev->RxDesc : (rxdesc + 1);
		synopGMAC_rx_desc_init_ring(rxdesc, synopGMAC_is_last_rx_desc(gmacdev,rxdesc));
//		synopGMAC_rx_desc_recycle(rxdesc, synopGMAC_is_last_rx_desc(gmacdev,rxdesc));
	}
	TR("%02d %08x %08x %08x %08x %08x %08x %08x\n",rxnext,(u32)rxdesc,rxdesc->status,rxdesc->length,rxdesc->buffer1,rxdesc->buffer2,rxdesc->data1,rxdesc->data2);
	(gmacdev->BusyRxDesc)--; //This returns one descriptor to processor. So busy count will be decremented by one

	return(rxnext);
}
/**
 * Get the index and address of Tx desc.
 * This api is same for both ring mode and chain mode.
 * This function tracks the tx descriptor the DMA just closed after the transmission of data from this descriptor is
 * over. This returns the descriptor fields to the caller.
 * @param[in] pointer to synopGMACdevice.
 * @param[out] status field of the descriptor.
 * @param[out] Dma-able buffer1 pointer.
 * @param[out] length of buffer1 (Max is 2048).
 * @param[out] virtual pointer for buffer1.
 * @param[out] Dma-able buffer2 pointer.
 * @param[out] length of buffer2 (Max is 2048).
 * @param[out] virtual pointer for buffer2.
 * @param[out] u32 data indicating whether the descriptor is in ring mode or chain mode.
 * \return returns present tx descriptor index on success. Negative value if error.
 */
s32 synopGMAC_get_tx_qptr(synopGMACdevice * gmacdev, u32 * Status, u32 * Buffer1, u32 * Length1, u32 * Data1, u32 * Buffer2, u32 * Length2, u32 * Data2 )
{
	u32 txover      = gmacdev->TxBusy;
	DmaDesc *txdesc = gmacdev->TxBusyDesc;

	if(synopGMAC_is_desc_owned_by_dma(txdesc))
		return -1;
	if(synopGMAC_is_desc_empty(txdesc))
		return -1;

	(gmacdev->BusyTxDesc)--; //busy tx descriptor is reduced by one as it will be handed over to Processor now

	if(Status != 0)
		*Status = txdesc->status;

	if(Buffer1 != 0)
		*Buffer1 = txdesc->buffer1;
	if(Length1 != 0)
		*Length1 = (txdesc->length & DescSize1Mask) >> DescSize1Shift;
	if(Data1 != 0)
		*Data1 = txdesc->data1;

	if(Buffer2 != 0)
		*Buffer2 = txdesc->buffer2;
	if(Length2 != 0)
		*Length2 = (txdesc->length & DescSize2Mask) >> DescSize2Shift;
	if(Data1 != 0)
		*Data2 = txdesc->data2;

	gmacdev->TxBusy = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? 0 : txover + 1;

	if(synopGMAC_is_tx_desc_chained(txdesc)){
	   gmacdev->TxBusyDesc = (DmaDesc *)txdesc->data2;
		synopGMAC_tx_desc_init_chain(txdesc);
	}
	else{
		gmacdev->TxBusyDesc = synopGMAC_is_last_tx_desc(gmacdev,txdesc) ? gmacdev->TxDesc : (txdesc + 1);
		synopGMAC_tx_desc_init_ring(txdesc, synopGMAC_is_last_tx_desc(gmacdev,txdesc));
	}
	TR("(get)%02d %08x %08x %08x %08x %08x %08x %08x\n",txover,(u32)txdesc,txdesc->status,txdesc->length,txdesc->buffer1,txdesc->buffer2,txdesc->data1,txdesc->data2);

	return txover;	
}
Esempio n. 3
0
rt_err_t rt_eth_tx(rt_device_t device, struct pbuf* p)
{
	/* lock eth device */
	rt_sem_take(&sem_lock, RT_WAITING_FOREVER);

	DEBUG_MES("in %s\n", __FUNCTION__);

	s32 status;
	u32 pbuf;
	u64 dma_addr;
	u32 offload_needed = 0;
	u32 index;
	DmaDesc * dpr;
	struct rt_eth_dev *dev = (struct rt_eth_dev *) device;
	struct synopGMACNetworkAdapter *adapter;
	synopGMACdevice * gmacdev;
	adapter = (struct synopGMACNetworkAdapter *) dev->priv;
	if(adapter == NULL)
		return -1;

	gmacdev = (synopGMACdevice *) adapter->synopGMACdev;
	if(gmacdev == NULL)
		return -1;

	if(!synopGMAC_is_desc_owned_by_dma(gmacdev->TxNextDesc))
	{

		pbuf = (u32)plat_alloc_memory(p->len);
		//pbuf = (u32)pbuf_alloc(PBUF_LINK, p->len, PBUF_RAM);
		if(pbuf == 0)
		{
			rt_kprintf("===error in alloc bf1\n");
			return -1;
		}

		DEBUG_MES("p->len = %d\n", p->len);
		memcpy((void *)pbuf, p->payload, p->len);
		dma_addr = plat_dma_map_single(gmacdev,(void*)pbuf,p->len);

		status = synopGMAC_set_tx_qptr(gmacdev,dma_addr,p->len,pbuf,0,0,0,offload_needed,&index,dpr);
		if(status < 0){
			rt_kprintf("%s No More Free Tx Descriptors\n",__FUNCTION__);

			plat_free_memory((void *)pbuf);
			return -16;
		}
	}
	synopGMAC_resume_dma_tx(gmacdev);

	s32 desc_index;
	u32 data1, data2;
	u32 dma_addr1, dma_addr2;
	u32 length1, length2;
#ifdef ENH_DESC_8W
	u32 ext_status;
	u16 time_stamp_higher;
	u32 time_stamp_high;
	u32 time_stamp_low;
#endif
	do {
#ifdef ENH_DESC_8W
		desc_index = synopGMAC_get_tx_qptr(gmacdev, &status, &dma_addr1, &length1, &data1, &dma_addr2, &length2, &data2,&ext_status,&time_stamp_high,&time_stamp_low);
		synopGMAC_TS_read_timestamp_higher_val(gmacdev, &time_stamp_higher);
#else
		desc_index = synopGMAC_get_tx_qptr(gmacdev, &status, &dma_addr1, &length1, &data1, &dma_addr2, &length2, &data2);
#endif
		if(desc_index >= 0 && data1 != 0){
#ifdef  IPC_OFFLOAD
			if(synopGMAC_is_tx_ipv4header_checksum_error(gmacdev, status)){
				rt_kprintf("Harware Failed to Insert IPV4 Header Checksum\n");
			}
			if(synopGMAC_is_tx_payload_checksum_error(gmacdev, status)){
				rt_kprintf("Harware Failed to Insert Payload Checksum\n");
			}
#endif

			plat_free_memory((void *)(data1));  //sw:   data1 = buffer1

			if(synopGMAC_is_desc_valid(status)){
				adapter->synopGMACNetStats.tx_bytes += length1;
				adapter->synopGMACNetStats.tx_packets++;
			}
			else {
				adapter->synopGMACNetStats.tx_errors++;
				adapter->synopGMACNetStats.tx_aborted_errors += synopGMAC_is_tx_aborted(status);
				adapter->synopGMACNetStats.tx_carrier_errors += synopGMAC_is_tx_carrier_error(status);
			}
		}   adapter->synopGMACNetStats.collisions += synopGMAC_get_tx_collision_count(status);
	} while(desc_index >= 0);

	/* unlock eth device */
	rt_sem_release(&sem_lock);
//	rt_kprintf("output %d bytes\n", p->len);
	u32 test_data;
	test_data = synopGMACReadReg(gmacdev->DmaBase, DmaStatus);
	return RT_EOK;
}