Example #1
0
File: eth.c Project: 0xBADCA7/lk
static int eth_rx_worker(void *arg)
{
    for (;;) {
#if 0
        status_t event_err = event_wait_timeout(&eth.rx_event, 1000);
        if (event_err == ERR_TIMED_OUT) {
            /* periodically poll the phys status register */
            /* XXX specific to DP83848 */
            uint32_t val;

            /* Read PHY_MISR */
            /* seems to take about 30 usecs */
            HAL_ETH_ReadPHYRegister(&eth.EthHandle, PHY_MISR, &val);

            /* Check whether the link interrupt has occurred or not */
            if (val & PHY_LINK_INTERRUPT) {
                /* Read PHY_SR*/
                HAL_ETH_ReadPHYRegister(&eth.EthHandle, PHY_SR, &val);

                /* Check whether the link is up or down*/
                if (val & PHY_LINK_STATUS) {
                    printf("eth: link up\n");
                    //netif_set_link_up(link_arg->netif);
                } else {
                    printf("eth: link down\n");
                    //netif_set_link_down(link_arg->netif);
                }
            }
        } else {
#else
        status_t event_err = event_wait(&eth.rx_event);
        if (event_err >= NO_ERROR) {
#endif
            // XXX probably race with the event here
            while (HAL_ETH_GetReceivedFrame_IT(&eth.EthHandle) == HAL_OK) {
                LTRACEF("got packet len %u, buffer %p, seg count %u\n", eth.EthHandle.RxFrameInfos.length,
                        (void *)eth.EthHandle.RxFrameInfos.buffer,
                        eth.EthHandle.RxFrameInfos.SegCount);

#if WITH_LIB_MINIP
                /* allocate a pktbuf header, point it at our rx buffer, and pass up the stack */
                pktbuf_t *p = pktbuf_alloc_empty();
                if (p) {
                    pktbuf_add_buffer(p, (void *)eth.EthHandle.RxFrameInfos.buffer, eth.EthHandle.RxFrameInfos.length,
                                      0, 0, NULL, NULL);
                    p->dlen = eth.EthHandle.RxFrameInfos.length;

                    minip_rx_driver_callback(p);

                    pktbuf_free(p, true);
                }
#endif

                /* Release descriptors to DMA */
                /* Point to first descriptor */
                __IO ETH_DMADescTypeDef *dmarxdesc;

                dmarxdesc = eth.EthHandle.RxFrameInfos.FSRxDesc;
                /* Set Own bit in Rx descriptors: gives the buffers back to DMA */
                for (uint i=0; i< eth.EthHandle.RxFrameInfos.SegCount; i++) {
                    dmarxdesc->Status |= ETH_DMARXDESC_OWN;
                    dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);
                }

                /* Clear Segment_Count */
                eth.EthHandle.RxFrameInfos.SegCount =0;

                /* When Rx Buffer unavailable flag is set: clear it and resume reception */
                if ((eth.EthHandle.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t)RESET) {
                    /* Clear RBUS ETHERNET DMA flag */
                    eth.EthHandle.Instance->DMASR = ETH_DMASR_RBUS;
                    /* Resume DMA reception */
                    eth.EthHandle.Instance->DMARPDR = 0;
                }
            }
        }
    }

    return 0;
}

#if WITH_LIB_MINIP

status_t stm32_eth_send_minip_pkt(pktbuf_t *p)
{
    LTRACEF("p %p, dlen %zu, eof %u\n", p, p->dlen, p->flags & PKTBUF_FLAG_EOF);

    DEBUG_ASSERT(p && p->dlen);

    if (!(p->flags & PKTBUF_FLAG_EOF)) {
        /* can't handle multi part packets yet */
        PANIC_UNIMPLEMENTED;

        return ERR_NOT_IMPLEMENTED;
    }

    status_t err = eth_send(p->data, p->dlen);

    pktbuf_free(p, true);

    return err;
}
Example #2
0
/**
 * @brief Should allocate a pbuf and transfer the bytes of the incoming
 * packet from the interface into the pbuf.
 *
 * @param netif the lwip network interface structure for this ethernetif
 * @return a pbuf filled with the received packet (including MAC header)
 *         NULL on memory error
 */
static struct pbuf *low_level_input( struct netif *netif )
{
  struct pbuf             *p = NULL, *q = NULL;
  uint16_t                 len = 0;
  uint8_t                 *buffer;
  __IO ETH_DMADescTypeDef *dmarxdesc;
  uint32_t                 bufferoffset = 0;
  uint32_t                 payloadoffset = 0;
  uint32_t                 byteslefttocopy = 0;
  uint32_t                 i = 0;

  /* get received frame */
  if ( HAL_ETH_GetReceivedFrame_IT( &EthHandle ) != HAL_OK )
    return NULL;

  /* Obtain the size of the packet and put it into the "len" variable. */
  len = EthHandle.RxFrameInfos.length;
  buffer = (uint8_t *) EthHandle.RxFrameInfos.buffer;

  if ( len > 0 ) {
    /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
    p = pbuf_alloc( PBUF_RAW, len, PBUF_POOL );
  }

  if ( p != NULL ) {
    dmarxdesc = EthHandle.RxFrameInfos.FSRxDesc;
    bufferoffset = 0;

    for ( q = p; q != NULL; q = q->next ) {
      byteslefttocopy = q->len;
      payloadoffset = 0;

      /* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size */
      while ( ( byteslefttocopy + bufferoffset ) > ETH_RX_BUF_SIZE ) {
        /* Copy data to pbuf */
        memcpy( (uint8_t *) ( (uint8_t *) q->payload + payloadoffset ),
          (uint8_t *) ( (uint8_t *) buffer + bufferoffset ),
          ( ETH_RX_BUF_SIZE - bufferoffset ) );

        /* Point to next descriptor */
        dmarxdesc = (ETH_DMADescTypeDef *) ( dmarxdesc->Buffer2NextDescAddr );
        buffer = (uint8_t *) ( dmarxdesc->Buffer1Addr );

        byteslefttocopy = byteslefttocopy - ( ETH_RX_BUF_SIZE - bufferoffset );
        payloadoffset = payloadoffset + ( ETH_RX_BUF_SIZE - bufferoffset );
        bufferoffset = 0;
      }

      /* Copy remaining data in pbuf */
      memcpy( (uint8_t *) ( (uint8_t *) q->payload + payloadoffset ),
        (uint8_t *) ( (uint8_t *) buffer + bufferoffset ), byteslefttocopy );
      bufferoffset = bufferoffset + byteslefttocopy;
    }
  }

  /* Release descriptors to DMA */
  /* Point to first descriptor */
  dmarxdesc = EthHandle.RxFrameInfos.FSRxDesc;

  /* Set Own bit in Rx descriptors: gives the buffers back to DMA */
  for ( i = 0; i < EthHandle.RxFrameInfos.SegCount; i++ ) {
    dmarxdesc->Status |= ETH_DMARXDESC_OWN;
    dmarxdesc = (ETH_DMADescTypeDef *) ( dmarxdesc->Buffer2NextDescAddr );
  }

  /* Clear Segment_Count */
  EthHandle.RxFrameInfos.SegCount = 0;

  /* When Rx Buffer unavailable flag is set: clear it and resume reception */
  if ( ( EthHandle.Instance->DMASR & ETH_DMASR_RBUS ) != (uint32_t) RESET ) {
    /* Clear RBUS ETHERNET DMA flag */
    EthHandle.Instance->DMASR = ETH_DMASR_RBUS;
    /* Resume DMA reception */
    EthHandle.Instance->DMARPDR = 0;
  }

  return p;
}
/* The deferred interrupt handler is a standard RTOS task.  FreeRTOS's centralised
 deferred interrupt handling capabilities can also be used. */
static void prvEMACDeferredInterruptHandlerTask(void *pvParameters) {
	xNetworkBufferDescriptor_t *pxBufferDescriptor;
	size_t xBytesReceived;
	/* Used to indicate that xSendEventStructToIPTask() is being called because
	 of an Ethernet receive event. */
	xIPStackEvent_t xRxEvent;

	uint8_t *buffer;
	__IO ETH_DMADescTypeDef *dmarxdesc;
	uint32_t payloadoffset = 0;
	uint32_t byteslefttocopy = 0;
	uint32_t i = 0;

	xEMACRxEventSemaphore = xSemaphoreCreateCounting(10, 0);

	for (;;) {
		/* Wait for the Ethernet MAC interrupt to indicate that another packet
		 has been received.  It is assumed xEMACRxEventSemaphore is a counting
		 semaphore (to count the Rx events) and that the semaphore has already
		 been created (remember this is an example of a simple rather than
		 optimised port layer). */
		if (xSemaphoreTake( xEMACRxEventSemaphore, portMAX_DELAY ) == pdTRUE) {

			/* get received frame */
			if (HAL_ETH_GetReceivedFrame_IT(&heth_global) != HAL_OK)
				return;

			/* Obtain the size of the packet */
			xBytesReceived = (uint16_t) heth_global.RxFrameInfos.length;
			buffer = (uint8_t *) heth_global.RxFrameInfos.buffer;

			if (xBytesReceived > 0) {
				/* Allocate a network buffer descriptor that points to a buffer
				 large enough to hold the received frame.  As this is the simple
				 rather than efficient example the received data will just be copied
				 into this buffer. */
				pxBufferDescriptor = pxGetNetworkBufferWithDescriptor(xBytesReceived, 0);

				if (pxBufferDescriptor != NULL) {
					/* pxBufferDescriptor->pucEthernetBuffer now points to an Ethernet
					 buffer large enough to hold the received data.  Copy the
					 received data into pcNetworkBuffer->pucEthernetBuffer.  Here it
					 is assumed ReceiveData() is a peripheral driver function that
					 copies the received data into a buffer passed in as the function's
					 parameter.  Remember! While is is a simple robust technique -
					 it is not efficient.  An example that uses a zero copy technique
					 is provided further down this page. */

					dmarxdesc = heth_global.RxFrameInfos.FSRxDesc;

					pxBufferDescriptor->xDataLength = xBytesReceived;

					byteslefttocopy = xBytesReceived;
					payloadoffset = 0;

					/* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/
					while (byteslefttocopy > ETH_RX_BUF_SIZE) {
						/* Copy data to pbuf */
						memcpy(
								(uint8_t*) ((uint8_t*) pxBufferDescriptor->pucEthernetBuffer
										+ payloadoffset), (uint8_t*) ((uint8_t*) buffer),
								ETH_RX_BUF_SIZE);

						/* Point to next descriptor */
						dmarxdesc = (ETH_DMADescTypeDef *) (dmarxdesc->Buffer2NextDescAddr);
						buffer = (uint8_t *) (dmarxdesc->Buffer1Addr);

						byteslefttocopy -= ETH_RX_BUF_SIZE;
						payloadoffset += ETH_RX_BUF_SIZE;
					}
					/* Copy remaining data in pbuf */
					memcpy(
							(uint8_t*) ((uint8_t*) pxBufferDescriptor->pucEthernetBuffer
									+ payloadoffset), (uint8_t*) ((uint8_t*) buffer),
							byteslefttocopy);
				}

				/* See if the data contained in the received Ethernet frame needs
				 to be processed.  NOTE! It is preferable to do this in
				 the interrupt service routine itself, which would remove the need
				 to unblock this task for packets that don't need processing. */
				if (eConsiderFrameForProcessing(pxBufferDescriptor->pucEthernetBuffer)
						== eProcessBuffer) {
					/* The event about to be sent to the TCP/IP is an Rx event. */
					xRxEvent.eEventType = eNetworkRxEvent;

					/* pvData is used to point to the network buffer descriptor that
					 now references the received data. */
					xRxEvent.pvData = (void *) pxBufferDescriptor;

					/* Send the data to the TCP/IP stack. */
					if (xSendEventStructToIPTask(&xRxEvent, 0) == pdFALSE) {
						/* The buffer could not be sent to the IP task so the buffer
						 must be released. */
						vReleaseNetworkBufferAndDescriptor(pxBufferDescriptor);

						/* Make a call to the standard trace macro to log the
						 occurrence. */
						iptraceETHERNET_RX_EVENT_LOST();
					}
					else {
						/* The message was successfully sent to the TCP/IP stack.
						 Call the standard trace macro to log the occurrence. */
						iptraceNETWORK_INTERFACE_RECEIVE();
						gdb.monit.rx_eth_frames++;
					}
				}
				else {
					/* The Ethernet frame can be dropped, but the Ethernet buffer
					 must be released. */
					vReleaseNetworkBufferAndDescriptor(pxBufferDescriptor);
				}

				/* Release descriptors to DMA */
				/* Point to first descriptor */
				dmarxdesc = heth_global.RxFrameInfos.FSRxDesc;
				/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
				for (i = 0; i < heth_global.RxFrameInfos.SegCount; i++) {
					dmarxdesc->Status |= ETH_DMARXDESC_OWN;
					dmarxdesc = (ETH_DMADescTypeDef *) (dmarxdesc->Buffer2NextDescAddr);
				}

				/* Clear Segment_Count */
				heth_global.RxFrameInfos.SegCount = 0;

			}
			else {
				/* The event was lost because a network buffer was not available.
				 Call the standard trace macro to log the occurrence. */
				iptraceETHERNET_RX_EVENT_LOST();
			}
		}

		/* When Rx Buffer unavailable flag is set: clear it and resume reception */
		if ((heth_global.Instance->DMASR & ETH_DMASR_RBUS) != (uint32_t) RESET) {
			/* Clear RBUS ETHERNET DMA flag */
			heth_global.Instance->DMASR = ETH_DMASR_RBUS;
			/* Resume DMA reception */
			heth_global.Instance->DMARPDR = 0;
		}
	}

}