static void * 
thread_func(void *param)
{
	thread_t *t = (thread_t *)param;
	while (1)
	{
		if (t->state == DONE)
			return NULL;

		task_t *task = NULL;
		pthread_mutex_lock(&t->task_list_lock);
		while (RING_EMPTY(&t->tasks, task, link))
		{
			if (t->state == DONE)
				return NULL;
			pthread_cond_wait(&t->task_list_aval_cond, &t->task_list_lock);
		}

		task = RING_FIRST(&t->tasks);
		RING_REMOVE(task, link);
		pthread_mutex_unlock(&t->task_list_lock);
		if (task)
		{
			(*task->func)(&(task->param));
			mem_pool_free(t->mem_pool, (void *)task);
		}
	}

	return NULL;

}
/**
 *  \brief Process successfully sent packets
 *  \param gmacd Pointer to GMAC Driver instance.
 */
static void _gmacd_tx_complete_handler(struct _gmacd* gmacd, uint8_t queue)
{
	Gmac* gmac = gmacd->gmac;
	struct _gmacd_queue* q = &gmacd->queues[queue];
	struct _gmac_desc *desc;
	gmacd_callback_t callback;
	uint32_t tsr;

	//printf("<TX>\r\n");

	/* Clear status */
	tsr = gmac_get_tx_status(gmac);
	gmac_clear_tx_status(gmac, tsr);

	while (!RING_EMPTY(q->tx_head, q->tx_tail)) {
		desc = &q->tx_desc[q->tx_tail];

		/* Exit if frame has not been sent yet:
		 * On TX completion, the GMAC set the USED bit only into the
		 * very first buffer descriptor of the sent frame.
		 * Otherwise it updates this descriptor with status error bits.
		 * This is the descriptor writeback.
		 */
		if ((desc->status & GMAC_TX_STATUS_USED) == 0)
			break;

		/* Process all buffers of the current transmitted frame */
		while ((desc->status & GMAC_TX_STATUS_LASTBUF) == 0) {
			RING_INC(q->tx_tail, q->tx_size);
			desc = &q->tx_desc[q->tx_tail];
		}

		/* Notify upper layer that a frame has been sent */
		if (q->tx_callbacks) {
			callback = q->tx_callbacks[q->tx_tail];
			if (callback)
				callback(queue, tsr);
		}

		/* Go to next frame */
		RING_INC(q->tx_tail, q->tx_size);
	}

	/* If a wakeup callback has been set, notify upper layer that it can
	   send more packets now */
	if (q->tx_wakeup_callback) {
		if (RING_SPACE(q->tx_head, q->tx_tail, q->tx_size) >=
				q->tx_wakeup_threshold) {
			q->tx_wakeup_callback(queue);
		}
	}
}
Exemple #3
0
void
serial_out()
{
    uint8_t *buf;
    int32_t len;
    uint32_t now = usb_now();

    if (timer_out == now)
        return;

    if (RING_EMPTY(&output_ring))
        return;

    len = ring_read_contineous(&output_ring, &buf);
    cdcacm_data_wx(buf, len);
    timer_out = now;
}
bool
thread_pool_is_idle(thread_pool_t *tp)
{
    int i = 0;
    for (; i < tp->thread_count; i++)
    {
        thread_t *t = tp->threads + i;
        ASSERT(t, "a thread in thread pool is null\n");
        pthread_mutex_lock(&(t->task_list_lock));
        if (!RING_EMPTY(&(t->tasks), task, link))
        {
            pthread_mutex_unlock(&(t->task_list_lock));
            return false;
        }
        pthread_mutex_unlock(&(t->task_list_lock));
    }
    return true;
}
static int
add_task_to_thread(thread_t *t, task_func_t func, void *task_param)
{
	task_t *task = (task_t *)mem_pool_alloc(t->mem_pool);
    if (!task)
        return 1;
	task->func = func;
	task->param.real_time_param = task_param;
	task->param.thread_local_data = t->thread_local_data;
	RING_ELEM_INIT(task, link);

	pthread_mutex_lock(&t->task_list_lock);
    if (RING_EMPTY(&t->tasks, task, link))
        pthread_cond_signal(&t->task_list_aval_cond);
	RING_INSERT_TAIL(&t->tasks, task, task, link);
	pthread_mutex_unlock(&t->task_list_lock);
    return 0;
}
/**
 *  \brief Reset TX queue when errors are detected
 *  \param gmacd Pointer to GMAC Driver instance.
 */
static void _gmacd_tx_error_handler(struct _gmacd* gmacd, uint8_t queue)
{
	Gmac *gmac = gmacd->gmac;
	struct _gmacd_queue* q = &gmacd->queues[queue];
	struct _gmac_desc* desc;
	gmacd_callback_t callback;
	uint32_t tsr;

	printf("<TXERR>\r\n");

	/* Clear TXEN bit into the Network Configuration Register:
	 * this is a workaround to recover from TX lockups that
	 * occur on sama5d4 gmac (r1p24f2) when using  scatter-gather.
	 * This issue has never been seen on sama5d4 gmac (r1p31).
	 */
	gmac_transmit_enable(gmac, false);

	/* The following step should be optional since this function is called
	 * directly by the IRQ handler. Indeed, according to Cadence
	 * documentation, the transmission is halted on errors such as
	 * too many retries or transmit under run.
	 * However it would become mandatory if the call of this function
	 * were scheduled as a task by the IRQ handler (this is how Linux
	 * driver works). Then this function might compete with GMACD_Send().
	 *
	 * Setting bit 10, tx_halt, of the Network Control Register is not enough:
	 * We should wait for bit 3, tx_go, of the Transmit Status Register to
	 * be cleared at transmit completion if a frame is being transmitted.
	 */
	gmac_halt_transmission(gmac);
	while (gmac_get_tx_status(gmac) & GMAC_TSR_TXGO);

	/* Treat frames in TX queue including the ones that caused the error. */
	while (!RING_EMPTY(q->tx_head, q->tx_tail)) {
		int tx_completed = 0;
		desc = &q->tx_desc[q->tx_tail];

		/* Check USED bit on the very first buffer descriptor to validate
		 * TX completion.
		 */
		if (desc->status & GMAC_TX_STATUS_USED)
			tx_completed = 1;

		/* Go to the last buffer descriptor of the frame */
		while ((desc->status & GMAC_TX_STATUS_LASTBUF) == 0) {
			RING_INC(q->tx_tail, q->tx_size);
			desc = &q->tx_desc[q->tx_tail];
		}

		/* Notify upper layer that a frame status */
		// TODO: which error to notify?
		if (q->tx_callbacks) {
			callback = q->tx_callbacks[q->tx_tail];
			if (callback)
				callback(queue, tx_completed ? GMAC_TSR_TXCOMP : 0);
		}

		/* Go to next frame */
		RING_INC(q->tx_tail, q->tx_size);
	}

	/* Reset TX queue */
	_gmacd_reset_tx(gmacd, queue);

	/* Clear status */
	tsr = gmac_get_tx_status(gmac);
	gmac_clear_tx_status(gmac, tsr);

	/* Now we are ready to start transmission again */
	gmac_transmit_enable(gmac, true);
	if (q->tx_wakeup_callback)
		q->tx_wakeup_callback(queue);
}