nova: map write_combined ds as dma able

This commit is contained in:
Alexander Boettcher 2013-01-25 16:30:09 +01:00 committed by Norman Feske
parent 1c2f76cd2a
commit ff062f24ff
7 changed files with 49 additions and 29 deletions

View File

@ -66,6 +66,8 @@ namespace Genode {
Nova::Rights(true, _rw, true)); Nova::Rights(true, _rw, true));
} }
bool write_combined() { return _write_combined; };
addr_t dst_addr() { return _dst_addr; } addr_t dst_addr() { return _dst_addr; }
}; };

View File

@ -463,6 +463,11 @@ namespace Nova {
*/ */
unsigned msg_words() { return items & 0xffffU; } unsigned msg_words() { return items & 0xffffU; }
/**
* Return current number of message items on UTCB
*/
unsigned msg_items() { return items >> 16; }
/** /**
* Append message-transfer item to message buffer * Append message-transfer item to message buffer
* *
@ -478,7 +483,7 @@ namespace Nova {
/* transfer items start at the end of the UTCB */ /* transfer items start at the end of the UTCB */
items += 1 << 16; items += 1 << 16;
Item *item = reinterpret_cast<Item *>(this); Item *item = reinterpret_cast<Item *>(this);
item += (PAGE_SIZE_BYTE / sizeof(struct Item)) - (items >> 16); item += (PAGE_SIZE_BYTE / sizeof(struct Item)) - msg_items();
/* check that there is enough space left on UTCB */ /* check that there is enough space left on UTCB */
if (msg + msg_words() >= reinterpret_cast<mword_t *>(item)) { if (msg + msg_words() >= reinterpret_cast<mword_t *>(item)) {

View File

@ -57,7 +57,8 @@ void Ipc_pager::set_reply_mapping(Mapping m)
{ {
Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb(); Nova::Utcb *utcb = (Nova::Utcb *)Thread_base::myself()->utcb();
utcb->set_msg_word(0); utcb->set_msg_word(0);
bool res = utcb->append_item(m.mem_crd(), m.dst_addr()); bool res = utcb->append_item(m.mem_crd(), m.dst_addr(), false, false,
false, m.write_combined());
/* one item ever fits on the UTCB */ /* one item ever fits on the UTCB */
(void)res; (void)res;
} }

View File

@ -45,11 +45,13 @@ static void echo_reply()
Nova::Crd snd_rcv(echo()->utcb()->msg[0]); Nova::Crd snd_rcv(echo()->utcb()->msg[0]);
Nova::mword_t offset = echo()->utcb()->msg[1]; Nova::mword_t offset = echo()->utcb()->msg[1];
bool kern_pd = echo()->utcb()->msg[2]; bool kern_pd = echo()->utcb()->msg[2];
bool dma_mem = echo()->utcb()->msg[3];
/* reset message transfer descriptor */ /* reset message transfer descriptor */
echo()->utcb()->set_msg_word(0); echo()->utcb()->set_msg_word(0);
/* append capability-range as message-transfer item */ /* append capability-range as message-transfer item */
bool res = echo()->utcb()->append_item(snd_rcv, offset, kern_pd); bool res = echo()->utcb()->append_item(snd_rcv, offset, kern_pd, false,
false, dma_mem);
/* set return code, 0 means failure */ /* set return code, 0 means failure */
echo()->utcb()->msg[0] = res; echo()->utcb()->msg[0] = res;

View File

@ -29,21 +29,23 @@ enum { verbose_local_map = false };
/** /**
* Establish a one-to-one mapping * Establish a mapping
* *
* \param utcb UTCB of the calling EC * \param utcb UTCB of the calling EC
* \param src_crd capability range descriptor of source * \param src_crd capability range descriptor of source
* resource to map locally * resource to map locally
* \param dst_crd capability range descriptor of mapping * \param dst_crd capability range descriptor of mapping
* target * target
* \param kern_pd Whether to map the items from the kernel or from core
* \param dma_mem Whether the memory is usable for DMA or not
* *
* This functions sends a mapping from the calling EC to the echo EC. * This functions sends a message from the calling EC to the echo EC.
* In order to successfully transfer the mapping, we have to open a * The calling EC opens a receive window and the echo EC creates a transfer
* corresponding receive window at the echo EC. We do this by poking * item of the message and replies. The kernel will map during the reply
* a receive-capability-range descriptor directly onto the echo UTCB. * from the echo EC to the calling EC.
*/ */
static int map_local(Nova::Utcb *utcb, Nova::Crd src_crd, Nova::Crd dst_crd, static int map_local(Nova::Utcb *utcb, Nova::Crd src_crd, Nova::Crd dst_crd,
bool kern_pd = false) bool kern_pd = false, bool dma_mem = false)
{ {
/* open receive window at current EC */ /* open receive window at current EC */
utcb->crd_rcv = dst_crd; utcb->crd_rcv = dst_crd;
@ -52,16 +54,18 @@ static int map_local(Nova::Utcb *utcb, Nova::Crd src_crd, Nova::Crd dst_crd,
utcb->msg[0] = src_crd.value(); utcb->msg[0] = src_crd.value();
utcb->msg[1] = 0; utcb->msg[1] = 0;
utcb->msg[2] = kern_pd; utcb->msg[2] = kern_pd;
utcb->set_msg_word(3); utcb->msg[3] = dma_mem;
utcb->set_msg_word(4);
/* establish the mapping via a portal traversal during reply phase */ /* establish the mapping via a portal traversal during reply phase */
Nova::uint8_t res = Nova::call(echo()->pt_sel()); Nova::uint8_t res = Nova::call(echo()->pt_sel());
if (res != Nova::NOVA_OK || utcb->msg_words() != 1 || !utcb->msg[0]) { if (res != Nova::NOVA_OK || utcb->msg_words() != 1 || !utcb->msg[0] ||
utcb->msg_items() != 1) {
PERR("Failure - map_local 0x%lx:%lu:%u->0x%lx:%lu:%u - call result=%x" PERR("Failure - map_local 0x%lx:%lu:%u->0x%lx:%lu:%u - call result=%x"
" utcb=%x:%lx !!! %p %u", " utcb=%x:%x:%lx !!! utcb=%p kern=%u",
src_crd.addr(), src_crd.order(), src_crd.type(), src_crd.addr(), src_crd.order(), src_crd.type(),
dst_crd.addr(), dst_crd.order(), dst_crd.type(), dst_crd.addr(), dst_crd.order(), dst_crd.type(), res,
res, utcb->msg_words(), utcb->msg[0], utcb, kern_pd); utcb->msg_items(), utcb->msg_words(), utcb->msg[0], utcb, kern_pd);
return res > 0 ? res : -1; return res > 0 ? res : -1;
} }
/* clear receive window */ /* clear receive window */
@ -74,12 +78,11 @@ static int map_local(Nova::Utcb *utcb, Nova::Crd src_crd, Nova::Crd dst_crd,
static inline int unmap_local(Nova::Crd crd, bool self = true) { static inline int unmap_local(Nova::Crd crd, bool self = true) {
return Nova::revoke(crd, self); } return Nova::revoke(crd, self); }
inline int inline int map_local_phys_to_virt(Nova::Utcb *utcb, Nova::Crd src,
map_local_phys_to_virt(Nova::Utcb *utcb, Nova::Crd src, Nova::Crd dst) { Nova::Crd dst) {
return map_local(utcb, src, dst, true); } return map_local(utcb, src, dst, true); }
inline int inline int map_local_one_to_one(Nova::Utcb *utcb, Nova::Crd crd) {
map_local_one_to_one(Nova::Utcb *utcb, Nova::Crd crd) {
return map_local(utcb, crd, crd, true); } return map_local(utcb, crd, crd, true); }
@ -95,7 +98,7 @@ inline int map_local(Nova::Utcb *utcb,
Genode::addr_t from_start, Genode::addr_t to_start, Genode::addr_t from_start, Genode::addr_t to_start,
Genode::size_t num_pages, Genode::size_t num_pages,
Nova::Rights const &permission, Nova::Rights const &permission,
bool kern_pd = false) bool kern_pd = false, bool dma_mem = false)
{ {
if (verbose_local_map) if (verbose_local_map)
Genode::printf("::map_local: from %lx to %lx, %zd pages from kernel %u\n", Genode::printf("::map_local: from %lx to %lx, %zd pages from kernel %u\n",
@ -146,7 +149,7 @@ inline int map_local(Nova::Utcb *utcb,
int const res = map_local(utcb, int const res = map_local(utcb,
Mem_crd((from_curr >> 12), order - get_page_size_log2(), permission), Mem_crd((from_curr >> 12), order - get_page_size_log2(), permission),
Mem_crd((to_curr >> 12), order - get_page_size_log2(), permission), Mem_crd((to_curr >> 12), order - get_page_size_log2(), permission),
kern_pd); kern_pd, dma_mem);
if (res) return res; if (res) return res;
/* advance offset by current flexpage size */ /* advance offset by current flexpage size */

View File

@ -51,10 +51,10 @@ addr_t Io_mem_session_component::_map_local(addr_t base, size_t size)
} }
/* map the dataspace's physical pages to local addresses */ /* map the dataspace's physical pages to local addresses */
const Nova::Rights rights(true, true, true); const Nova::Rights rights(true, true, false);
map_local((Nova::Utcb *)Thread_base::myself()->utcb(), int res = map_local((Nova::Utcb *)Thread_base::myself()->utcb(),
base, (addr_t)virt_addr, base, (addr_t)virt_addr,
page_rounded_size >> get_page_size_log2(), rights, true); page_rounded_size >> get_page_size_log2(), rights, true);
return (addr_t)virt_addr; return res ? 0 : (addr_t)virt_addr;
} }

View File

@ -86,10 +86,17 @@ void Ram_session_component::_clear_ds(Dataspace_component *ds)
page_rounded_size, ds->phys_addr(), virt_addr, Thread_base::myself()->utcb()); page_rounded_size, ds->phys_addr(), virt_addr, Thread_base::myself()->utcb());
/* map the dataspace's physical pages to local addresses */ /* map the dataspace's physical pages to local addresses */
const Nova::Rights rights(true, true, true); const Nova::Rights rights(true, ds->writable(), true);
map_local((Nova::Utcb *)Thread_base::myself()->utcb(), int res = map_local((Nova::Utcb *)Thread_base::myself()->utcb(),
ds->phys_addr(), (addr_t)virt_addr, ds->phys_addr(), (addr_t)virt_addr,
page_rounded_size >> get_page_size_log2(), rights, true); page_rounded_size >> get_page_size_log2(), rights,
true);
if (res) {
PERR("map failed - ram ds size=0x%8zx phys 0x%8lx, core-local 0x%8p\n",
page_rounded_size, ds->phys_addr(), virt_addr);
return;
}
memset(virt_addr, 0, page_rounded_size); memset(virt_addr, 0, page_rounded_size);