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); }
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); }
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); }