ahci: use sys_vumap() instead of sys_umap()

This is only an optimization for CPU performance. Callers are
currently still required to supply contiguous memory.
This commit is contained in:
David van Moolenbroek 2012-01-11 23:54:53 +01:00
parent 70abb127cc
commit 186a4db672
3 changed files with 45 additions and 34 deletions

View file

@ -258,8 +258,8 @@ PRIVATE int atapi_exec(struct port_state *ps, int cmd,
if (!write && (ps->flags & FLAG_USE_DMADIR))
fis.cf_feat |= ATA_FEAT_PACKET_DMADIR;
prd.prd_phys = ps->tmp_phys;
prd.prd_size = size;
prd.vp_addr = ps->tmp_phys;
prd.vp_size = size;
nr_prds++;
}
@ -640,8 +640,8 @@ PRIVATE int gen_identify(struct port_state *ps, int blocking)
else
fis.cf_cmd = ATA_CMD_IDENTIFY;
prd.prd_phys = ps->tmp_phys;
prd.prd_size = ATA_ID_SIZE;
prd.vp_addr = ps->tmp_phys;
prd.vp_size = ATA_ID_SIZE;
/* Start the command, and possibly wait for the result. */
port_set_cmd(ps, 0, &fis, NULL /*packet*/, &prd, 1, FALSE /*write*/);
@ -803,10 +803,10 @@ PRIVATE void ct_set_prdt(u8_t *ct, prd_t *prdt, int nr_prds)
p = (u32_t *) &ct[AHCI_CT_PRDT_OFF];
for (i = 0; i < nr_prds; i++, prdt++) {
*p++ = prdt->prd_phys;
*p++ = prdt->vp_addr;
*p++ = 0;
*p++ = 0;
*p++ = prdt->prd_size - 1;
*p++ = prdt->vp_size - 1;
}
}
@ -1026,7 +1026,7 @@ PRIVATE int sum_iovec(struct port_state *ps, endpoint_t endpt,
*===========================================================================*/
PRIVATE int setup_prdt(struct port_state *ps, endpoint_t endpt,
iovec_s_t *iovec, int nr_req, vir_bytes size, vir_bytes lead,
prd_t *prdt)
int write, prd_t *prdt)
{
/* Convert (the first part of) an I/O vector to a Physical Region
* Descriptor Table describing array that can later be used to set the
@ -1035,57 +1035,69 @@ PRIVATE int setup_prdt(struct port_state *ps, endpoint_t endpt,
* used for padding as appropriate. Return the number of PRD entries,
* or a negative error code.
*/
vir_bytes bytes, trail;
phys_bytes phys;
int i, r, nr_prds = 0;
struct vumap_vir vvec[NR_PRDS];
size_t bytes, trail;
int i, r, pcount, nr_prds = 0;
if (lead > 0) {
/* Allocate a buffer for the data we don't want. */
if ((r = port_get_padbuf(ps, ps->sector_size)) != OK)
return r;
prdt[nr_prds].prd_phys = ps->pad_phys;
prdt[nr_prds].prd_size = lead;
prdt[nr_prds].vp_addr = ps->pad_phys;
prdt[nr_prds].vp_size = lead;
nr_prds++;
}
/* The sum of lead, size, trail has to be sector-aligned. */
trail = (ps->sector_size - (lead + size)) % ps->sector_size;
/* Get the physical addresses of the given buffers. */
for (i = 0; i < nr_req && size > 0; i++) {
bytes = MIN(iovec[i].iov_size, size);
/* Get the physical address of the given buffer. */
if (endpt == SELF)
r = sys_umap(endpt, VM_D,
(vir_bytes) iovec[i].iov_grant, bytes, &phys);
vvec[i].vv_addr = (vir_bytes) iovec[i].iov_grant;
else
r = sys_umap(endpt, VM_GRANT, iovec[i].iov_grant,
bytes, &phys);
vvec[i].vv_grant = iovec[i].iov_grant;
if (r != OK) {
dprintf(V_ERR, ("%s: unable to map area from %d "
"(%d)\n", ahci_portname(ps), endpt, r));
vvec[i].vv_size = bytes;
size -= bytes;
}
pcount = i;
if ((r = sys_vumap(endpt, vvec, i, 0, write ? VUA_READ : VUA_WRITE,
&prdt[nr_prds], &pcount)) != OK) {
dprintf(V_ERR, ("%s: unable to map memory from %d (%d)\n",
ahci_portname(ps), endpt, r));
return r;
}
assert(pcount > 0 && pcount <= i);
/* Make sure all buffers are physically contiguous and word-aligned. */
for (i = 0; i < pcount; i++) {
if (vvec[i].vv_size != prdt[nr_prds].vp_size) {
dprintf(V_ERR, ("%s: non-contiguous memory from %d\n",
ahci_portname(ps), endpt));
return EINVAL;
}
if (phys & 1) {
if (prdt[nr_prds].vp_addr & 1) {
dprintf(V_ERR, ("%s: bad physical address from %d\n",
ahci_portname(ps), endpt));
return EINVAL;
}
assert(nr_prds < NR_PRDS);
prdt[nr_prds].prd_phys = phys;
prdt[nr_prds].prd_size = bytes;
nr_prds++;
size -= bytes;
}
if (trail > 0) {
assert(nr_prds < NR_PRDS);
prdt[nr_prds].prd_phys = ps->pad_phys + lead;
prdt[nr_prds].prd_size = trail;
prdt[nr_prds].vp_addr = ps->pad_phys + lead;
prdt[nr_prds].vp_size = trail;
nr_prds++;
}
@ -1154,7 +1166,8 @@ PRIVATE ssize_t port_transfer(struct port_state *ps, u64_t pos, u64_t eof,
}
/* Create a vector of physical addresses and sizes for the transfer. */
nr_prds = r = setup_prdt(ps, endpt, iovec, nr_req, size, lead, prdt);
nr_prds = r = setup_prdt(ps, endpt, iovec, nr_req, size, lead, write,
prdt);
if (r < 0) return r;

View file

@ -247,13 +247,10 @@ typedef struct {
u8_t cf_ctl; /* Control */
} cmd_fis_t;
/* Physical Region Descriptor (PRD). For internal use only;
/* Physical Region Descriptor (PRD). For internal and sys_vumap() use only;
* the contents of this structure are later converted to an actual PRD.
*/
typedef struct {
phys_bytes prd_phys;
vir_bytes prd_size;
} prd_t;
typedef struct vumap_phys prd_t;
/* These are from at_wini, as this driver is a drop-in replacement for at_wini.
* Practically speaking this is already the upper limit with 256 minor device

View file

@ -339,6 +339,7 @@ service ahci
{
system
UMAP # 14
VUMAP # 18
IRQCTL # 19
;
pci class