summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2016-09-21 00:35:26 +0200
committerRichard Braun <rbraun@sceen.net>2016-09-21 00:35:26 +0200
commit6923672268ae8e51e3cf303314fca196dc369e19 (patch)
tree1401fbb4ee3c6be84745dec814487d6d85920f02
parent39fb13e762817b814aa0fc6e49305b5c0fd0c083 (diff)
Update device drivers for highmem support
Unconditionally use bounce buffers for now. * linux/dev/glue/net.c (device_write): Unconditionally use a bounce buffer. * xen/block.c (device_write): Likewise. * xen/net.c: Include <device/ds_routines.h>. (device_write): Unconditionally use a bounce buffer.
-rw-r--r--linux/dev/glue/net.c63
-rw-r--r--xen/block.c49
-rw-r--r--xen/net.c49
3 files changed, 68 insertions, 93 deletions
diff --git a/linux/dev/glue/net.c b/linux/dev/glue/net.c
index 15732737..6b9cadd5 100644
--- a/linux/dev/glue/net.c
+++ b/linux/dev/glue/net.c
@@ -428,62 +428,43 @@ device_write (void *d, ipc_port_t reply_port,
int *bytes_written)
{
unsigned char *p;
- int i, amt, skblen, s;
+ int i, s;
vm_map_copy_t copy = (vm_map_copy_t) data;
+ char *map_data;
+ vm_offset_t map_addr;
+ vm_size_t map_size;
struct net_data *nd = d;
struct linux_device *dev = nd->dev;
struct sk_buff *skb;
+ kern_return_t kr;
if (count == 0 || count > dev->mtu + dev->hard_header_len)
return D_INVALID_SIZE;
/* Allocate a sk_buff. */
- amt = PAGE_SIZE - (copy->offset & PAGE_MASK);
- skblen = (amt >= count) ? 0 : count;
- skb = dev_alloc_skb (skblen);
+ skb = dev_alloc_skb (count);
if (!skb)
return D_NO_MEMORY;
- /* Copy user data. This is only required if it spans multiple pages. */
- if (skblen == 0)
- {
- assert (copy->cpy_npages == 1);
-
- skb->copy = copy;
- skb->data = ((void *) phystokv(copy->cpy_page_list[0]->phys_addr)
- + (copy->offset & PAGE_MASK));
- skb->len = count;
- skb->head = skb->data;
- skb->tail = skb->data + skb->len;
- skb->end = skb->tail;
- }
- else
- {
- skb->len = skblen;
- skb->tail = skb->data + skblen;
- skb->end = skb->tail;
-
- memcpy (skb->data,
- ((void *) phystokv(copy->cpy_page_list[0]->phys_addr)
- + (copy->offset & PAGE_MASK)),
- amt);
- count -= amt;
- p = skb->data + amt;
- for (i = 1; count > 0 && i < copy->cpy_npages; i++)
- {
- amt = PAGE_SIZE;
- if (amt > count)
- amt = count;
- memcpy (p, (void *) phystokv(copy->cpy_page_list[i]->phys_addr), amt);
- count -= amt;
- p += amt;
- }
+ /* Map user data. */
+ kr = kmem_io_map_copyout(device_io_map, (vm_offset_t *)&map_data,
+ &map_addr, &map_size, copy, count);
- assert (count == 0);
+ if (kr) {
+ dev_kfree_skb (skb, FREE_WRITE);
+ return D_NO_MEMORY;
+ }
- vm_map_copy_discard (copy);
- }
+ /* XXX The underlying physical pages of the mapping could be highmem,
+ for which drivers require the use of a bounce buffer. */
+ memcpy (skb->data, map_data, count);
+ kmem_io_map_deallocate (device_io_map, map_addr, map_size);
+ vm_map_copy_discard (copy);
+ skb->len = count;
+ skb->head = skb->data;
+ skb->tail = skb->data + skb->len;
+ skb->end = skb->tail;
skb->dev = dev;
skb->reply = reply_port;
skb->reply_type = reply_port_type;
diff --git a/xen/block.c b/xen/block.c
index dc922348..25685982 100644
--- a/xen/block.c
+++ b/xen/block.c
@@ -568,7 +568,10 @@ device_write(void *d, ipc_port_t reply_port,
{
io_return_t err = 0;
vm_map_copy_t copy = (vm_map_copy_t) data;
- vm_offset_t aligned_buffer = 0;
+ vm_offset_t buffer = 0;
+ char *map_data;
+ vm_offset_t map_addr;
+ vm_size_t map_size;
unsigned copy_npages = atop(round_page(count));
vm_offset_t phys_addrs[copy_npages];
struct block_data *bd = d;
@@ -576,6 +579,7 @@ device_write(void *d, ipc_port_t reply_port,
grant_ref_t gref[BLKIF_MAX_SEGMENTS_PER_REQUEST];
unsigned reqn, size;
unsigned i, nbpages, j;
+ kern_return_t kr;
if (!(bd->mode & D_WRITE))
return D_READ_ONLY;
@@ -591,31 +595,24 @@ device_write(void *d, ipc_port_t reply_port,
if (count > copy->size)
return D_INVALID_SIZE;
- if (copy->type != VM_MAP_COPY_PAGE_LIST || copy->offset & PAGE_MASK) {
- /* Unaligned write. Has to copy data before passing it to the backend. */
- kern_return_t kr;
- vm_offset_t buffer;
-
- kr = kmem_alloc(device_io_map, &aligned_buffer, count);
- if (kr != KERN_SUCCESS)
- return kr;
-
- kr = vm_map_copyout(device_io_map, &buffer, vm_map_copy_copy(copy));
- if (kr != KERN_SUCCESS) {
- kmem_free(device_io_map, aligned_buffer, count);
- return kr;
- }
-
- memcpy((void*) aligned_buffer, (void*) buffer, count);
+ /* XXX The underlying physical pages of the mapping could be highmem,
+ for which drivers require the use of a bounce buffer. */
+ kr = kmem_alloc(device_io_map, &buffer, count);
+ if (kr != KERN_SUCCESS)
+ return kr;
+
+ kr = kmem_io_map_copyout(device_io_map, (vm_offset_t *)&map_data,
+ &map_addr, &map_size, copy, count);
+ if (kr != KERN_SUCCESS) {
+ kmem_free(device_io_map, buffer, count);
+ return kr;
+ }
- vm_deallocate (device_io_map, buffer, count);
+ memcpy((void *)buffer, map_data, count);
+ kmem_io_map_deallocate(device_io_map, map_addr, map_size);
- for (i = 0; i < copy_npages; i++)
- phys_addrs[i] = kvtophys(aligned_buffer + ptoa(i));
- } else {
- for (i = 0; i < copy_npages; i++)
- phys_addrs[i] = copy->cpy_page_list[i]->phys_addr;
- }
+ for (i = 0; i < copy_npages; i++)
+ phys_addrs[i] = kvtophys(buffer + ptoa(i));
for (i=0; i<copy_npages; i+=nbpages) {
@@ -674,8 +671,8 @@ device_write(void *d, ipc_port_t reply_port,
}
}
- if (aligned_buffer)
- kmem_free(device_io_map, aligned_buffer, count);
+ if (buffer)
+ kmem_free(device_io_map, buffer, count);
vm_map_copy_discard (copy);
diff --git a/xen/net.c b/xen/net.c
index 296035db..11121387 100644
--- a/xen/net.c
+++ b/xen/net.c
@@ -29,6 +29,7 @@
#include <device/net_io.h>
#include <device/device_reply.user.h>
#include <device/device_emul.h>
+#include <device/ds_routines.h>
#include <intel/pmap.h>
#include <xen/public/io/netif.h>
#include <xen/public/memory.h>
@@ -601,9 +602,11 @@ device_write(void *d, ipc_port_t reply_port,
struct ifnet *ifp = &nd->ifnet;
netif_tx_request_t *req;
unsigned reqn;
- vm_offset_t offset;
- vm_page_t m;
- vm_size_t size;
+ vm_offset_t buffer;
+ char *map_data;
+ vm_offset_t map_addr;
+ vm_size_t map_size;
+ kern_return_t kr;
/* The maximum that we can handle. */
assert(ifp->if_header_size + ifp->if_mtu <= PAGE_SIZE);
@@ -617,26 +620,21 @@ device_write(void *d, ipc_port_t reply_port,
assert(copy->cpy_npages <= 2);
assert(copy->cpy_npages >= 1);
- offset = copy->offset & PAGE_MASK;
- if (paranoia || copy->cpy_npages == 2) {
- /* have to copy :/ */
- while ((m = vm_page_grab()) == 0)
- VM_PAGE_WAIT (0);
- assert (! m->active && ! m->inactive);
- m->busy = TRUE;
+ kr = kmem_alloc(device_io_map, &buffer, count);
- if (copy->cpy_npages == 1)
- size = count;
- else
- size = PAGE_SIZE - offset;
+ if (kr != KERN_SUCCESS)
+ return kr;
+
+ kr = kmem_io_map_copyout(device_io_map, (vm_offset_t *)&map_data,
+ &map_addr, &map_size, copy, count);
- memcpy((void*)phystokv(m->phys_addr), (void*)phystokv(copy->cpy_page_list[0]->phys_addr + offset), size);
- if (copy->cpy_npages == 2)
- memcpy((void*)phystokv(m->phys_addr + size), (void*)phystokv(copy->cpy_page_list[1]->phys_addr), count - size);
+ if (kr != KERN_SUCCESS) {
+ kmem_free(device_io_map, buffer, count);
+ return kr;
+ }
- offset = 0;
- } else
- m = copy->cpy_page_list[0];
+ memcpy((void *)buffer, map_data, count);
+ kmem_io_map_deallocate(device_io_map, map_addr, map_size);
/* allocate a request */
spl_t spl = splimp();
@@ -653,8 +651,8 @@ device_write(void *d, ipc_port_t reply_port,
(void) splx(spl);
req = RING_GET_REQUEST(&nd->tx, reqn);
- req->gref = gref = hyp_grant_give(nd->domid, atop(m->phys_addr), 1);
- req->offset = offset;
+ req->gref = gref = hyp_grant_give(nd->domid, atop(kvtophys(buffer)), 1);
+ req->offset = 0;
req->flags = 0;
req->id = gref;
req->size = count;
@@ -685,11 +683,11 @@ device_write(void *d, ipc_port_t reply_port,
/* Suitable for Ethernet only. */
header = (struct ether_header *) (net_kmsg (kmsg)->header);
packet = (struct packet_header *) (net_kmsg (kmsg)->packet);
- memcpy (header, (void*)phystokv(m->phys_addr + offset), sizeof (struct ether_header));
+ memcpy (header, (void*)buffer, sizeof (struct ether_header));
/* packet is prefixed with a struct packet_header,
see include/device/net_status.h. */
- memcpy (packet + 1, (void*)phystokv(m->phys_addr + offset + sizeof (struct ether_header)),
+ memcpy (packet + 1, (void*)buffer + sizeof (struct ether_header),
count - sizeof (struct ether_header));
packet->length = count - sizeof (struct ether_header)
+ sizeof (struct packet_header);
@@ -702,8 +700,7 @@ device_write(void *d, ipc_port_t reply_port,
}
}
- if (paranoia || copy->cpy_npages == 2)
- VM_PAGE_FREE(m);
+ kmem_free(device_io_map, buffer, count);
vm_map_copy_discard (copy);