fix to simulate multi-segment dma transfer for pq3sdhc(4).
This commit is contained in:
parent
f6920c646c
commit
ce4ff06e02
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: sdmmc.c,v 1.23 2014/11/16 16:20:01 ozaki-r Exp $ */
|
||||
/* $NetBSD: sdmmc.c,v 1.24 2015/02/27 16:08:17 nonaka Exp $ */
|
||||
/* $OpenBSD: sdmmc.c,v 1.18 2009/01/09 10:58:38 jsg Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -49,7 +49,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.23 2014/11/16 16:20:01 ozaki-r Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.24 2015/02/27 16:08:17 nonaka Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_sdmmc.h"
|
||||
|
@ -626,25 +626,31 @@ sdmmc_function_alloc(struct sdmmc_softc *sc)
|
|||
bus_dma_segment_t ds;
|
||||
int rseg, error;
|
||||
|
||||
error = bus_dmamap_create(sc->sc_dmat, SDMMC_SECTOR_SIZE, 1,
|
||||
SDMMC_SECTOR_SIZE, 0, BUS_DMA_WAITOK, &sf->bbuf_dmap);
|
||||
error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, 1,
|
||||
MAXPHYS, 0, BUS_DMA_WAITOK, &sf->bbuf_dmap);
|
||||
if (error)
|
||||
goto fail1;
|
||||
error = bus_dmamem_alloc(sc->sc_dmat, SDMMC_SECTOR_SIZE,
|
||||
error = bus_dmamem_alloc(sc->sc_dmat, MAXPHYS,
|
||||
PAGE_SIZE, 0, &ds, 1, &rseg, BUS_DMA_WAITOK);
|
||||
if (error)
|
||||
goto fail2;
|
||||
error = bus_dmamem_map(sc->sc_dmat, &ds, 1, SDMMC_SECTOR_SIZE,
|
||||
error = bus_dmamem_map(sc->sc_dmat, &ds, 1, MAXPHYS,
|
||||
&sf->bbuf, BUS_DMA_WAITOK);
|
||||
if (error)
|
||||
goto fail3;
|
||||
error = bus_dmamap_load(sc->sc_dmat, sf->bbuf_dmap,
|
||||
sf->bbuf, SDMMC_SECTOR_SIZE, NULL,
|
||||
sf->bbuf, MAXPHYS, NULL,
|
||||
BUS_DMA_WAITOK|BUS_DMA_READ|BUS_DMA_WRITE);
|
||||
if (error)
|
||||
goto fail4;
|
||||
error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, 1,
|
||||
MAXPHYS, 0, BUS_DMA_WAITOK, &sf->sseg_dmap);
|
||||
if (!error)
|
||||
goto out;
|
||||
|
||||
bus_dmamem_unmap(sc->sc_dmat, sf->bbuf, SDMMC_SECTOR_SIZE);
|
||||
bus_dmamap_unload(sc->sc_dmat, sf->bbuf_dmap);
|
||||
fail4:
|
||||
bus_dmamem_unmap(sc->sc_dmat, sf->bbuf, MAXPHYS);
|
||||
fail3:
|
||||
bus_dmamem_free(sc->sc_dmat, &ds, 1);
|
||||
fail2:
|
||||
|
@ -666,8 +672,9 @@ sdmmc_function_free(struct sdmmc_function *sf)
|
|||
if (ISSET(sc->sc_flags, SMF_MEM_MODE) &&
|
||||
ISSET(sc->sc_caps, SMC_CAPS_DMA) &&
|
||||
!ISSET(sc->sc_caps, SMC_CAPS_MULTI_SEG_DMA)) {
|
||||
bus_dmamap_destroy(sc->sc_dmat, sf->sseg_dmap);
|
||||
bus_dmamap_unload(sc->sc_dmat, sf->bbuf_dmap);
|
||||
bus_dmamem_unmap(sc->sc_dmat, sf->bbuf, SDMMC_SECTOR_SIZE);
|
||||
bus_dmamem_unmap(sc->sc_dmat, sf->bbuf, MAXPHYS);
|
||||
bus_dmamem_free(sc->sc_dmat,
|
||||
sf->bbuf_dmap->dm_segs, sf->bbuf_dmap->dm_nsegs);
|
||||
bus_dmamap_destroy(sc->sc_dmat, sf->bbuf_dmap);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: sdmmc_mem.c,v 1.33 2015/02/07 04:13:26 christos Exp $ */
|
||||
/* $NetBSD: sdmmc_mem.c,v 1.34 2015/02/27 16:08:17 nonaka Exp $ */
|
||||
/* $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -45,7 +45,7 @@
|
|||
/* Routines for SD/MMC memory cards. */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.33 2015/02/07 04:13:26 christos Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.34 2015/02/27 16:08:17 nonaka Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_sdmmc.h"
|
||||
|
@ -87,10 +87,14 @@ static int sdmmc_mem_single_read_block(struct sdmmc_function *, uint32_t,
|
|||
u_char *, size_t);
|
||||
static int sdmmc_mem_single_write_block(struct sdmmc_function *, uint32_t,
|
||||
u_char *, size_t);
|
||||
static int sdmmc_mem_read_block_subr(struct sdmmc_function *, uint32_t,
|
||||
u_char *, size_t);
|
||||
static int sdmmc_mem_write_block_subr(struct sdmmc_function *, uint32_t,
|
||||
u_char *, size_t);
|
||||
static int sdmmc_mem_single_segment_dma_read_block(struct sdmmc_function *,
|
||||
uint32_t, u_char *, size_t);
|
||||
static int sdmmc_mem_single_segment_dma_write_block(struct sdmmc_function *,
|
||||
uint32_t, u_char *, size_t);
|
||||
static int sdmmc_mem_read_block_subr(struct sdmmc_function *, bus_dmamap_t,
|
||||
uint32_t, u_char *, size_t);
|
||||
static int sdmmc_mem_write_block_subr(struct sdmmc_function *, bus_dmamap_t,
|
||||
uint32_t, u_char *, size_t);
|
||||
|
||||
/*
|
||||
* Initialize SD/MMC memory cards and memory in SDIO "combo" cards.
|
||||
|
@ -1251,7 +1255,7 @@ static int
|
|||
sdmmc_mem_single_read_block(struct sdmmc_function *sf, uint32_t blkno,
|
||||
u_char *data, size_t datalen)
|
||||
{
|
||||
struct sdmmc_softc *sc __diagused = sf->sc;
|
||||
struct sdmmc_softc *sc = sf->sc;
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
|
@ -1259,7 +1263,7 @@ sdmmc_mem_single_read_block(struct sdmmc_function *sf, uint32_t blkno,
|
|||
KASSERT(!ISSET(sc->sc_caps, SMC_CAPS_DMA));
|
||||
|
||||
for (i = 0; i < datalen / SDMMC_SECTOR_SIZE; i++) {
|
||||
error = sdmmc_mem_read_block_subr(sf, blkno + i,
|
||||
error = sdmmc_mem_read_block_subr(sf, sc->sc_dmap, blkno + i,
|
||||
data + i * SDMMC_SECTOR_SIZE, SDMMC_SECTOR_SIZE);
|
||||
if (error)
|
||||
break;
|
||||
|
@ -1267,13 +1271,81 @@ sdmmc_mem_single_read_block(struct sdmmc_function *sf, uint32_t blkno,
|
|||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simulate multi-segment dma transfer.
|
||||
*/
|
||||
static int
|
||||
sdmmc_mem_read_block_subr(struct sdmmc_function *sf, uint32_t blkno,
|
||||
u_char *data, size_t datalen)
|
||||
sdmmc_mem_single_segment_dma_read_block(struct sdmmc_function *sf,
|
||||
uint32_t blkno, u_char *data, size_t datalen)
|
||||
{
|
||||
struct sdmmc_softc *sc = sf->sc;
|
||||
bool use_bbuf = false;
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sc->sc_dmap->dm_nsegs; i++) {
|
||||
size_t len = sc->sc_dmap->dm_segs[i].ds_len;
|
||||
if ((len % SDMMC_SECTOR_SIZE) != 0) {
|
||||
use_bbuf = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (use_bbuf) {
|
||||
bus_dmamap_sync(sc->sc_dmat, sf->bbuf_dmap, 0, datalen,
|
||||
BUS_DMASYNC_PREREAD);
|
||||
|
||||
error = sdmmc_mem_read_block_subr(sf, sf->bbuf_dmap,
|
||||
blkno, data, datalen);
|
||||
if (error) {
|
||||
bus_dmamap_unload(sc->sc_dmat, sf->bbuf_dmap);
|
||||
return error;
|
||||
}
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmat, sf->bbuf_dmap, 0, datalen,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
|
||||
/* Copy from bounce buffer */
|
||||
memcpy(data, sf->bbuf, datalen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < sc->sc_dmap->dm_nsegs; i++) {
|
||||
size_t len = sc->sc_dmap->dm_segs[i].ds_len;
|
||||
|
||||
error = bus_dmamap_load(sc->sc_dmat, sf->sseg_dmap,
|
||||
data, len, NULL, BUS_DMA_NOWAIT|BUS_DMA_READ);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmat, sf->sseg_dmap, 0, len,
|
||||
BUS_DMASYNC_PREREAD);
|
||||
|
||||
error = sdmmc_mem_read_block_subr(sf, sf->sseg_dmap,
|
||||
blkno, data, len);
|
||||
if (error) {
|
||||
bus_dmamap_unload(sc->sc_dmat, sf->sseg_dmap);
|
||||
return error;
|
||||
}
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmat, sf->sseg_dmap, 0, len,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
|
||||
bus_dmamap_unload(sc->sc_dmat, sf->sseg_dmap);
|
||||
|
||||
blkno += len / SDMMC_SECTOR_SIZE;
|
||||
data += len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sdmmc_mem_read_block_subr(struct sdmmc_function *sf, bus_dmamap_t dmap,
|
||||
uint32_t blkno, u_char *data, size_t datalen)
|
||||
{
|
||||
struct sdmmc_softc *sc = sf->sc;
|
||||
struct sdmmc_command cmd;
|
||||
int error, bbuf, seg, off, len, num;
|
||||
int error;
|
||||
|
||||
if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) {
|
||||
error = sdmmc_select_card(sc, sf);
|
||||
|
@ -1281,10 +1353,6 @@ sdmmc_mem_read_block_subr(struct sdmmc_function *sf, uint32_t blkno,
|
|||
goto out;
|
||||
}
|
||||
|
||||
bbuf = 0;
|
||||
num = 0;
|
||||
seg = off = len = 0;
|
||||
retry:
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.c_data = data;
|
||||
cmd.c_datalen = datalen;
|
||||
|
@ -1295,30 +1363,8 @@ retry:
|
|||
if (!ISSET(sf->flags, SFF_SDHC))
|
||||
cmd.c_arg <<= SDMMC_SECTOR_SIZE_SB;
|
||||
cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1 | SCF_RSP_SPI_R1;
|
||||
if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
|
||||
cmd.c_dmamap = sc->sc_dmap;
|
||||
if (!ISSET(sc->sc_caps, SMC_CAPS_MULTI_SEG_DMA)) {
|
||||
len = sc->sc_dmap->dm_segs[seg].ds_len - off;
|
||||
len &= ~(SDMMC_SECTOR_SIZE - 1);
|
||||
cmd.c_datalen = len;
|
||||
cmd.c_dmaseg = seg;
|
||||
cmd.c_dmaoff = off;
|
||||
bbuf = 0;
|
||||
if (len == 0) {
|
||||
/* Use bounce buffer */
|
||||
bus_dmamap_sync(sc->sc_dmat, sf->bbuf_dmap,
|
||||
0, SDMMC_SECTOR_SIZE, BUS_DMASYNC_PREREAD);
|
||||
cmd.c_datalen = SDMMC_SECTOR_SIZE;
|
||||
cmd.c_dmamap = sf->bbuf_dmap;
|
||||
cmd.c_dmaseg = 0;
|
||||
cmd.c_dmaoff = 0;
|
||||
bbuf = 1;
|
||||
len = SDMMC_SECTOR_SIZE;
|
||||
}
|
||||
cmd.c_opcode = (cmd.c_datalen / cmd.c_blklen) > 1 ?
|
||||
MMC_READ_BLOCK_MULTIPLE : MMC_READ_BLOCK_SINGLE;
|
||||
}
|
||||
}
|
||||
if (ISSET(sc->sc_caps, SMC_CAPS_DMA))
|
||||
cmd.c_dmamap = dmap;
|
||||
|
||||
error = sdmmc_mmc_command(sc, &cmd);
|
||||
if (error)
|
||||
|
@ -1350,34 +1396,6 @@ retry:
|
|||
} while (!ISSET(MMC_R1(cmd.c_resp), MMC_R1_READY_FOR_DATA));
|
||||
}
|
||||
|
||||
if (ISSET(sc->sc_caps, SMC_CAPS_DMA) &&
|
||||
!ISSET(sc->sc_caps, SMC_CAPS_MULTI_SEG_DMA)) {
|
||||
bus_dma_segment_t *dm_segs = sc->sc_dmap->dm_segs;
|
||||
|
||||
if (bbuf) {
|
||||
bus_dmamap_sync(sc->sc_dmat, sf->bbuf_dmap,
|
||||
0, SDMMC_SECTOR_SIZE, BUS_DMASYNC_POSTREAD);
|
||||
bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, num,
|
||||
SDMMC_SECTOR_SIZE, BUS_DMASYNC_POSTREAD);
|
||||
memcpy(data, sf->bbuf, SDMMC_SECTOR_SIZE);
|
||||
bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, num,
|
||||
SDMMC_SECTOR_SIZE, BUS_DMASYNC_PREREAD);
|
||||
}
|
||||
num += len;
|
||||
data += len;
|
||||
datalen -= len;
|
||||
blkno += (len / SDMMC_SECTOR_SIZE);
|
||||
|
||||
while (off + len >= dm_segs[seg].ds_len) {
|
||||
len -= dm_segs[seg++].ds_len;
|
||||
off = 0;
|
||||
}
|
||||
off += len;
|
||||
|
||||
if (seg < sc->sc_dmap->dm_nsegs)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
@ -1397,7 +1415,8 @@ sdmmc_mem_read_block(struct sdmmc_function *sf, uint32_t blkno, u_char *data,
|
|||
}
|
||||
|
||||
if (!ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
|
||||
error = sdmmc_mem_read_block_subr(sf, blkno, data, datalen);
|
||||
error = sdmmc_mem_read_block_subr(sf, sc->sc_dmap, blkno, data,
|
||||
datalen);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -1408,6 +1427,7 @@ sdmmc_mem_read_block(struct sdmmc_function *sf, uint32_t blkno, u_char *data,
|
|||
goto out;
|
||||
|
||||
#ifdef SDMMC_DEBUG
|
||||
printf("data=%p, datalen=%zu\n", data, datalen);
|
||||
for (int i = 0; i < sc->sc_dmap->dm_nsegs; i++) {
|
||||
printf("seg#%d: addr=%#lx, size=%#lx\n", i,
|
||||
(u_long)sc->sc_dmap->dm_segs[i].ds_addr,
|
||||
|
@ -1415,10 +1435,18 @@ sdmmc_mem_read_block(struct sdmmc_function *sf, uint32_t blkno, u_char *data,
|
|||
}
|
||||
#endif
|
||||
|
||||
if (sc->sc_dmap->dm_nsegs > 1
|
||||
&& !ISSET(sc->sc_caps, SMC_CAPS_MULTI_SEG_DMA)) {
|
||||
error = sdmmc_mem_single_segment_dma_read_block(sf, blkno,
|
||||
data, datalen);
|
||||
goto unload;
|
||||
}
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
|
||||
BUS_DMASYNC_PREREAD);
|
||||
|
||||
error = sdmmc_mem_read_block_subr(sf, blkno, data, datalen);
|
||||
error = sdmmc_mem_read_block_subr(sf, sc->sc_dmap, blkno, data,
|
||||
datalen);
|
||||
if (error)
|
||||
goto unload;
|
||||
|
||||
|
@ -1438,7 +1466,7 @@ static int
|
|||
sdmmc_mem_single_write_block(struct sdmmc_function *sf, uint32_t blkno,
|
||||
u_char *data, size_t datalen)
|
||||
{
|
||||
struct sdmmc_softc *sc __diagused = sf->sc;
|
||||
struct sdmmc_softc *sc = sf->sc;
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
|
@ -1446,7 +1474,7 @@ sdmmc_mem_single_write_block(struct sdmmc_function *sf, uint32_t blkno,
|
|||
KASSERT(!ISSET(sc->sc_caps, SMC_CAPS_DMA));
|
||||
|
||||
for (i = 0; i < datalen / SDMMC_SECTOR_SIZE; i++) {
|
||||
error = sdmmc_mem_write_block_subr(sf, blkno + i,
|
||||
error = sdmmc_mem_write_block_subr(sf, sc->sc_dmap, blkno + i,
|
||||
data + i * SDMMC_SECTOR_SIZE, SDMMC_SECTOR_SIZE);
|
||||
if (error)
|
||||
break;
|
||||
|
@ -1454,13 +1482,82 @@ sdmmc_mem_single_write_block(struct sdmmc_function *sf, uint32_t blkno,
|
|||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simulate multi-segment dma transfer.
|
||||
*/
|
||||
static int
|
||||
sdmmc_mem_write_block_subr(struct sdmmc_function *sf, uint32_t blkno,
|
||||
u_char *data, size_t datalen)
|
||||
sdmmc_mem_single_segment_dma_write_block(struct sdmmc_function *sf,
|
||||
uint32_t blkno, u_char *data, size_t datalen)
|
||||
{
|
||||
struct sdmmc_softc *sc = sf->sc;
|
||||
bool use_bbuf = false;
|
||||
int error = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sc->sc_dmap->dm_nsegs; i++) {
|
||||
size_t len = sc->sc_dmap->dm_segs[i].ds_len;
|
||||
if ((len % SDMMC_SECTOR_SIZE) != 0) {
|
||||
use_bbuf = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (use_bbuf) {
|
||||
/* Copy to bounce buffer */
|
||||
memcpy(sf->bbuf, data, datalen);
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmat, sf->bbuf_dmap, 0, datalen,
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
|
||||
error = sdmmc_mem_write_block_subr(sf, sf->bbuf_dmap,
|
||||
blkno, data, datalen);
|
||||
if (error) {
|
||||
bus_dmamap_unload(sc->sc_dmat, sf->bbuf_dmap);
|
||||
return error;
|
||||
}
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmat, sf->bbuf_dmap, 0, datalen,
|
||||
BUS_DMASYNC_POSTWRITE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < sc->sc_dmap->dm_nsegs; i++) {
|
||||
size_t len = sc->sc_dmap->dm_segs[i].ds_len;
|
||||
|
||||
error = bus_dmamap_load(sc->sc_dmat, sf->sseg_dmap,
|
||||
data, len, NULL, BUS_DMA_NOWAIT|BUS_DMA_WRITE);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmat, sf->sseg_dmap, 0, len,
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
|
||||
error = sdmmc_mem_write_block_subr(sf, sf->sseg_dmap,
|
||||
blkno, data, len);
|
||||
if (error) {
|
||||
bus_dmamap_unload(sc->sc_dmat, sf->sseg_dmap);
|
||||
return error;
|
||||
}
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmat, sf->sseg_dmap, 0, len,
|
||||
BUS_DMASYNC_POSTWRITE);
|
||||
|
||||
bus_dmamap_unload(sc->sc_dmat, sf->sseg_dmap);
|
||||
|
||||
blkno += len / SDMMC_SECTOR_SIZE;
|
||||
data += len;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
sdmmc_mem_write_block_subr(struct sdmmc_function *sf, bus_dmamap_t dmap,
|
||||
uint32_t blkno, u_char *data, size_t datalen)
|
||||
{
|
||||
struct sdmmc_softc *sc = sf->sc;
|
||||
struct sdmmc_command cmd;
|
||||
int error, bbuf, seg, off, len, num;
|
||||
int error;
|
||||
|
||||
if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) {
|
||||
error = sdmmc_select_card(sc, sf);
|
||||
|
@ -1468,10 +1565,6 @@ sdmmc_mem_write_block_subr(struct sdmmc_function *sf, uint32_t blkno,
|
|||
goto out;
|
||||
}
|
||||
|
||||
bbuf = 0;
|
||||
num = 0;
|
||||
seg = off = len = 0;
|
||||
retry:
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.c_data = data;
|
||||
cmd.c_datalen = datalen;
|
||||
|
@ -1482,35 +1575,8 @@ retry:
|
|||
if (!ISSET(sf->flags, SFF_SDHC))
|
||||
cmd.c_arg <<= SDMMC_SECTOR_SIZE_SB;
|
||||
cmd.c_flags = SCF_CMD_ADTC | SCF_RSP_R1;
|
||||
if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
|
||||
cmd.c_dmamap = sc->sc_dmap;
|
||||
if (!ISSET(sc->sc_caps, SMC_CAPS_MULTI_SEG_DMA)) {
|
||||
len = sc->sc_dmap->dm_segs[seg].ds_len - off;
|
||||
len &= ~(SDMMC_SECTOR_SIZE - 1);
|
||||
cmd.c_datalen = len;
|
||||
cmd.c_dmaseg = seg;
|
||||
cmd.c_dmaoff = off;
|
||||
bbuf = 0;
|
||||
if (len == 0) {
|
||||
/* Use bounce buffer */
|
||||
bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, num,
|
||||
SDMMC_SECTOR_SIZE, BUS_DMASYNC_POSTWRITE);
|
||||
memcpy(sf->bbuf, data, SDMMC_SECTOR_SIZE);
|
||||
bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, num,
|
||||
SDMMC_SECTOR_SIZE, BUS_DMASYNC_PREWRITE);
|
||||
bus_dmamap_sync(sc->sc_dmat, sf->bbuf_dmap, 0,
|
||||
SDMMC_SECTOR_SIZE, BUS_DMASYNC_PREWRITE);
|
||||
cmd.c_datalen = SDMMC_SECTOR_SIZE;
|
||||
cmd.c_dmamap = sf->bbuf_dmap;
|
||||
cmd.c_dmaseg = 0;
|
||||
cmd.c_dmaoff = 0;
|
||||
bbuf = 1;
|
||||
len = SDMMC_SECTOR_SIZE;
|
||||
}
|
||||
cmd.c_opcode = (cmd.c_datalen / cmd.c_blklen) > 1 ?
|
||||
MMC_WRITE_BLOCK_MULTIPLE : MMC_WRITE_BLOCK_SINGLE;
|
||||
}
|
||||
}
|
||||
if (ISSET(sc->sc_caps, SMC_CAPS_DMA))
|
||||
cmd.c_dmamap = dmap;
|
||||
|
||||
error = sdmmc_mmc_command(sc, &cmd);
|
||||
if (error)
|
||||
|
@ -1541,28 +1607,6 @@ retry:
|
|||
} while (!ISSET(MMC_R1(cmd.c_resp), MMC_R1_READY_FOR_DATA));
|
||||
}
|
||||
|
||||
if (ISSET(sc->sc_caps, SMC_CAPS_DMA) &&
|
||||
!ISSET(sc->sc_caps, SMC_CAPS_MULTI_SEG_DMA)) {
|
||||
bus_dma_segment_t *dm_segs = sc->sc_dmap->dm_segs;
|
||||
|
||||
if (bbuf)
|
||||
bus_dmamap_sync(sc->sc_dmat, sf->bbuf_dmap,
|
||||
0, SDMMC_SECTOR_SIZE, BUS_DMASYNC_POSTWRITE);
|
||||
num += len;
|
||||
data += len;
|
||||
datalen -= len;
|
||||
blkno += (len / SDMMC_SECTOR_SIZE);
|
||||
|
||||
while (off + len >= dm_segs[seg].ds_len) {
|
||||
len -= dm_segs[seg++].ds_len;
|
||||
off = 0;
|
||||
}
|
||||
off += len;
|
||||
|
||||
if (seg < sc->sc_dmap->dm_nsegs)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
@ -1588,7 +1632,8 @@ sdmmc_mem_write_block(struct sdmmc_function *sf, uint32_t blkno, u_char *data,
|
|||
}
|
||||
|
||||
if (!ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
|
||||
error = sdmmc_mem_write_block_subr(sf, blkno, data, datalen);
|
||||
error = sdmmc_mem_write_block_subr(sf, sc->sc_dmap, blkno, data,
|
||||
datalen);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -1599,17 +1644,28 @@ sdmmc_mem_write_block(struct sdmmc_function *sf, uint32_t blkno, u_char *data,
|
|||
goto out;
|
||||
|
||||
#ifdef SDMMC_DEBUG
|
||||
aprint_normal_dev(sc->sc_dev, "%s: data=%p, datalen=%zu\n",
|
||||
__func__, data, datalen);
|
||||
for (int i = 0; i < sc->sc_dmap->dm_nsegs; i++) {
|
||||
printf("seg#%d: addr=%#lx, size=%#lx\n", i,
|
||||
aprint_normal_dev(sc->sc_dev,
|
||||
"%s: seg#%d: addr=%#lx, size=%#lx\n", __func__, i,
|
||||
(u_long)sc->sc_dmap->dm_segs[i].ds_addr,
|
||||
(u_long)sc->sc_dmap->dm_segs[i].ds_len);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sc->sc_dmap->dm_nsegs > 1
|
||||
&& !ISSET(sc->sc_caps, SMC_CAPS_MULTI_SEG_DMA)) {
|
||||
error = sdmmc_mem_single_segment_dma_write_block(sf, blkno,
|
||||
data, datalen);
|
||||
goto unload;
|
||||
}
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
|
||||
error = sdmmc_mem_write_block_subr(sf, blkno, data, datalen);
|
||||
error = sdmmc_mem_write_block_subr(sf, sc->sc_dmap, blkno, data,
|
||||
datalen);
|
||||
if (error)
|
||||
goto unload;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: sdmmcvar.h,v 1.15 2014/03/19 15:26:42 nonaka Exp $ */
|
||||
/* $NetBSD: sdmmcvar.h,v 1.16 2015/02/27 16:08:17 nonaka Exp $ */
|
||||
/* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */
|
||||
|
||||
/*
|
||||
|
@ -189,6 +189,7 @@ struct sdmmc_function {
|
|||
|
||||
void *bbuf; /* bounce buffer */
|
||||
bus_dmamap_t bbuf_dmap; /* DMA map for bounce buffer */
|
||||
bus_dmamap_t sseg_dmap; /* DMA map for single segment */
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue