Example #1
0
static void wbsd_empty_fifo(struct wbsd_host *host)
{
	struct mmc_data *data = host->mrq->cmd->data;
	char *buffer;
	int i, fsr, fifo;

	/*
	 * Handle excessive data.
	 */
	if (host->num_sg == 0)
		return;

	buffer = wbsd_sg_to_buffer(host) + host->offset;

	/*
	 * Drain the fifo. This has a tendency to loop longer
	 * than the FIFO length (usually one block).
	 */
	while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_EMPTY)) {
		/*
		 * The size field in the FSR is broken so we have to
		 * do some guessing.
		 */
		if (fsr & WBSD_FIFO_FULL)
			fifo = 16;
		else if (fsr & WBSD_FIFO_FUTHRE)
			fifo = 8;
		else
			fifo = 1;

		for (i = 0; i < fifo; i++) {
			*buffer = inb(host->base + WBSD_DFR);
			buffer++;
			host->offset++;
			host->remain--;

			data->bytes_xfered++;

			/*
			 * End of scatter list entry?
			 */
			if (host->remain == 0) {
				/*
				 * Get next entry. Check if last.
				 */
				if (!wbsd_next_sg(host))
					return;

				buffer = wbsd_sg_to_buffer(host);
			}
		}
	}

	/*
	 * This is a very dirty hack to solve a
	 * hardware problem. The chip doesn't trigger
	 * FIFO threshold interrupts properly.
	 */
	if ((data->blocks * data->blksz - data->bytes_xfered) < 16)
		tasklet_schedule(&host->fifo_tasklet);
}
Example #2
0
static void wbsd_fill_fifo(struct wbsd_host *host)
{
	struct mmc_data *data = host->mrq->cmd->data;
	char *buffer;
	int i, fsr, fifo;

	/*
	 * Check that we aren't being called after the
	 * entire buffer has been transferred.
	 */
	if (host->num_sg == 0)
		return;

	buffer = wbsd_sg_to_buffer(host) + host->offset;

	/*
	 * Fill the fifo. This has a tendency to loop longer
	 * than the FIFO length (usually one block).
	 */
	while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_FULL)) {
		/*
		 * The size field in the FSR is broken so we have to
		 * do some guessing.
		 */
		if (fsr & WBSD_FIFO_EMPTY)
			fifo = 0;
		else if (fsr & WBSD_FIFO_EMTHRE)
			fifo = 8;
		else
			fifo = 15;

		for (i = 16; i > fifo; i--) {
			outb(*buffer, host->base + WBSD_DFR);
			buffer++;
			host->offset++;
			host->remain--;

			data->bytes_xfered++;

			/*
			 * End of scatter list entry?
			 */
			if (host->remain == 0) {
				/*
				 * Get next entry. Check if last.
				 */
				if (!wbsd_next_sg(host))
					return;

				buffer = wbsd_sg_to_buffer(host);
			}
		}
	}

	/*
	 * The controller stops sending interrupts for
	 * 'FIFO empty' under certain conditions. So we
	 * need to be a bit more pro-active.
	 */
	tasklet_schedule(&host->fifo_tasklet);
}
Example #3
0
static void wbsd_fill_fifo(struct wbsd_host* host)
{
	struct mmc_data* data = host->mrq->cmd->data;
	char* buffer;
	
	/*
	 * Check that we aren't being called after the
	 * entire buffer has been transfered.
	 */
	if (data->bytes_xfered == host->size)
		return;

	buffer = wbsd_kmap_sg(host) + host->offset;

	/*
	 * Fill the fifo. This has a tendency to loop longer
	 * than the FIFO length (usually one block).
	 */
	while (!(inb(host->base + WBSD_FSR) & WBSD_FIFO_FULL))
	{
		outb(*buffer, host->base + WBSD_DFR);
		buffer++;
		host->offset++;
		host->remain--;
		
		data->bytes_xfered++;
		
		/*
		 * Transfer done?
		 */
		if (data->bytes_xfered == host->size)
		{
			wbsd_kunmap_sg(host);
			return;
		}

		/*
		 * End of scatter list entry?
		 */
		if (host->remain == 0)
		{
			wbsd_kunmap_sg(host);
			
			/*
			 * Get next entry. Check if last.
			 */
			if (!wbsd_next_sg(host))
			{
				/*
				 * We should never reach this point.
				 * It means that we're trying to
				 * transfer more blocks than can fit
				 * into the scatter list.
				 */
				BUG_ON(1);
				
				host->size = data->bytes_xfered;
				
				return;
			}
			
			buffer = wbsd_kmap_sg(host);
		}
	}
	
	wbsd_kunmap_sg(host);
}