Merge 66ab401505 into 4db99f4012
This commit is contained in:
commit
593c84c91e
|
|
@ -334,7 +334,7 @@ service at_wini
|
||||||
15 # Controller 1
|
15 # Controller 1
|
||||||
;
|
;
|
||||||
system
|
system
|
||||||
UMAP # 14
|
VUMAP # 18
|
||||||
IRQCTL # 19
|
IRQCTL # 19
|
||||||
DEVIO # 21
|
DEVIO # 21
|
||||||
SDEVIO # 22
|
SDEVIO # 22
|
||||||
|
|
|
||||||
|
|
@ -1052,8 +1052,9 @@ static ssize_t w_transfer(
|
||||||
|
|
||||||
if (do_dma) {
|
if (do_dma) {
|
||||||
stop_dma(wn);
|
stop_dma(wn);
|
||||||
if (!setup_dma(&nbytes, proc_nr, iov, addr_offset, do_write)) {
|
r = setup_dma(&nbytes, proc_nr, iov, addr_offset, do_write);
|
||||||
do_dma = 0;
|
if (r == 0) {
|
||||||
|
return -errno;
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
printf("nbytes = %d\n", nbytes);
|
printf("nbytes = %d\n", nbytes);
|
||||||
|
|
@ -1324,97 +1325,121 @@ static int setup_dma(
|
||||||
endpoint_t proc_nr,
|
endpoint_t proc_nr,
|
||||||
iovec_t *iov,
|
iovec_t *iov,
|
||||||
size_t addr_offset,
|
size_t addr_offset,
|
||||||
int UNUSED(do_write)
|
int do_write
|
||||||
)
|
){
|
||||||
{
|
/* vvec cannot be bigger than prdt, so I think it is a suitable size
|
||||||
phys_bytes user_phys;
|
* Should not exhaust the stack */
|
||||||
unsigned n, offset, size;
|
struct vumap_vir vvec[N_PRDTE];
|
||||||
int i, j, r;
|
struct vumap_phys pvec[N_PRDTE];
|
||||||
|
|
||||||
|
unsigned bytes, offset, size;
|
||||||
|
int i, j, vvec_len, r, pcount;
|
||||||
u32_t v;
|
u32_t v;
|
||||||
struct wini *wn = w_wn;
|
struct wini *wn = w_wn;
|
||||||
|
|
||||||
/* First try direct scatter/gather to the supplied buffers */
|
size = *sizep;
|
||||||
size= *sizep;
|
i = 0; /* pvec index */
|
||||||
i= 0; /* iov index */
|
j = 0; /* prdt index */
|
||||||
j= 0; /* prdt index */
|
vvec_len = 0;
|
||||||
offset= 0; /* Offset in current iov */
|
|
||||||
|
|
||||||
#if VERBOSE_DMA
|
/* Step 1: copy data from iov to vvec */
|
||||||
printf("at_wini: setup_dma: proc_nr %d\n", proc_nr);
|
while (size > 0) {
|
||||||
#endif
|
if (proc_nr == SELF) {
|
||||||
|
vvec[vvec_len].vv_addr = iov[vvec_len].iov_addr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vvec[vvec_len].vv_grant = (cp_grant_id_t)iov[vvec_len].iov_addr;
|
||||||
|
}
|
||||||
|
|
||||||
while (size > 0)
|
if (size < iov[vvec_len].iov_size) {
|
||||||
{
|
vvec[vvec_len].vv_size = size;
|
||||||
#if VERBOSE_DMA
|
|
||||||
printf(
|
|
||||||
"at_wini: setup_dma: iov[%d]: addr 0x%lx, size %ld offset %d, size %d\n",
|
|
||||||
i, iov[i].iov_addr, iov[i].iov_size, offset, size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
n= iov[i].iov_size-offset;
|
|
||||||
if (n > size)
|
|
||||||
n= size;
|
|
||||||
if (n == 0 || (n & 1))
|
|
||||||
panic("bad size in iov: 0x%lx", iov[i].iov_size);
|
|
||||||
if(proc_nr != SELF) {
|
|
||||||
r= sys_umap(proc_nr, VM_GRANT, iov[i].iov_addr, n,
|
|
||||||
&user_phys);
|
|
||||||
if (r != 0)
|
|
||||||
panic("can't map user buffer (VM_GRANT): %d", r);
|
|
||||||
user_phys += offset + addr_offset;
|
|
||||||
} else {
|
} else {
|
||||||
r= sys_umap(proc_nr, VM_D,
|
vvec[vvec_len].vv_size = iov[vvec_len].iov_size;
|
||||||
iov[i].iov_addr+offset+addr_offset, n,
|
|
||||||
&user_phys);
|
|
||||||
if (r != 0)
|
|
||||||
panic("can't map user buffer (VM_D): %d", r);
|
|
||||||
}
|
}
|
||||||
if (user_phys & 1)
|
size -= vvec[vvec_len].vv_size;
|
||||||
{
|
vvec_len++;
|
||||||
/* Buffer is not aligned */
|
|
||||||
printf("setup_dma: user buffer is not aligned\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vector is not allowed to cross a 64K boundary */
|
|
||||||
if (user_phys/0x10000 != (user_phys+n-1)/0x10000)
|
|
||||||
n= ((user_phys/0x10000)+1)*0x10000 - user_phys;
|
|
||||||
|
|
||||||
/* vector is not allowed to be bigger than 64K, but we get that
|
|
||||||
* for free.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (j >= N_PRDTE)
|
|
||||||
{
|
|
||||||
/* Too many entries */
|
|
||||||
printf("setup_dma: user buffer has too many entries\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
prdt[j].prdte_base= user_phys;
|
|
||||||
prdt[j].prdte_count= n;
|
|
||||||
prdt[j].prdte_reserved= 0;
|
|
||||||
prdt[j].prdte_flags= 0;
|
|
||||||
j++;
|
|
||||||
|
|
||||||
offset += n;
|
|
||||||
if (offset >= iov[i].iov_size)
|
|
||||||
{
|
|
||||||
i++;
|
|
||||||
offset= 0;
|
|
||||||
addr_offset= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size -= n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (j <= 0 || j > N_PRDTE)
|
pcount = vvec_len;
|
||||||
panic("bad prdt index: %d", j);
|
|
||||||
prdt[j-1].prdte_flags |= PRDTE_FL_EOT;
|
/* Step 2: sys_vumap */
|
||||||
|
/* sys_vumap should resolve all our addresses in one go,
|
||||||
|
* since caller is required to provide us with physically
|
||||||
|
* contiguous buffers. If sys_vumap fails to do so,
|
||||||
|
* we can just return EINVAL */
|
||||||
|
|
||||||
|
r = sys_vumap(proc_nr, vvec, vvec_len, addr_offset,
|
||||||
|
do_write? VUA_READ : VUA_WRITE, pvec, &pcount);
|
||||||
|
|
||||||
|
if (r != OK) {
|
||||||
|
printf("setup_dma: can't map user buffer: %d", r);
|
||||||
|
errno = EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sanity check: buffers should be 2-aligned
|
||||||
|
* (i.e. their start addresses should be even) */
|
||||||
|
for (i = 0; i < pcount; i++) {
|
||||||
|
if (pvec[i].vp_addr & 1) {
|
||||||
|
printf("setup_dma: user buffer is not aligned\n");
|
||||||
|
errno = EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 3: redistribute pvec ranges to PRD's */
|
||||||
|
i = 0;
|
||||||
|
size = 0;
|
||||||
|
offset = 0;
|
||||||
|
while (i < pcount) {
|
||||||
|
prdt[j].prdte_base = pvec[i].vp_addr + offset;
|
||||||
|
bytes = pvec[i].vp_size - offset;
|
||||||
|
|
||||||
|
/* make sure PRD does not cross 64K boundary */
|
||||||
|
if (prdt[j].prdte_base / 0x10000 !=
|
||||||
|
(prdt[j].prdte_base + bytes - 1) / 0x10000) {
|
||||||
|
bytes = ((prdt[j].prdte_base / 0x10000) + 1) * 0x10000
|
||||||
|
- prdt[j].prdte_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PRD size must not exceed 64K, but we get that for free */
|
||||||
|
|
||||||
|
prdt[j].prdte_count = bytes;
|
||||||
|
prdt[j].prdte_reserved = 0;
|
||||||
|
prdt[j].prdte_flags = 0;
|
||||||
|
|
||||||
|
offset += bytes;
|
||||||
|
if (offset == pvec[i].vp_size) {
|
||||||
|
i++;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* keeping track of how much data in vvec were processed */
|
||||||
|
size += bytes;
|
||||||
|
|
||||||
|
j++;
|
||||||
|
if (j == N_PRDTE && i < pcount) {
|
||||||
|
/* we are out of PRDT space and not yet done with
|
||||||
|
* all regions! Bail out gracefully. */
|
||||||
|
printf("setup_dma: user buffer has too many entries\n");
|
||||||
|
errno = EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prdt[j - 1].prdte_flags |= PRDTE_FL_EOT;
|
||||||
|
|
||||||
|
if (size < *sizep) {
|
||||||
|
/* sys_vumap didn't resolve everything in one go, therefore
|
||||||
|
* buffers were not physically contiguous.
|
||||||
|
*/
|
||||||
|
printf("setup_dma: user buffers are not physically contiguous\n");
|
||||||
|
errno = EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#if VERBOSE_DMA
|
#if VERBOSE_DMA
|
||||||
printf("dma not bad\n");
|
printf("dma not bad\n");
|
||||||
for (i= 0; i<j; i++) {
|
for (i = 0; i < j; i++) {
|
||||||
printf("prdt[%d]: base 0x%lx, size %d, flags 0x%x\n",
|
printf("prdt[%d]: base 0x%lx, size %d, flags 0x%x\n",
|
||||||
i, prdt[i].prdte_base, prdt[i].prdte_count,
|
i, prdt[i].prdte_base, prdt[i].prdte_count,
|
||||||
prdt[i].prdte_flags);
|
prdt[i].prdte_flags);
|
||||||
|
|
@ -1422,18 +1447,18 @@ static int setup_dma(
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Verify that the bus master is not active */
|
/* Verify that the bus master is not active */
|
||||||
r= sys_inb(wn->base_dma + DMA_STATUS, &v);
|
r = sys_inb(wn->base_dma + DMA_STATUS, &v);
|
||||||
if (r != 0) panic("setup_dma: sys_inb failed: %d", r);
|
if (r != 0) panic("setup_dma: sys_inb failed: %d", r);
|
||||||
if (v & DMA_ST_BM_ACTIVE)
|
if (v & DMA_ST_BM_ACTIVE)
|
||||||
panic("Bus master IDE active");
|
panic("Bus master IDE active");
|
||||||
|
|
||||||
if (prdt_phys & 3)
|
if (prdt_phys & 3)
|
||||||
panic("prdt not aligned: 0x%lx", prdt_phys);
|
panic("prdt not aligned: 0x%lx", prdt_phys);
|
||||||
r= sys_outl(wn->base_dma + DMA_PRDTP, prdt_phys);
|
r = sys_outl(wn->base_dma + DMA_PRDTP, prdt_phys);
|
||||||
if (r != 0) panic("setup_dma: sys_outl failed: %d", r);
|
if (r != 0) panic("setup_dma: sys_outl failed: %d", r);
|
||||||
|
|
||||||
/* Clear interrupt and error flags */
|
/* Clear interrupt and error flags */
|
||||||
r= sys_outb(wn->base_dma + DMA_STATUS, DMA_ST_INT | DMA_ST_ERROR);
|
r = sys_outb(wn->base_dma + DMA_STATUS, DMA_ST_INT | DMA_ST_ERROR);
|
||||||
if (r != 0) panic("setup_dma: sys_outb failed: %d", r);
|
if (r != 0) panic("setup_dma: sys_outb failed: %d", r);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -1849,8 +1874,9 @@ static int atapi_transfer(
|
||||||
|
|
||||||
if(do_dma) {
|
if(do_dma) {
|
||||||
stop_dma(wn);
|
stop_dma(wn);
|
||||||
if (!setup_dma(&nbytes, proc_nr, iov, addr_offset, 0)) {
|
r = setup_dma(&nbytes, proc_nr, iov, addr_offset, 0);
|
||||||
do_dma = 0;
|
if (r == 0) {
|
||||||
|
return errno;
|
||||||
} else if(nbytes != nblocks * CD_SECTOR_SIZE) {
|
} else if(nbytes != nblocks * CD_SECTOR_SIZE) {
|
||||||
stop_dma(wn);
|
stop_dma(wn);
|
||||||
do_dma = 0;
|
do_dma = 0;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user