mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
Merged.
This commit is contained in:
commit
3f962c0f21
43 files changed
+2069
-5527
No files matched your search
@@ -111,13 +111,6 @@ config XEN_NETDEV_FRONTEND
|
||||
dedicated device-driver domain, or your master control domain
|
||||
(domain 0), then you almost certainly want to say Y here.
|
||||
|
||||
config XEN_NETDEV_GRANT
|
||||
bool "Grant table substrate for network drivers (DANGEROUS)"
|
||||
default n
|
||||
help
|
||||
This introduces the use of grant tables as a data exhange mechanism
|
||||
between the frontend and backend network drivers.
|
||||
|
||||
config XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER
|
||||
bool "Pipelined transmitter (DANGEROUS)"
|
||||
depends on XEN_NETDEV_FRONTEND
|
||||
|
||||
@@ -19,7 +19,6 @@ CONFIG_XEN_NETDEV_BACKEND=y
|
||||
# CONFIG_XEN_TPMDEV_BACKEND is not set
|
||||
CONFIG_XEN_BLKDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_GRANT=y
|
||||
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
|
||||
# CONFIG_XEN_BLKDEV_TAP is not set
|
||||
# CONFIG_XEN_SHADOW_MODE is not set
|
||||
|
||||
@@ -19,7 +19,6 @@ CONFIG_XEN_NETDEV_BACKEND=y
|
||||
# CONFIG_XEN_TPMDEV_BACKEND is not set
|
||||
CONFIG_XEN_BLKDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_GRANT=y
|
||||
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
|
||||
# CONFIG_XEN_BLKDEV_TAP is not set
|
||||
# CONFIG_XEN_SHADOW_MODE is not set
|
||||
|
||||
@@ -16,7 +16,6 @@ CONFIG_NO_IDLE_HZ=y
|
||||
# CONFIG_XEN_TPMDEV_BACKEND is not set
|
||||
CONFIG_XEN_BLKDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_GRANT=y
|
||||
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
|
||||
# CONFIG_XEN_BLKDEV_TAP is not set
|
||||
# CONFIG_XEN_SHADOW_MODE is not set
|
||||
|
||||
@@ -16,7 +16,6 @@ CONFIG_NO_IDLE_HZ=y
|
||||
# CONFIG_XEN_TPMDEV_BACKEND is not set
|
||||
CONFIG_XEN_BLKDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_GRANT=y
|
||||
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
|
||||
# CONFIG_XEN_BLKDEV_TAP is not set
|
||||
# CONFIG_XEN_SHADOW_MODE is not set
|
||||
|
||||
@@ -19,7 +19,6 @@ CONFIG_XEN_NETDEV_BACKEND=y
|
||||
# CONFIG_XEN_TPMDEV_BACKEND is not set
|
||||
CONFIG_XEN_BLKDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_GRANT=y
|
||||
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
|
||||
# CONFIG_XEN_BLKDEV_TAP is not set
|
||||
# CONFIG_XEN_SHADOW_MODE is not set
|
||||
|
||||
@@ -19,7 +19,6 @@ CONFIG_XEN_NETDEV_BACKEND=y
|
||||
# CONFIG_XEN_TPMDEV_BACKEND is not set
|
||||
CONFIG_XEN_BLKDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_FRONTEND=y
|
||||
CONFIG_XEN_NETDEV_GRANT=y
|
||||
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
|
||||
# CONFIG_XEN_BLKDEV_TAP is not set
|
||||
# CONFIG_XEN_SHADOW_MODE is not set
|
||||
|
||||
@@ -28,12 +28,12 @@
|
||||
#define BATCH_PER_DOMAIN 16
|
||||
|
||||
static unsigned long mmap_vstart;
|
||||
#define MMAP_PAGES \
|
||||
(MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
|
||||
#define MMAP_VADDR(_req,_seg) \
|
||||
(mmap_vstart + \
|
||||
((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE) + \
|
||||
((_seg) * PAGE_SIZE))
|
||||
#define MMAP_PAGES \
|
||||
(MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
|
||||
#define MMAP_VADDR(_req,_seg) \
|
||||
(mmap_vstart + \
|
||||
((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE) + \
|
||||
((_seg) * PAGE_SIZE))
|
||||
|
||||
/*
|
||||
* Each outstanding request that we've passed to the lower device layers has a
|
||||
@@ -42,12 +42,12 @@ static unsigned long mmap_vstart;
|
||||
* response queued for it, with the saved 'id' passed back.
|
||||
*/
|
||||
typedef struct {
|
||||
blkif_t *blkif;
|
||||
unsigned long id;
|
||||
int nr_pages;
|
||||
atomic_t pendcnt;
|
||||
unsigned short operation;
|
||||
int status;
|
||||
blkif_t *blkif;
|
||||
unsigned long id;
|
||||
int nr_pages;
|
||||
atomic_t pendcnt;
|
||||
unsigned short operation;
|
||||
int status;
|
||||
} pending_req_t;
|
||||
|
||||
/*
|
||||
@@ -68,14 +68,13 @@ static PEND_RING_IDX pending_prod, pending_cons;
|
||||
static request_queue_t *plugged_queue;
|
||||
static inline void flush_plugged_queue(void)
|
||||
{
|
||||
request_queue_t *q = plugged_queue;
|
||||
if ( q != NULL )
|
||||
{
|
||||
if ( q->unplug_fn != NULL )
|
||||
q->unplug_fn(q);
|
||||
blk_put_queue(q);
|
||||
plugged_queue = NULL;
|
||||
}
|
||||
request_queue_t *q = plugged_queue;
|
||||
if (q != NULL) {
|
||||
if ( q->unplug_fn != NULL )
|
||||
q->unplug_fn(q);
|
||||
blk_put_queue(q);
|
||||
plugged_queue = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* When using grant tables to map a frame for device access then the
|
||||
@@ -106,24 +105,23 @@ static void make_response(blkif_t *blkif, unsigned long id,
|
||||
|
||||
static void fast_flush_area(int idx, int nr_pages)
|
||||
{
|
||||
struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
unsigned int i, invcount = 0;
|
||||
u16 handle;
|
||||
struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
unsigned int i, invcount = 0;
|
||||
u16 handle;
|
||||
|
||||
for ( i = 0; i < nr_pages; i++ )
|
||||
{
|
||||
if ( BLKBACK_INVALID_HANDLE != ( handle = pending_handle(idx, i) ) )
|
||||
{
|
||||
unmap[i].host_addr = MMAP_VADDR(idx, i);
|
||||
unmap[i].dev_bus_addr = 0;
|
||||
unmap[i].handle = handle;
|
||||
pending_handle(idx, i) = BLKBACK_INVALID_HANDLE;
|
||||
invcount++;
|
||||
}
|
||||
}
|
||||
if ( unlikely(HYPERVISOR_grant_table_op(
|
||||
GNTTABOP_unmap_grant_ref, unmap, invcount)))
|
||||
BUG();
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
handle = pending_handle(idx, i);
|
||||
if (handle == BLKBACK_INVALID_HANDLE)
|
||||
continue;
|
||||
unmap[i].host_addr = MMAP_VADDR(idx, i);
|
||||
unmap[i].dev_bus_addr = 0;
|
||||
unmap[i].handle = handle;
|
||||
pending_handle(idx, i) = BLKBACK_INVALID_HANDLE;
|
||||
invcount++;
|
||||
}
|
||||
|
||||
BUG_ON(HYPERVISOR_grant_table_op(
|
||||
GNTTABOP_unmap_grant_ref, unmap, invcount));
|
||||
}
|
||||
|
||||
|
||||
@@ -136,34 +134,38 @@ static spinlock_t blkio_schedule_list_lock;
|
||||
|
||||
static int __on_blkdev_list(blkif_t *blkif)
|
||||
{
|
||||
return blkif->blkdev_list.next != NULL;
|
||||
return blkif->blkdev_list.next != NULL;
|
||||
}
|
||||
|
||||
static void remove_from_blkdev_list(blkif_t *blkif)
|
||||
{
|
||||
unsigned long flags;
|
||||
if ( !__on_blkdev_list(blkif) ) return;
|
||||
spin_lock_irqsave(&blkio_schedule_list_lock, flags);
|
||||
if ( __on_blkdev_list(blkif) )
|
||||
{
|
||||
list_del(&blkif->blkdev_list);
|
||||
blkif->blkdev_list.next = NULL;
|
||||
blkif_put(blkif);
|
||||
}
|
||||
spin_unlock_irqrestore(&blkio_schedule_list_lock, flags);
|
||||
unsigned long flags;
|
||||
|
||||
if (!__on_blkdev_list(blkif))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&blkio_schedule_list_lock, flags);
|
||||
if (__on_blkdev_list(blkif)) {
|
||||
list_del(&blkif->blkdev_list);
|
||||
blkif->blkdev_list.next = NULL;
|
||||
blkif_put(blkif);
|
||||
}
|
||||
spin_unlock_irqrestore(&blkio_schedule_list_lock, flags);
|
||||
}
|
||||
|
||||
static void add_to_blkdev_list_tail(blkif_t *blkif)
|
||||
{
|
||||
unsigned long flags;
|
||||
if ( __on_blkdev_list(blkif) ) return;
|
||||
spin_lock_irqsave(&blkio_schedule_list_lock, flags);
|
||||
if ( !__on_blkdev_list(blkif) && (blkif->status == CONNECTED) )
|
||||
{
|
||||
list_add_tail(&blkif->blkdev_list, &blkio_schedule_list);
|
||||
blkif_get(blkif);
|
||||
}
|
||||
spin_unlock_irqrestore(&blkio_schedule_list_lock, flags);
|
||||
unsigned long flags;
|
||||
|
||||
if (__on_blkdev_list(blkif))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&blkio_schedule_list_lock, flags);
|
||||
if (!__on_blkdev_list(blkif) && (blkif->status == CONNECTED)) {
|
||||
list_add_tail(&blkif->blkdev_list, &blkio_schedule_list);
|
||||
blkif_get(blkif);
|
||||
}
|
||||
spin_unlock_irqrestore(&blkio_schedule_list_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -175,54 +177,53 @@ static DECLARE_WAIT_QUEUE_HEAD(blkio_schedule_wait);
|
||||
|
||||
static int blkio_schedule(void *arg)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wq, current);
|
||||
DECLARE_WAITQUEUE(wq, current);
|
||||
|
||||
blkif_t *blkif;
|
||||
struct list_head *ent;
|
||||
blkif_t *blkif;
|
||||
struct list_head *ent;
|
||||
|
||||
daemonize("xenblkd");
|
||||
daemonize("xenblkd");
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
/* Wait for work to do. */
|
||||
add_wait_queue(&blkio_schedule_wait, &wq);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if ( (NR_PENDING_REQS == MAX_PENDING_REQS) ||
|
||||
list_empty(&blkio_schedule_list) )
|
||||
schedule();
|
||||
__set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&blkio_schedule_wait, &wq);
|
||||
for (;;) {
|
||||
/* Wait for work to do. */
|
||||
add_wait_queue(&blkio_schedule_wait, &wq);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if ( (NR_PENDING_REQS == MAX_PENDING_REQS) ||
|
||||
list_empty(&blkio_schedule_list) )
|
||||
schedule();
|
||||
__set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&blkio_schedule_wait, &wq);
|
||||
|
||||
/* Queue up a batch of requests. */
|
||||
while ( (NR_PENDING_REQS < MAX_PENDING_REQS) &&
|
||||
!list_empty(&blkio_schedule_list) )
|
||||
{
|
||||
ent = blkio_schedule_list.next;
|
||||
blkif = list_entry(ent, blkif_t, blkdev_list);
|
||||
blkif_get(blkif);
|
||||
remove_from_blkdev_list(blkif);
|
||||
if ( do_block_io_op(blkif, BATCH_PER_DOMAIN) )
|
||||
add_to_blkdev_list_tail(blkif);
|
||||
blkif_put(blkif);
|
||||
}
|
||||
/* Queue up a batch of requests. */
|
||||
while ((NR_PENDING_REQS < MAX_PENDING_REQS) &&
|
||||
!list_empty(&blkio_schedule_list)) {
|
||||
ent = blkio_schedule_list.next;
|
||||
blkif = list_entry(ent, blkif_t, blkdev_list);
|
||||
blkif_get(blkif);
|
||||
remove_from_blkdev_list(blkif);
|
||||
if (do_block_io_op(blkif, BATCH_PER_DOMAIN))
|
||||
add_to_blkdev_list_tail(blkif);
|
||||
blkif_put(blkif);
|
||||
}
|
||||
|
||||
/* Push the batch through to disc. */
|
||||
flush_plugged_queue();
|
||||
}
|
||||
/* Push the batch through to disc. */
|
||||
flush_plugged_queue();
|
||||
}
|
||||
}
|
||||
|
||||
static void maybe_trigger_blkio_schedule(void)
|
||||
{
|
||||
/*
|
||||
* Needed so that two processes, who together make the following predicate
|
||||
* true, don't both read stale values and evaluate the predicate
|
||||
* incorrectly. Incredibly unlikely to stall the scheduler on x86, but...
|
||||
*/
|
||||
smp_mb();
|
||||
/*
|
||||
* Needed so that two processes, which together make the following
|
||||
* predicate true, don't both read stale values and evaluate the
|
||||
* predicate incorrectly. Incredibly unlikely to stall the scheduler
|
||||
* on x86, but...
|
||||
*/
|
||||
smp_mb();
|
||||
|
||||
if ( (NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
|
||||
!list_empty(&blkio_schedule_list) )
|
||||
wake_up(&blkio_schedule_wait);
|
||||
if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
|
||||
!list_empty(&blkio_schedule_list))
|
||||
wake_up(&blkio_schedule_wait);
|
||||
}
|
||||
|
||||
|
||||
@@ -233,36 +234,34 @@ static void maybe_trigger_blkio_schedule(void)
|
||||
|
||||
static void __end_block_io_op(pending_req_t *pending_req, int uptodate)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long flags;
|
||||
|
||||
/* An error fails the entire request. */
|
||||
if ( !uptodate )
|
||||
{
|
||||
DPRINTK("Buffer not up-to-date at end of operation\n");
|
||||
pending_req->status = BLKIF_RSP_ERROR;
|
||||
}
|
||||
/* An error fails the entire request. */
|
||||
if (!uptodate) {
|
||||
DPRINTK("Buffer not up-to-date at end of operation\n");
|
||||
pending_req->status = BLKIF_RSP_ERROR;
|
||||
}
|
||||
|
||||
if ( atomic_dec_and_test(&pending_req->pendcnt) )
|
||||
{
|
||||
int pending_idx = pending_req - pending_reqs;
|
||||
fast_flush_area(pending_idx, pending_req->nr_pages);
|
||||
make_response(pending_req->blkif, pending_req->id,
|
||||
pending_req->operation, pending_req->status);
|
||||
blkif_put(pending_req->blkif);
|
||||
spin_lock_irqsave(&pend_prod_lock, flags);
|
||||
pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
|
||||
spin_unlock_irqrestore(&pend_prod_lock, flags);
|
||||
maybe_trigger_blkio_schedule();
|
||||
}
|
||||
if (atomic_dec_and_test(&pending_req->pendcnt)) {
|
||||
int pending_idx = pending_req - pending_reqs;
|
||||
fast_flush_area(pending_idx, pending_req->nr_pages);
|
||||
make_response(pending_req->blkif, pending_req->id,
|
||||
pending_req->operation, pending_req->status);
|
||||
blkif_put(pending_req->blkif);
|
||||
spin_lock_irqsave(&pend_prod_lock, flags);
|
||||
pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
|
||||
spin_unlock_irqrestore(&pend_prod_lock, flags);
|
||||
maybe_trigger_blkio_schedule();
|
||||
}
|
||||
}
|
||||
|
||||
static int end_block_io_op(struct bio *bio, unsigned int done, int error)
|
||||
{
|
||||
if ( bio->bi_size != 0 )
|
||||
return 1;
|
||||
__end_block_io_op(bio->bi_private, !error);
|
||||
bio_put(bio);
|
||||
return error;
|
||||
if (bio->bi_size != 0)
|
||||
return 1;
|
||||
__end_block_io_op(bio->bi_private, !error);
|
||||
bio_put(bio);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -272,10 +271,10 @@ static int end_block_io_op(struct bio *bio, unsigned int done, int error)
|
||||
|
||||
irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
blkif_t *blkif = dev_id;
|
||||
add_to_blkdev_list_tail(blkif);
|
||||
maybe_trigger_blkio_schedule();
|
||||
return IRQ_HANDLED;
|
||||
blkif_t *blkif = dev_id;
|
||||
add_to_blkdev_list_tail(blkif);
|
||||
maybe_trigger_blkio_schedule();
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
@@ -286,183 +285,174 @@ irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
|
||||
|
||||
static int do_block_io_op(blkif_t *blkif, int max_to_do)
|
||||
{
|
||||
blkif_back_ring_t *blk_ring = &blkif->blk_ring;
|
||||
blkif_request_t *req;
|
||||
RING_IDX i, rp;
|
||||
int more_to_do = 0;
|
||||
blkif_back_ring_t *blk_ring = &blkif->blk_ring;
|
||||
blkif_request_t *req;
|
||||
RING_IDX i, rp;
|
||||
int more_to_do = 0;
|
||||
|
||||
rp = blk_ring->sring->req_prod;
|
||||
rmb(); /* Ensure we see queued requests up to 'rp'. */
|
||||
rp = blk_ring->sring->req_prod;
|
||||
rmb(); /* Ensure we see queued requests up to 'rp'. */
|
||||
|
||||
for ( i = blk_ring->req_cons;
|
||||
(i != rp) && !RING_REQUEST_CONS_OVERFLOW(blk_ring, i);
|
||||
i++ )
|
||||
{
|
||||
if ( (max_to_do-- == 0) || (NR_PENDING_REQS == MAX_PENDING_REQS) )
|
||||
{
|
||||
more_to_do = 1;
|
||||
break;
|
||||
}
|
||||
for (i = blk_ring->req_cons;
|
||||
(i != rp) && !RING_REQUEST_CONS_OVERFLOW(blk_ring, i);
|
||||
i++) {
|
||||
if ((max_to_do-- == 0) ||
|
||||
(NR_PENDING_REQS == MAX_PENDING_REQS)) {
|
||||
more_to_do = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
req = RING_GET_REQUEST(blk_ring, i);
|
||||
switch ( req->operation )
|
||||
{
|
||||
case BLKIF_OP_READ:
|
||||
case BLKIF_OP_WRITE:
|
||||
dispatch_rw_block_io(blkif, req);
|
||||
break;
|
||||
req = RING_GET_REQUEST(blk_ring, i);
|
||||
switch (req->operation) {
|
||||
case BLKIF_OP_READ:
|
||||
case BLKIF_OP_WRITE:
|
||||
dispatch_rw_block_io(blkif, req);
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTK("error: unknown block io operation [%d]\n",
|
||||
req->operation);
|
||||
make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
DPRINTK("error: unknown block io operation [%d]\n",
|
||||
req->operation);
|
||||
make_response(blkif, req->id, req->operation,
|
||||
BLKIF_RSP_ERROR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
blk_ring->req_cons = i;
|
||||
return more_to_do;
|
||||
blk_ring->req_cons = i;
|
||||
return more_to_do;
|
||||
}
|
||||
|
||||
static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
|
||||
{
|
||||
extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]);
|
||||
int operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ;
|
||||
unsigned long fas = 0;
|
||||
int i, pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
|
||||
pending_req_t *pending_req;
|
||||
struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
struct phys_req preq;
|
||||
struct {
|
||||
unsigned long buf; unsigned int nsec;
|
||||
} seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
unsigned int nseg;
|
||||
struct bio *bio = NULL, *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
int nbio = 0;
|
||||
request_queue_t *q;
|
||||
extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]);
|
||||
int operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ;
|
||||
unsigned long fas = 0;
|
||||
int i, pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
|
||||
pending_req_t *pending_req;
|
||||
struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
struct phys_req preq;
|
||||
struct {
|
||||
unsigned long buf; unsigned int nsec;
|
||||
} seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
unsigned int nseg;
|
||||
struct bio *bio = NULL, *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
int nbio = 0;
|
||||
request_queue_t *q;
|
||||
|
||||
/* Check that number of segments is sane. */
|
||||
nseg = req->nr_segments;
|
||||
if ( unlikely(nseg == 0) ||
|
||||
unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST) )
|
||||
{
|
||||
DPRINTK("Bad number of segments in request (%d)\n", nseg);
|
||||
goto bad_descriptor;
|
||||
}
|
||||
/* Check that number of segments is sane. */
|
||||
nseg = req->nr_segments;
|
||||
if (unlikely(nseg == 0) ||
|
||||
unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
|
||||
DPRINTK("Bad number of segments in request (%d)\n", nseg);
|
||||
goto bad_descriptor;
|
||||
}
|
||||
|
||||
preq.dev = req->handle;
|
||||
preq.sector_number = req->sector_number;
|
||||
preq.nr_sects = 0;
|
||||
preq.dev = req->handle;
|
||||
preq.sector_number = req->sector_number;
|
||||
preq.nr_sects = 0;
|
||||
|
||||
for ( i = 0; i < nseg; i++ )
|
||||
{
|
||||
fas = req->frame_and_sects[i];
|
||||
seg[i].nsec = blkif_last_sect(fas) - blkif_first_sect(fas) + 1;
|
||||
for (i = 0; i < nseg; i++) {
|
||||
fas = req->frame_and_sects[i];
|
||||
seg[i].nsec = blkif_last_sect(fas) - blkif_first_sect(fas) + 1;
|
||||
|
||||
if ( seg[i].nsec <= 0 )
|
||||
goto bad_descriptor;
|
||||
preq.nr_sects += seg[i].nsec;
|
||||
if (seg[i].nsec <= 0)
|
||||
goto bad_descriptor;
|
||||
preq.nr_sects += seg[i].nsec;
|
||||
|
||||
map[i].host_addr = MMAP_VADDR(pending_idx, i);
|
||||
map[i].dom = blkif->domid;
|
||||
map[i].ref = blkif_gref_from_fas(fas);
|
||||
map[i].flags = GNTMAP_host_map;
|
||||
if ( operation == WRITE )
|
||||
map[i].flags |= GNTMAP_readonly;
|
||||
}
|
||||
map[i].host_addr = MMAP_VADDR(pending_idx, i);
|
||||
map[i].dom = blkif->domid;
|
||||
map[i].ref = blkif_gref_from_fas(fas);
|
||||
map[i].flags = GNTMAP_host_map;
|
||||
if ( operation == WRITE )
|
||||
map[i].flags |= GNTMAP_readonly;
|
||||
}
|
||||
|
||||
if ( unlikely(HYPERVISOR_grant_table_op(
|
||||
GNTTABOP_map_grant_ref, map, nseg)))
|
||||
BUG();
|
||||
BUG_ON(HYPERVISOR_grant_table_op(
|
||||
GNTTABOP_map_grant_ref, map, nseg));
|
||||
|
||||
for ( i = 0; i < nseg; i++ )
|
||||
{
|
||||
if ( unlikely(map[i].handle < 0) )
|
||||
{
|
||||
DPRINTK("invalid buffer -- could not remap it\n");
|
||||
fast_flush_area(pending_idx, nseg);
|
||||
goto bad_descriptor;
|
||||
}
|
||||
for (i = 0; i < nseg; i++) {
|
||||
if (unlikely(map[i].handle < 0)) {
|
||||
DPRINTK("invalid buffer -- could not remap it\n");
|
||||
fast_flush_area(pending_idx, nseg);
|
||||
goto bad_descriptor;
|
||||
}
|
||||
|
||||
phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] =
|
||||
FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT);
|
||||
phys_to_machine_mapping[__pa(MMAP_VADDR(
|
||||
pending_idx, i)) >> PAGE_SHIFT] =
|
||||
FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT);
|
||||
|
||||
pending_handle(pending_idx, i) = map[i].handle;
|
||||
}
|
||||
pending_handle(pending_idx, i) = map[i].handle;
|
||||
}
|
||||
|
||||
for ( i = 0; i < nseg; i++ )
|
||||
{
|
||||
fas = req->frame_and_sects[i];
|
||||
seg[i].buf = map[i].dev_bus_addr | (blkif_first_sect(fas) << 9);
|
||||
}
|
||||
for (i = 0; i < nseg; i++) {
|
||||
fas = req->frame_and_sects[i];
|
||||
seg[i].buf = map[i].dev_bus_addr |
|
||||
(blkif_first_sect(fas) << 9);
|
||||
}
|
||||
|
||||
if ( vbd_translate(&preq, blkif, operation) != 0 )
|
||||
{
|
||||
DPRINTK("access denied: %s of [%llu,%llu] on dev=%04x\n",
|
||||
operation == READ ? "read" : "write", preq.sector_number,
|
||||
preq.sector_number + preq.nr_sects, preq.dev);
|
||||
goto bad_descriptor;
|
||||
}
|
||||
if (vbd_translate(&preq, blkif, operation) != 0) {
|
||||
DPRINTK("access denied: %s of [%llu,%llu] on dev=%04x\n",
|
||||
operation == READ ? "read" : "write",
|
||||
preq.sector_number,
|
||||
preq.sector_number + preq.nr_sects, preq.dev);
|
||||
goto bad_descriptor;
|
||||
}
|
||||
|
||||
pending_req = &pending_reqs[pending_idx];
|
||||
pending_req->blkif = blkif;
|
||||
pending_req->id = req->id;
|
||||
pending_req->operation = operation;
|
||||
pending_req->status = BLKIF_RSP_OKAY;
|
||||
pending_req->nr_pages = nseg;
|
||||
pending_req = &pending_reqs[pending_idx];
|
||||
pending_req->blkif = blkif;
|
||||
pending_req->id = req->id;
|
||||
pending_req->operation = operation;
|
||||
pending_req->status = BLKIF_RSP_OKAY;
|
||||
pending_req->nr_pages = nseg;
|
||||
|
||||
for ( i = 0; i < nseg; i++ )
|
||||
{
|
||||
if ( ((int)preq.sector_number|(int)seg[i].nsec) &
|
||||
((bdev_hardsect_size(preq.bdev) >> 9) - 1) )
|
||||
{
|
||||
DPRINTK("Misaligned I/O request from domain %d", blkif->domid);
|
||||
goto cleanup_and_fail;
|
||||
}
|
||||
for (i = 0; i < nseg; i++) {
|
||||
if (((int)preq.sector_number|(int)seg[i].nsec) &
|
||||
((bdev_hardsect_size(preq.bdev) >> 9) - 1)) {
|
||||
DPRINTK("Misaligned I/O request from domain %d",
|
||||
blkif->domid);
|
||||
goto cleanup_and_fail;
|
||||
}
|
||||
|
||||
while ( (bio == NULL) ||
|
||||
(bio_add_page(bio,
|
||||
virt_to_page(MMAP_VADDR(pending_idx, i)),
|
||||
seg[i].nsec << 9,
|
||||
seg[i].buf & ~PAGE_MASK) == 0) )
|
||||
{
|
||||
bio = biolist[nbio++] = bio_alloc(GFP_KERNEL, nseg-i);
|
||||
if ( unlikely(bio == NULL) )
|
||||
{
|
||||
cleanup_and_fail:
|
||||
for ( i = 0; i < (nbio-1); i++ )
|
||||
bio_put(biolist[i]);
|
||||
fast_flush_area(pending_idx, nseg);
|
||||
goto bad_descriptor;
|
||||
}
|
||||
while ((bio == NULL) ||
|
||||
(bio_add_page(bio,
|
||||
virt_to_page(MMAP_VADDR(pending_idx, i)),
|
||||
seg[i].nsec << 9,
|
||||
seg[i].buf & ~PAGE_MASK) == 0)) {
|
||||
bio = biolist[nbio++] = bio_alloc(GFP_KERNEL, nseg-i);
|
||||
if (unlikely(bio == NULL)) {
|
||||
cleanup_and_fail:
|
||||
for (i = 0; i < (nbio-1); i++)
|
||||
bio_put(biolist[i]);
|
||||
fast_flush_area(pending_idx, nseg);
|
||||
goto bad_descriptor;
|
||||
}
|
||||
|
||||
bio->bi_bdev = preq.bdev;
|
||||
bio->bi_private = pending_req;
|
||||
bio->bi_end_io = end_block_io_op;
|
||||
bio->bi_sector = preq.sector_number;
|
||||
}
|
||||
bio->bi_bdev = preq.bdev;
|
||||
bio->bi_private = pending_req;
|
||||
bio->bi_end_io = end_block_io_op;
|
||||
bio->bi_sector = preq.sector_number;
|
||||
}
|
||||
|
||||
preq.sector_number += seg[i].nsec;
|
||||
}
|
||||
preq.sector_number += seg[i].nsec;
|
||||
}
|
||||
|
||||
if ( (q = bdev_get_queue(bio->bi_bdev)) != plugged_queue )
|
||||
{
|
||||
flush_plugged_queue();
|
||||
blk_get_queue(q);
|
||||
plugged_queue = q;
|
||||
}
|
||||
if ((q = bdev_get_queue(bio->bi_bdev)) != plugged_queue) {
|
||||
flush_plugged_queue();
|
||||
blk_get_queue(q);
|
||||
plugged_queue = q;
|
||||
}
|
||||
|
||||
atomic_set(&pending_req->pendcnt, nbio);
|
||||
pending_cons++;
|
||||
blkif_get(blkif);
|
||||
atomic_set(&pending_req->pendcnt, nbio);
|
||||
pending_cons++;
|
||||
blkif_get(blkif);
|
||||
|
||||
for ( i = 0; i < nbio; i++ )
|
||||
submit_bio(operation, biolist[i]);
|
||||
for (i = 0; i < nbio; i++)
|
||||
submit_bio(operation, biolist[i]);
|
||||
|
||||
return;
|
||||
return;
|
||||
|
||||
bad_descriptor:
|
||||
make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
|
||||
make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
|
||||
}
|
||||
|
||||
|
||||
@@ -475,66 +465,71 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
|
||||
static void make_response(blkif_t *blkif, unsigned long id,
|
||||
unsigned short op, int st)
|
||||
{
|
||||
blkif_response_t *resp;
|
||||
unsigned long flags;
|
||||
blkif_back_ring_t *blk_ring = &blkif->blk_ring;
|
||||
blkif_response_t *resp;
|
||||
unsigned long flags;
|
||||
blkif_back_ring_t *blk_ring = &blkif->blk_ring;
|
||||
|
||||
/* Place on the response ring for the relevant domain. */
|
||||
spin_lock_irqsave(&blkif->blk_ring_lock, flags);
|
||||
resp = RING_GET_RESPONSE(blk_ring, blk_ring->rsp_prod_pvt);
|
||||
resp->id = id;
|
||||
resp->operation = op;
|
||||
resp->status = st;
|
||||
wmb(); /* Ensure other side can see the response fields. */
|
||||
blk_ring->rsp_prod_pvt++;
|
||||
RING_PUSH_RESPONSES(blk_ring);
|
||||
spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
|
||||
/* Place on the response ring for the relevant domain. */
|
||||
spin_lock_irqsave(&blkif->blk_ring_lock, flags);
|
||||
resp = RING_GET_RESPONSE(blk_ring, blk_ring->rsp_prod_pvt);
|
||||
resp->id = id;
|
||||
resp->operation = op;
|
||||
resp->status = st;
|
||||
wmb(); /* Ensure other side can see the response fields. */
|
||||
blk_ring->rsp_prod_pvt++;
|
||||
RING_PUSH_RESPONSES(blk_ring);
|
||||
spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
|
||||
|
||||
/* Kick the relevant domain. */
|
||||
notify_via_evtchn(blkif->evtchn);
|
||||
/* Kick the relevant domain. */
|
||||
notify_via_evtchn(blkif->evtchn);
|
||||
}
|
||||
|
||||
void blkif_deschedule(blkif_t *blkif)
|
||||
{
|
||||
remove_from_blkdev_list(blkif);
|
||||
remove_from_blkdev_list(blkif);
|
||||
}
|
||||
|
||||
static int __init blkif_init(void)
|
||||
{
|
||||
int i;
|
||||
struct page *page;
|
||||
int i;
|
||||
struct page *page;
|
||||
|
||||
if ( !(xen_start_info->flags & SIF_INITDOMAIN) &&
|
||||
!(xen_start_info->flags & SIF_BLK_BE_DOMAIN) )
|
||||
return 0;
|
||||
if (!(xen_start_info->flags & SIF_INITDOMAIN) &&
|
||||
!(xen_start_info->flags & SIF_BLK_BE_DOMAIN))
|
||||
return 0;
|
||||
|
||||
blkif_interface_init();
|
||||
blkif_interface_init();
|
||||
|
||||
page = balloon_alloc_empty_page_range(MMAP_PAGES);
|
||||
BUG_ON(page == NULL);
|
||||
mmap_vstart = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
|
||||
page = balloon_alloc_empty_page_range(MMAP_PAGES);
|
||||
BUG_ON(page == NULL);
|
||||
mmap_vstart = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
|
||||
|
||||
pending_cons = 0;
|
||||
pending_prod = MAX_PENDING_REQS;
|
||||
memset(pending_reqs, 0, sizeof(pending_reqs));
|
||||
for ( i = 0; i < MAX_PENDING_REQS; i++ )
|
||||
pending_ring[i] = i;
|
||||
pending_cons = 0;
|
||||
pending_prod = MAX_PENDING_REQS;
|
||||
memset(pending_reqs, 0, sizeof(pending_reqs));
|
||||
for (i = 0; i < MAX_PENDING_REQS; i++)
|
||||
pending_ring[i] = i;
|
||||
|
||||
spin_lock_init(&blkio_schedule_list_lock);
|
||||
INIT_LIST_HEAD(&blkio_schedule_list);
|
||||
spin_lock_init(&blkio_schedule_list_lock);
|
||||
INIT_LIST_HEAD(&blkio_schedule_list);
|
||||
|
||||
if ( kernel_thread(blkio_schedule, 0, CLONE_FS | CLONE_FILES) < 0 )
|
||||
BUG();
|
||||
BUG_ON(kernel_thread(blkio_schedule, 0, CLONE_FS | CLONE_FILES) < 0);
|
||||
|
||||
blkif_xenbus_init();
|
||||
blkif_xenbus_init();
|
||||
|
||||
memset( pending_grant_handles, BLKBACK_INVALID_HANDLE, MMAP_PAGES );
|
||||
memset(pending_grant_handles, BLKBACK_INVALID_HANDLE, MMAP_PAGES);
|
||||
|
||||
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
|
||||
printk(KERN_ALERT "NOTE: Blkif backend is running with tap support on!\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__initcall(blkif_init);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -31,39 +31,39 @@
|
||||
#endif
|
||||
|
||||
struct vbd {
|
||||
blkif_vdev_t handle; /* what the domain refers to this vbd as */
|
||||
unsigned char readonly; /* Non-zero -> read-only */
|
||||
unsigned char type; /* VDISK_xxx */
|
||||
u32 pdevice; /* phys device that this vbd maps to */
|
||||
struct block_device *bdev;
|
||||
blkif_vdev_t handle; /* what the domain refers to this vbd as */
|
||||
unsigned char readonly; /* Non-zero -> read-only */
|
||||
unsigned char type; /* VDISK_xxx */
|
||||
u32 pdevice; /* phys device that this vbd maps to */
|
||||
struct block_device *bdev;
|
||||
};
|
||||
|
||||
typedef struct blkif_st {
|
||||
/* Unique identifier for this interface. */
|
||||
domid_t domid;
|
||||
unsigned int handle;
|
||||
/* Physical parameters of the comms window. */
|
||||
unsigned int evtchn;
|
||||
unsigned int remote_evtchn;
|
||||
/* Comms information. */
|
||||
blkif_back_ring_t blk_ring;
|
||||
struct vm_struct *blk_ring_area;
|
||||
/* VBDs attached to this interface. */
|
||||
struct vbd vbd;
|
||||
/* Private fields. */
|
||||
enum { DISCONNECTED, CONNECTED } status;
|
||||
/* Unique identifier for this interface. */
|
||||
domid_t domid;
|
||||
unsigned int handle;
|
||||
/* Physical parameters of the comms window. */
|
||||
unsigned int evtchn;
|
||||
unsigned int remote_evtchn;
|
||||
/* Comms information. */
|
||||
blkif_back_ring_t blk_ring;
|
||||
struct vm_struct *blk_ring_area;
|
||||
/* VBDs attached to this interface. */
|
||||
struct vbd vbd;
|
||||
/* Private fields. */
|
||||
enum { DISCONNECTED, CONNECTED } status;
|
||||
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
|
||||
/* Is this a blktap frontend */
|
||||
unsigned int is_blktap;
|
||||
/* Is this a blktap frontend */
|
||||
unsigned int is_blktap;
|
||||
#endif
|
||||
struct list_head blkdev_list;
|
||||
spinlock_t blk_ring_lock;
|
||||
atomic_t refcnt;
|
||||
struct list_head blkdev_list;
|
||||
spinlock_t blk_ring_lock;
|
||||
atomic_t refcnt;
|
||||
|
||||
struct work_struct free_work;
|
||||
struct work_struct free_work;
|
||||
|
||||
u16 shmem_handle;
|
||||
grant_ref_t shmem_ref;
|
||||
u16 shmem_handle;
|
||||
grant_ref_t shmem_ref;
|
||||
} blkif_t;
|
||||
|
||||
blkif_t *alloc_blkif(domid_t domid);
|
||||
@@ -71,11 +71,11 @@ void free_blkif_callback(blkif_t *blkif);
|
||||
int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn);
|
||||
|
||||
#define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
|
||||
#define blkif_put(_b) \
|
||||
do { \
|
||||
if ( atomic_dec_and_test(&(_b)->refcnt) ) \
|
||||
free_blkif_callback(_b); \
|
||||
} while (0)
|
||||
#define blkif_put(_b) \
|
||||
do { \
|
||||
if (atomic_dec_and_test(&(_b)->refcnt)) \
|
||||
free_blkif_callback(_b); \
|
||||
} while (0)
|
||||
|
||||
/* Create a vbd. */
|
||||
int vbd_create(blkif_t *blkif, blkif_vdev_t vdevice, u32 pdevice,
|
||||
@@ -87,10 +87,10 @@ unsigned int vbd_info(struct vbd *vbd);
|
||||
unsigned long vbd_secsize(struct vbd *vbd);
|
||||
|
||||
struct phys_req {
|
||||
unsigned short dev;
|
||||
unsigned short nr_sects;
|
||||
struct block_device *bdev;
|
||||
blkif_sector_t sector_number;
|
||||
unsigned short dev;
|
||||
unsigned short nr_sects;
|
||||
struct block_device *bdev;
|
||||
blkif_sector_t sector_number;
|
||||
};
|
||||
|
||||
int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation);
|
||||
@@ -104,3 +104,13 @@ void blkif_xenbus_init(void);
|
||||
irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
|
||||
|
||||
#endif /* __BLKIF__BACKEND__COMMON_H__ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -13,134 +13,144 @@ static kmem_cache_t *blkif_cachep;
|
||||
|
||||
blkif_t *alloc_blkif(domid_t domid)
|
||||
{
|
||||
blkif_t *blkif;
|
||||
blkif_t *blkif;
|
||||
|
||||
blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
|
||||
if (!blkif)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
|
||||
if (!blkif)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
memset(blkif, 0, sizeof(*blkif));
|
||||
blkif->domid = domid;
|
||||
blkif->status = DISCONNECTED;
|
||||
spin_lock_init(&blkif->blk_ring_lock);
|
||||
atomic_set(&blkif->refcnt, 1);
|
||||
memset(blkif, 0, sizeof(*blkif));
|
||||
blkif->domid = domid;
|
||||
blkif->status = DISCONNECTED;
|
||||
spin_lock_init(&blkif->blk_ring_lock);
|
||||
atomic_set(&blkif->refcnt, 1);
|
||||
|
||||
return blkif;
|
||||
return blkif;
|
||||
}
|
||||
|
||||
static int map_frontend_page(blkif_t *blkif, unsigned long shared_page)
|
||||
{
|
||||
struct gnttab_map_grant_ref op;
|
||||
struct gnttab_map_grant_ref op;
|
||||
|
||||
op.host_addr = (unsigned long)blkif->blk_ring_area->addr;
|
||||
op.flags = GNTMAP_host_map;
|
||||
op.ref = shared_page;
|
||||
op.dom = blkif->domid;
|
||||
op.host_addr = (unsigned long)blkif->blk_ring_area->addr;
|
||||
op.flags = GNTMAP_host_map;
|
||||
op.ref = shared_page;
|
||||
op.dom = blkif->domid;
|
||||
|
||||
lock_vm_area(blkif->blk_ring_area);
|
||||
BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1));
|
||||
unlock_vm_area(blkif->blk_ring_area);
|
||||
lock_vm_area(blkif->blk_ring_area);
|
||||
BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1));
|
||||
unlock_vm_area(blkif->blk_ring_area);
|
||||
|
||||
if (op.handle < 0) {
|
||||
DPRINTK(" Grant table operation failure !\n");
|
||||
return op.handle;
|
||||
}
|
||||
if (op.handle < 0) {
|
||||
DPRINTK(" Grant table operation failure !\n");
|
||||
return op.handle;
|
||||
}
|
||||
|
||||
blkif->shmem_ref = shared_page;
|
||||
blkif->shmem_handle = op.handle;
|
||||
blkif->shmem_ref = shared_page;
|
||||
blkif->shmem_handle = op.handle;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unmap_frontend_page(blkif_t *blkif)
|
||||
{
|
||||
struct gnttab_unmap_grant_ref op;
|
||||
struct gnttab_unmap_grant_ref op;
|
||||
|
||||
op.host_addr = (unsigned long)blkif->blk_ring_area->addr;
|
||||
op.handle = blkif->shmem_handle;
|
||||
op.dev_bus_addr = 0;
|
||||
op.host_addr = (unsigned long)blkif->blk_ring_area->addr;
|
||||
op.handle = blkif->shmem_handle;
|
||||
op.dev_bus_addr = 0;
|
||||
|
||||
lock_vm_area(blkif->blk_ring_area);
|
||||
BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
|
||||
unlock_vm_area(blkif->blk_ring_area);
|
||||
lock_vm_area(blkif->blk_ring_area);
|
||||
BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
|
||||
unlock_vm_area(blkif->blk_ring_area);
|
||||
}
|
||||
|
||||
int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
|
||||
{
|
||||
blkif_sring_t *sring;
|
||||
evtchn_op_t op = { .cmd = EVTCHNOP_bind_interdomain };
|
||||
int err;
|
||||
blkif_sring_t *sring;
|
||||
evtchn_op_t op = { .cmd = EVTCHNOP_bind_interdomain };
|
||||
int err;
|
||||
|
||||
BUG_ON(blkif->remote_evtchn);
|
||||
BUG_ON(blkif->remote_evtchn);
|
||||
|
||||
if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
|
||||
return -ENOMEM;
|
||||
if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
|
||||
return -ENOMEM;
|
||||
|
||||
err = map_frontend_page(blkif, shared_page);
|
||||
if (err) {
|
||||
free_vm_area(blkif->blk_ring_area);
|
||||
return err;
|
||||
}
|
||||
err = map_frontend_page(blkif, shared_page);
|
||||
if (err) {
|
||||
free_vm_area(blkif->blk_ring_area);
|
||||
return err;
|
||||
}
|
||||
|
||||
op.u.bind_interdomain.dom1 = DOMID_SELF;
|
||||
op.u.bind_interdomain.dom2 = blkif->domid;
|
||||
op.u.bind_interdomain.port1 = 0;
|
||||
op.u.bind_interdomain.port2 = evtchn;
|
||||
err = HYPERVISOR_event_channel_op(&op);
|
||||
if (err) {
|
||||
unmap_frontend_page(blkif);
|
||||
free_vm_area(blkif->blk_ring_area);
|
||||
return err;
|
||||
}
|
||||
op.u.bind_interdomain.dom1 = DOMID_SELF;
|
||||
op.u.bind_interdomain.dom2 = blkif->domid;
|
||||
op.u.bind_interdomain.port1 = 0;
|
||||
op.u.bind_interdomain.port2 = evtchn;
|
||||
err = HYPERVISOR_event_channel_op(&op);
|
||||
if (err) {
|
||||
unmap_frontend_page(blkif);
|
||||
free_vm_area(blkif->blk_ring_area);
|
||||
return err;
|
||||
}
|
||||
|
||||
blkif->evtchn = op.u.bind_interdomain.port1;
|
||||
blkif->remote_evtchn = evtchn;
|
||||
blkif->evtchn = op.u.bind_interdomain.port1;
|
||||
blkif->remote_evtchn = evtchn;
|
||||
|
||||
sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
|
||||
SHARED_RING_INIT(sring);
|
||||
BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE);
|
||||
sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
|
||||
SHARED_RING_INIT(sring);
|
||||
BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE);
|
||||
|
||||
bind_evtchn_to_irqhandler(blkif->evtchn, blkif_be_int, 0, "blkif-backend",
|
||||
blkif);
|
||||
blkif->status = CONNECTED;
|
||||
bind_evtchn_to_irqhandler(
|
||||
blkif->evtchn, blkif_be_int, 0, "blkif-backend", blkif);
|
||||
blkif->status = CONNECTED;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_blkif(void *arg)
|
||||
{
|
||||
evtchn_op_t op = { .cmd = EVTCHNOP_close };
|
||||
blkif_t *blkif = (blkif_t *)arg;
|
||||
evtchn_op_t op = { .cmd = EVTCHNOP_close };
|
||||
blkif_t *blkif = (blkif_t *)arg;
|
||||
|
||||
op.u.close.port = blkif->evtchn;
|
||||
op.u.close.dom = DOMID_SELF;
|
||||
HYPERVISOR_event_channel_op(&op);
|
||||
op.u.close.port = blkif->remote_evtchn;
|
||||
op.u.close.dom = blkif->domid;
|
||||
HYPERVISOR_event_channel_op(&op);
|
||||
op.u.close.port = blkif->evtchn;
|
||||
op.u.close.dom = DOMID_SELF;
|
||||
HYPERVISOR_event_channel_op(&op);
|
||||
op.u.close.port = blkif->remote_evtchn;
|
||||
op.u.close.dom = blkif->domid;
|
||||
HYPERVISOR_event_channel_op(&op);
|
||||
|
||||
vbd_free(&blkif->vbd);
|
||||
vbd_free(&blkif->vbd);
|
||||
|
||||
if (blkif->evtchn)
|
||||
unbind_evtchn_from_irqhandler(blkif->evtchn, blkif);
|
||||
if (blkif->evtchn)
|
||||
unbind_evtchn_from_irqhandler(blkif->evtchn, blkif);
|
||||
|
||||
if (blkif->blk_ring.sring) {
|
||||
unmap_frontend_page(blkif);
|
||||
free_vm_area(blkif->blk_ring_area);
|
||||
blkif->blk_ring.sring = NULL;
|
||||
}
|
||||
if (blkif->blk_ring.sring) {
|
||||
unmap_frontend_page(blkif);
|
||||
free_vm_area(blkif->blk_ring_area);
|
||||
blkif->blk_ring.sring = NULL;
|
||||
}
|
||||
|
||||
kmem_cache_free(blkif_cachep, blkif);
|
||||
kmem_cache_free(blkif_cachep, blkif);
|
||||
}
|
||||
|
||||
void free_blkif_callback(blkif_t *blkif)
|
||||
{
|
||||
INIT_WORK(&blkif->free_work, free_blkif, (void *)blkif);
|
||||
schedule_work(&blkif->free_work);
|
||||
INIT_WORK(&blkif->free_work, free_blkif, (void *)blkif);
|
||||
schedule_work(&blkif->free_work);
|
||||
}
|
||||
|
||||
void __init blkif_interface_init(void)
|
||||
{
|
||||
blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t),
|
||||
0, 0, NULL, NULL);
|
||||
blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t),
|
||||
0, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -11,10 +11,10 @@
|
||||
|
||||
static inline dev_t vbd_map_devnum(u32 cookie)
|
||||
{
|
||||
return MKDEV(BLKIF_MAJOR(cookie), BLKIF_MINOR(cookie));
|
||||
return MKDEV(BLKIF_MAJOR(cookie), BLKIF_MINOR(cookie));
|
||||
}
|
||||
#define vbd_sz(_v) ((_v)->bdev->bd_part ? \
|
||||
(_v)->bdev->bd_part->nr_sects : (_v)->bdev->bd_disk->capacity)
|
||||
#define vbd_sz(_v) ((_v)->bdev->bd_part ? \
|
||||
(_v)->bdev->bd_part->nr_sects : (_v)->bdev->bd_disk->capacity)
|
||||
#define bdev_put(_b) blkdev_put(_b)
|
||||
|
||||
unsigned long vbd_size(struct vbd *vbd)
|
||||
@@ -35,63 +35,73 @@ unsigned long vbd_secsize(struct vbd *vbd)
|
||||
int vbd_create(blkif_t *blkif, blkif_vdev_t handle,
|
||||
u32 pdevice, int readonly)
|
||||
{
|
||||
struct vbd *vbd;
|
||||
struct vbd *vbd;
|
||||
|
||||
vbd = &blkif->vbd;
|
||||
vbd->handle = handle;
|
||||
vbd->readonly = readonly;
|
||||
vbd->type = 0;
|
||||
vbd = &blkif->vbd;
|
||||
vbd->handle = handle;
|
||||
vbd->readonly = readonly;
|
||||
vbd->type = 0;
|
||||
|
||||
vbd->pdevice = pdevice;
|
||||
vbd->pdevice = pdevice;
|
||||
|
||||
vbd->bdev = open_by_devnum(
|
||||
vbd_map_devnum(vbd->pdevice),
|
||||
vbd->readonly ? FMODE_READ : FMODE_WRITE);
|
||||
if ( IS_ERR(vbd->bdev) )
|
||||
{
|
||||
DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
|
||||
return -ENOENT;
|
||||
}
|
||||
vbd->bdev = open_by_devnum(
|
||||
vbd_map_devnum(vbd->pdevice),
|
||||
vbd->readonly ? FMODE_READ : FMODE_WRITE);
|
||||
if (IS_ERR(vbd->bdev)) {
|
||||
DPRINTK("vbd_creat: device %08x doesn't exist.\n",
|
||||
vbd->pdevice);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if ( (vbd->bdev->bd_disk == NULL) )
|
||||
{
|
||||
DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice);
|
||||
vbd_free(vbd);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (vbd->bdev->bd_disk == NULL) {
|
||||
DPRINTK("vbd_creat: device %08x doesn't exist.\n",
|
||||
vbd->pdevice);
|
||||
vbd_free(vbd);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if ( vbd->bdev->bd_disk->flags & GENHD_FL_CD )
|
||||
vbd->type |= VDISK_CDROM;
|
||||
if ( vbd->bdev->bd_disk->flags & GENHD_FL_REMOVABLE )
|
||||
vbd->type |= VDISK_REMOVABLE;
|
||||
if (vbd->bdev->bd_disk->flags & GENHD_FL_CD)
|
||||
vbd->type |= VDISK_CDROM;
|
||||
if (vbd->bdev->bd_disk->flags & GENHD_FL_REMOVABLE)
|
||||
vbd->type |= VDISK_REMOVABLE;
|
||||
|
||||
DPRINTK("Successful creation of handle=%04x (dom=%u)\n",
|
||||
handle, blkif->domid);
|
||||
return 0;
|
||||
DPRINTK("Successful creation of handle=%04x (dom=%u)\n",
|
||||
handle, blkif->domid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vbd_free(struct vbd *vbd)
|
||||
{
|
||||
if (vbd->bdev)
|
||||
bdev_put(vbd->bdev);
|
||||
vbd->bdev = NULL;
|
||||
if (vbd->bdev)
|
||||
bdev_put(vbd->bdev);
|
||||
vbd->bdev = NULL;
|
||||
}
|
||||
|
||||
int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation)
|
||||
{
|
||||
struct vbd *vbd = &blkif->vbd;
|
||||
int rc = -EACCES;
|
||||
struct vbd *vbd = &blkif->vbd;
|
||||
int rc = -EACCES;
|
||||
|
||||
if ((operation == WRITE) && vbd->readonly)
|
||||
goto out;
|
||||
if ((operation == WRITE) && vbd->readonly)
|
||||
goto out;
|
||||
|
||||
if (unlikely((req->sector_number + req->nr_sects) > vbd_sz(vbd)))
|
||||
goto out;
|
||||
if (unlikely((req->sector_number + req->nr_sects) > vbd_sz(vbd)))
|
||||
goto out;
|
||||
|
||||
req->dev = vbd->pdevice;
|
||||
req->bdev = vbd->bdev;
|
||||
rc = 0;
|
||||
req->dev = vbd->pdevice;
|
||||
req->bdev = vbd->bdev;
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -124,7 +124,7 @@ static void frontend_changed(struct xenbus_watch *watch, const char *node)
|
||||
|
||||
return;
|
||||
|
||||
abort:
|
||||
abort:
|
||||
xenbus_transaction_end(1);
|
||||
}
|
||||
|
||||
@@ -278,3 +278,13 @@ void blkif_xenbus_init(void)
|
||||
{
|
||||
xenbus_register_backend(&blkback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -146,4 +146,15 @@ extern void do_blkif_request (request_queue_t *rq);
|
||||
int xlvbd_add(blkif_sector_t capacity, int device,
|
||||
u16 vdisk_info, u16 sector_size, struct blkfront_info *info);
|
||||
void xlvbd_del(struct blkfront_info *info);
|
||||
|
||||
#endif /* __XEN_DRIVERS_BLOCK_H__ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -65,7 +65,7 @@ static struct xlbd_type_info xlbd_vbd_type = {
|
||||
};
|
||||
|
||||
static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SCSI_MAJORS +
|
||||
NUM_VBD_MAJORS];
|
||||
NUM_VBD_MAJORS];
|
||||
|
||||
#define XLBD_MAJOR_IDE_START 0
|
||||
#define XLBD_MAJOR_SCSI_START (NUM_IDE_MAJORS)
|
||||
@@ -309,3 +309,13 @@ xlvbd_del(struct blkfront_info *info)
|
||||
|
||||
bdput(bd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large.
Load diff
@@ -33,39 +33,39 @@
|
||||
#define WPRINTK(fmt, args...) printk(KERN_WARNING "blk_tap: " fmt, ##args)
|
||||
|
||||
struct vbd {
|
||||
blkif_vdev_t handle; /* what the domain refers to this vbd as */
|
||||
unsigned char readonly; /* Non-zero -> read-only */
|
||||
unsigned char type; /* VDISK_xxx */
|
||||
u32 pdevice; /* phys device that this vbd maps to */
|
||||
struct block_device *bdev;
|
||||
blkif_vdev_t handle; /* what the domain refers to this vbd as */
|
||||
unsigned char readonly; /* Non-zero -> read-only */
|
||||
unsigned char type; /* VDISK_xxx */
|
||||
u32 pdevice; /* phys device that this vbd maps to */
|
||||
struct block_device *bdev;
|
||||
};
|
||||
|
||||
typedef struct blkif_st {
|
||||
/* Unique identifier for this interface. */
|
||||
domid_t domid;
|
||||
unsigned int handle;
|
||||
/* Physical parameters of the comms window. */
|
||||
unsigned int evtchn;
|
||||
unsigned int remote_evtchn;
|
||||
/* Comms information. */
|
||||
blkif_back_ring_t blk_ring;
|
||||
struct vm_struct *blk_ring_area;
|
||||
/* VBDs attached to this interface. */
|
||||
struct vbd vbd;
|
||||
/* Private fields. */
|
||||
enum { DISCONNECTED, CONNECTED } status;
|
||||
/* Unique identifier for this interface. */
|
||||
domid_t domid;
|
||||
unsigned int handle;
|
||||
/* Physical parameters of the comms window. */
|
||||
unsigned int evtchn;
|
||||
unsigned int remote_evtchn;
|
||||
/* Comms information. */
|
||||
blkif_back_ring_t blk_ring;
|
||||
struct vm_struct *blk_ring_area;
|
||||
/* VBDs attached to this interface. */
|
||||
struct vbd vbd;
|
||||
/* Private fields. */
|
||||
enum { DISCONNECTED, CONNECTED } status;
|
||||
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
|
||||
/* Is this a blktap frontend */
|
||||
unsigned int is_blktap;
|
||||
/* Is this a blktap frontend */
|
||||
unsigned int is_blktap;
|
||||
#endif
|
||||
struct list_head blkdev_list;
|
||||
spinlock_t blk_ring_lock;
|
||||
atomic_t refcnt;
|
||||
struct list_head blkdev_list;
|
||||
spinlock_t blk_ring_lock;
|
||||
atomic_t refcnt;
|
||||
|
||||
struct work_struct free_work;
|
||||
struct work_struct free_work;
|
||||
|
||||
u16 shmem_handle;
|
||||
grant_ref_t shmem_ref;
|
||||
u16 shmem_handle;
|
||||
grant_ref_t shmem_ref;
|
||||
} blkif_t;
|
||||
|
||||
blkif_t *alloc_blkif(domid_t domid);
|
||||
@@ -89,10 +89,10 @@ unsigned int vbd_info(struct vbd *vbd);
|
||||
unsigned long vbd_secsize(struct vbd *vbd);
|
||||
|
||||
struct phys_req {
|
||||
unsigned short dev;
|
||||
unsigned short nr_sects;
|
||||
struct block_device *bdev;
|
||||
blkif_sector_t sector_number;
|
||||
unsigned short dev;
|
||||
unsigned short nr_sects;
|
||||
struct block_device *bdev;
|
||||
blkif_sector_t sector_number;
|
||||
};
|
||||
|
||||
int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation);
|
||||
@@ -106,3 +106,13 @@ void blkif_xenbus_init(void);
|
||||
irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
|
||||
|
||||
#endif /* __BLKIF__BACKEND__COMMON_H__ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -222,3 +222,13 @@ void blkif_xenbus_init(void)
|
||||
{
|
||||
xenbus_register_backend(&blkback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large.
Load diff
@@ -125,3 +125,13 @@ void xencons_resume(void)
|
||||
|
||||
(void)xencons_ring_init();
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -3,12 +3,21 @@
|
||||
|
||||
asmlinkage int xprintk(const char *fmt, ...);
|
||||
|
||||
|
||||
int xencons_ring_init(void);
|
||||
int xencons_ring_send(const char *data, unsigned len);
|
||||
|
||||
typedef void (xencons_receiver_func)(char *buf, unsigned len,
|
||||
struct pt_regs *regs);
|
||||
typedef void (xencons_receiver_func)(
|
||||
char *buf, unsigned len, struct pt_regs *regs);
|
||||
void xencons_ring_register_receiver(xencons_receiver_func *f);
|
||||
|
||||
#endif /* _XENCONS_RING_H */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -1,9 +1,9 @@
|
||||
/******************************************************************************
|
||||
* evtchn.c
|
||||
*
|
||||
* Xenolinux driver for receiving and demuxing event-channel signals.
|
||||
* Driver for receiving and demuxing event-channel signals.
|
||||
*
|
||||
* Copyright (c) 2004, K A Fraser
|
||||
* Copyright (c) 2004-2005, K A Fraser
|
||||
* Multi-process extensions Copyright (c) 2004, Steven Smith
|
||||
*
|
||||
* This file may be distributed separately from the Linux kernel, or
|
||||
@@ -46,29 +46,18 @@
|
||||
#include <linux/init.h>
|
||||
#define XEN_EVTCHN_MASK_OPS
|
||||
#include <asm-xen/evtchn.h>
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
|
||||
#include <linux/devfs_fs_kernel.h>
|
||||
#define OLD_DEVFS
|
||||
#else
|
||||
#include <linux/gfp.h>
|
||||
#endif
|
||||
|
||||
#ifdef OLD_DEVFS
|
||||
/* NB. This must be shared amongst drivers if more things go in /dev/xen */
|
||||
static devfs_handle_t xen_dev_dir;
|
||||
#endif
|
||||
|
||||
struct per_user_data {
|
||||
/* Notification ring, accessed via /dev/xen/evtchn. */
|
||||
# define EVTCHN_RING_SIZE 2048 /* 2048 16-bit entries */
|
||||
# define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1))
|
||||
u16 *ring;
|
||||
unsigned int ring_cons, ring_prod, ring_overflow;
|
||||
/* Notification ring, accessed via /dev/xen/evtchn. */
|
||||
#define EVTCHN_RING_SIZE 2048 /* 2048 16-bit entries */
|
||||
#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1))
|
||||
u16 *ring;
|
||||
unsigned int ring_cons, ring_prod, ring_overflow;
|
||||
|
||||
/* Processes wait on this queue when ring is empty. */
|
||||
wait_queue_head_t evtchn_wait;
|
||||
struct fasync_struct *evtchn_async_queue;
|
||||
/* Processes wait on this queue when ring is empty. */
|
||||
wait_queue_head_t evtchn_wait;
|
||||
struct fasync_struct *evtchn_async_queue;
|
||||
};
|
||||
|
||||
/* Who's bound to each port? */
|
||||
@@ -77,356 +66,310 @@ static spinlock_t port_user_lock;
|
||||
|
||||
void evtchn_device_upcall(int port)
|
||||
{
|
||||
struct per_user_data *u;
|
||||
struct per_user_data *u;
|
||||
|
||||
spin_lock(&port_user_lock);
|
||||
spin_lock(&port_user_lock);
|
||||
|
||||
mask_evtchn(port);
|
||||
clear_evtchn(port);
|
||||
mask_evtchn(port);
|
||||
clear_evtchn(port);
|
||||
|
||||
if ( (u = port_user[port]) != NULL )
|
||||
{
|
||||
if ( (u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE )
|
||||
{
|
||||
u->ring[EVTCHN_RING_MASK(u->ring_prod)] = (u16)port;
|
||||
if ( u->ring_cons == u->ring_prod++ )
|
||||
{
|
||||
wake_up_interruptible(&u->evtchn_wait);
|
||||
kill_fasync(&u->evtchn_async_queue, SIGIO, POLL_IN);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u->ring_overflow = 1;
|
||||
}
|
||||
}
|
||||
if ((u = port_user[port]) != NULL) {
|
||||
if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
|
||||
u->ring[EVTCHN_RING_MASK(u->ring_prod)] = (u16)port;
|
||||
if (u->ring_cons == u->ring_prod++) {
|
||||
wake_up_interruptible(&u->evtchn_wait);
|
||||
kill_fasync(&u->evtchn_async_queue, SIGIO, POLL_IN);
|
||||
}
|
||||
} else {
|
||||
u->ring_overflow = 1;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&port_user_lock);
|
||||
spin_unlock(&port_user_lock);
|
||||
}
|
||||
|
||||
static ssize_t evtchn_read(struct file *file, char *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int rc;
|
||||
unsigned int c, p, bytes1 = 0, bytes2 = 0;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
struct per_user_data *u = file->private_data;
|
||||
int rc;
|
||||
unsigned int c, p, bytes1 = 0, bytes2 = 0;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
struct per_user_data *u = file->private_data;
|
||||
|
||||
add_wait_queue(&u->evtchn_wait, &wait);
|
||||
add_wait_queue(&u->evtchn_wait, &wait);
|
||||
|
||||
count &= ~1; /* even number of bytes */
|
||||
count &= ~1; /* even number of bytes */
|
||||
|
||||
if ( count == 0 )
|
||||
{
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
if (count == 0) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( count > PAGE_SIZE )
|
||||
count = PAGE_SIZE;
|
||||
if (count > PAGE_SIZE)
|
||||
count = PAGE_SIZE;
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
for (;;) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
if ( (c = u->ring_cons) != (p = u->ring_prod) )
|
||||
break;
|
||||
if ((c = u->ring_cons) != (p = u->ring_prod))
|
||||
break;
|
||||
|
||||
if ( u->ring_overflow )
|
||||
{
|
||||
rc = -EFBIG;
|
||||
goto out;
|
||||
}
|
||||
if (u->ring_overflow) {
|
||||
rc = -EFBIG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( file->f_flags & O_NONBLOCK )
|
||||
{
|
||||
rc = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
rc = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( signal_pending(current) )
|
||||
{
|
||||
rc = -ERESTARTSYS;
|
||||
goto out;
|
||||
}
|
||||
if (signal_pending(current)) {
|
||||
rc = -ERESTARTSYS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
schedule();
|
||||
}
|
||||
schedule();
|
||||
}
|
||||
|
||||
/* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
|
||||
if ( ((c ^ p) & EVTCHN_RING_SIZE) != 0 )
|
||||
{
|
||||
bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * sizeof(u16);
|
||||
bytes2 = EVTCHN_RING_MASK(p) * sizeof(u16);
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes1 = (p - c) * sizeof(u16);
|
||||
bytes2 = 0;
|
||||
}
|
||||
/* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
|
||||
if (((c ^ p) & EVTCHN_RING_SIZE) != 0) {
|
||||
bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) *
|
||||
sizeof(u16);
|
||||
bytes2 = EVTCHN_RING_MASK(p) * sizeof(u16);
|
||||
} else {
|
||||
bytes1 = (p - c) * sizeof(u16);
|
||||
bytes2 = 0;
|
||||
}
|
||||
|
||||
/* Truncate chunks according to caller's maximum byte count. */
|
||||
if ( bytes1 > count )
|
||||
{
|
||||
bytes1 = count;
|
||||
bytes2 = 0;
|
||||
}
|
||||
else if ( (bytes1 + bytes2) > count )
|
||||
{
|
||||
bytes2 = count - bytes1;
|
||||
}
|
||||
/* Truncate chunks according to caller's maximum byte count. */
|
||||
if (bytes1 > count) {
|
||||
bytes1 = count;
|
||||
bytes2 = 0;
|
||||
} else if ((bytes1 + bytes2) > count) {
|
||||
bytes2 = count - bytes1;
|
||||
}
|
||||
|
||||
if ( copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) ||
|
||||
((bytes2 != 0) && copy_to_user(&buf[bytes1], &u->ring[0], bytes2)) )
|
||||
{
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) ||
|
||||
((bytes2 != 0) &&
|
||||
copy_to_user(&buf[bytes1], &u->ring[0], bytes2))) {
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
u->ring_cons += (bytes1 + bytes2) / sizeof(u16);
|
||||
u->ring_cons += (bytes1 + bytes2) / sizeof(u16);
|
||||
|
||||
rc = bytes1 + bytes2;
|
||||
rc = bytes1 + bytes2;
|
||||
|
||||
out:
|
||||
__set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&u->evtchn_wait, &wait);
|
||||
return rc;
|
||||
__set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&u->evtchn_wait, &wait);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t evtchn_write(struct file *file, const char *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int rc, i;
|
||||
u16 *kbuf = (u16 *)__get_free_page(GFP_KERNEL);
|
||||
struct per_user_data *u = file->private_data;
|
||||
int rc, i;
|
||||
u16 *kbuf = (u16 *)__get_free_page(GFP_KERNEL);
|
||||
struct per_user_data *u = file->private_data;
|
||||
|
||||
if ( kbuf == NULL )
|
||||
return -ENOMEM;
|
||||
if (kbuf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
count &= ~1; /* even number of bytes */
|
||||
count &= ~1; /* even number of bytes */
|
||||
|
||||
if ( count == 0 )
|
||||
{
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
if (count == 0) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( count > PAGE_SIZE )
|
||||
count = PAGE_SIZE;
|
||||
if (count > PAGE_SIZE)
|
||||
count = PAGE_SIZE;
|
||||
|
||||
if ( copy_from_user(kbuf, buf, count) != 0 )
|
||||
{
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (copy_from_user(kbuf, buf, count) != 0) {
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock_irq(&port_user_lock);
|
||||
for ( i = 0; i < (count/2); i++ )
|
||||
if ( (kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u) )
|
||||
unmask_evtchn(kbuf[i]);
|
||||
spin_unlock_irq(&port_user_lock);
|
||||
spin_lock_irq(&port_user_lock);
|
||||
for (i = 0; i < (count/2); i++)
|
||||
if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u))
|
||||
unmask_evtchn(kbuf[i]);
|
||||
spin_unlock_irq(&port_user_lock);
|
||||
|
||||
rc = count;
|
||||
rc = count;
|
||||
|
||||
out:
|
||||
free_page((unsigned long)kbuf);
|
||||
return rc;
|
||||
free_page((unsigned long)kbuf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int evtchn_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int rc = 0;
|
||||
struct per_user_data *u = file->private_data;
|
||||
int rc = 0;
|
||||
struct per_user_data *u = file->private_data;
|
||||
|
||||
spin_lock_irq(&port_user_lock);
|
||||
spin_lock_irq(&port_user_lock);
|
||||
|
||||
switch ( cmd )
|
||||
{
|
||||
case EVTCHN_RESET:
|
||||
/* Initialise the ring to empty. Clear errors. */
|
||||
u->ring_cons = u->ring_prod = u->ring_overflow = 0;
|
||||
break;
|
||||
switch (cmd) {
|
||||
case EVTCHN_RESET:
|
||||
/* Initialise the ring to empty. Clear errors. */
|
||||
u->ring_cons = u->ring_prod = u->ring_overflow = 0;
|
||||
break;
|
||||
|
||||
case EVTCHN_BIND:
|
||||
if ( arg >= NR_EVENT_CHANNELS )
|
||||
{
|
||||
rc = -EINVAL;
|
||||
}
|
||||
else if ( port_user[arg] != NULL )
|
||||
{
|
||||
rc = -EISCONN;
|
||||
}
|
||||
else
|
||||
{
|
||||
port_user[arg] = u;
|
||||
unmask_evtchn(arg);
|
||||
}
|
||||
break;
|
||||
case EVTCHN_BIND:
|
||||
if (arg >= NR_EVENT_CHANNELS) {
|
||||
rc = -EINVAL;
|
||||
} else if (port_user[arg] != NULL) {
|
||||
rc = -EISCONN;
|
||||
} else {
|
||||
port_user[arg] = u;
|
||||
unmask_evtchn(arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case EVTCHN_UNBIND:
|
||||
if ( arg >= NR_EVENT_CHANNELS )
|
||||
{
|
||||
rc = -EINVAL;
|
||||
}
|
||||
else if ( port_user[arg] != u )
|
||||
{
|
||||
rc = -ENOTCONN;
|
||||
}
|
||||
else
|
||||
{
|
||||
port_user[arg] = NULL;
|
||||
mask_evtchn(arg);
|
||||
}
|
||||
break;
|
||||
case EVTCHN_UNBIND:
|
||||
if (arg >= NR_EVENT_CHANNELS) {
|
||||
rc = -EINVAL;
|
||||
} else if (port_user[arg] != u) {
|
||||
rc = -ENOTCONN;
|
||||
} else {
|
||||
port_user[arg] = NULL;
|
||||
mask_evtchn(arg);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rc = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&port_user_lock);
|
||||
spin_unlock_irq(&port_user_lock);
|
||||
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static unsigned int evtchn_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
unsigned int mask = POLLOUT | POLLWRNORM;
|
||||
struct per_user_data *u = file->private_data;
|
||||
unsigned int mask = POLLOUT | POLLWRNORM;
|
||||
struct per_user_data *u = file->private_data;
|
||||
|
||||
poll_wait(file, &u->evtchn_wait, wait);
|
||||
if ( u->ring_cons != u->ring_prod )
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
if ( u->ring_overflow )
|
||||
mask = POLLERR;
|
||||
return mask;
|
||||
poll_wait(file, &u->evtchn_wait, wait);
|
||||
if (u->ring_cons != u->ring_prod)
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
if (u->ring_overflow)
|
||||
mask = POLLERR;
|
||||
return mask;
|
||||
}
|
||||
|
||||
static int evtchn_fasync(int fd, struct file *filp, int on)
|
||||
{
|
||||
struct per_user_data *u = filp->private_data;
|
||||
return fasync_helper(fd, filp, on, &u->evtchn_async_queue);
|
||||
struct per_user_data *u = filp->private_data;
|
||||
return fasync_helper(fd, filp, on, &u->evtchn_async_queue);
|
||||
}
|
||||
|
||||
static int evtchn_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct per_user_data *u;
|
||||
struct per_user_data *u;
|
||||
|
||||
if ( (u = kmalloc(sizeof(*u), GFP_KERNEL)) == NULL )
|
||||
return -ENOMEM;
|
||||
if ((u = kmalloc(sizeof(*u), GFP_KERNEL)) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(u, 0, sizeof(*u));
|
||||
init_waitqueue_head(&u->evtchn_wait);
|
||||
memset(u, 0, sizeof(*u));
|
||||
init_waitqueue_head(&u->evtchn_wait);
|
||||
|
||||
if ( (u->ring = (u16 *)__get_free_page(GFP_KERNEL)) == NULL )
|
||||
{
|
||||
kfree(u);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if ((u->ring = (u16 *)__get_free_page(GFP_KERNEL)) == NULL)
|
||||
{
|
||||
kfree(u);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
filp->private_data = u;
|
||||
filp->private_data = u;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int evtchn_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
int i;
|
||||
struct per_user_data *u = filp->private_data;
|
||||
int i;
|
||||
struct per_user_data *u = filp->private_data;
|
||||
|
||||
spin_lock_irq(&port_user_lock);
|
||||
spin_lock_irq(&port_user_lock);
|
||||
|
||||
free_page((unsigned long)u->ring);
|
||||
free_page((unsigned long)u->ring);
|
||||
|
||||
for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
|
||||
{
|
||||
if ( port_user[i] == u )
|
||||
{
|
||||
port_user[i] = NULL;
|
||||
mask_evtchn(i);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < NR_EVENT_CHANNELS; i++)
|
||||
{
|
||||
if (port_user[i] == u)
|
||||
{
|
||||
port_user[i] = NULL;
|
||||
mask_evtchn(i);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irq(&port_user_lock);
|
||||
spin_unlock_irq(&port_user_lock);
|
||||
|
||||
kfree(u);
|
||||
kfree(u);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations evtchn_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = evtchn_read,
|
||||
.write = evtchn_write,
|
||||
.ioctl = evtchn_ioctl,
|
||||
.poll = evtchn_poll,
|
||||
.fasync = evtchn_fasync,
|
||||
.open = evtchn_open,
|
||||
.release = evtchn_release,
|
||||
.owner = THIS_MODULE,
|
||||
.read = evtchn_read,
|
||||
.write = evtchn_write,
|
||||
.ioctl = evtchn_ioctl,
|
||||
.poll = evtchn_poll,
|
||||
.fasync = evtchn_fasync,
|
||||
.open = evtchn_open,
|
||||
.release = evtchn_release,
|
||||
};
|
||||
|
||||
static struct miscdevice evtchn_miscdev = {
|
||||
.minor = EVTCHN_MINOR,
|
||||
.name = "evtchn",
|
||||
.fops = &evtchn_fops,
|
||||
.minor = EVTCHN_MINOR,
|
||||
.name = "evtchn",
|
||||
.fops = &evtchn_fops,
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
|
||||
.devfs_name = "misc/evtchn",
|
||||
.devfs_name = "misc/evtchn",
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __init evtchn_init(void)
|
||||
{
|
||||
#ifdef OLD_DEVFS
|
||||
devfs_handle_t symlink_handle;
|
||||
int pos;
|
||||
char link_dest[64];
|
||||
#endif
|
||||
int err;
|
||||
int err;
|
||||
|
||||
spin_lock_init(&port_user_lock);
|
||||
memset(port_user, 0, sizeof(port_user));
|
||||
spin_lock_init(&port_user_lock);
|
||||
memset(port_user, 0, sizeof(port_user));
|
||||
|
||||
/* (DEVFS) create '/dev/misc/evtchn'. */
|
||||
err = misc_register(&evtchn_miscdev);
|
||||
if ( err != 0 )
|
||||
{
|
||||
printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
|
||||
return err;
|
||||
}
|
||||
/* (DEVFS) create '/dev/misc/evtchn'. */
|
||||
err = misc_register(&evtchn_miscdev);
|
||||
if (err != 0)
|
||||
{
|
||||
printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef OLD_DEVFS
|
||||
/* (DEVFS) create directory '/dev/xen'. */
|
||||
xen_dev_dir = devfs_mk_dir(NULL, "xen", NULL);
|
||||
printk("Event-channel device installed.\n");
|
||||
|
||||
/* (DEVFS) &link_dest[pos] == '../misc/evtchn'. */
|
||||
pos = devfs_generate_path(evtchn_miscdev.devfs_handle,
|
||||
&link_dest[3],
|
||||
sizeof(link_dest) - 3);
|
||||
if ( pos >= 0 )
|
||||
strncpy(&link_dest[pos], "../", 3);
|
||||
|
||||
/* (DEVFS) symlink '/dev/xen/evtchn' -> '../misc/evtchn'. */
|
||||
(void)devfs_mk_symlink(xen_dev_dir,
|
||||
"evtchn",
|
||||
DEVFS_FL_DEFAULT,
|
||||
&link_dest[pos],
|
||||
&symlink_handle,
|
||||
NULL);
|
||||
|
||||
/* (DEVFS) automatically destroy the symlink with its destination. */
|
||||
devfs_auto_unregister(evtchn_miscdev.devfs_handle, symlink_handle);
|
||||
#endif
|
||||
|
||||
printk("Event-channel device installed.\n");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void evtchn_cleanup(void)
|
||||
{
|
||||
misc_deregister(&evtchn_miscdev);
|
||||
misc_deregister(&evtchn_miscdev);
|
||||
}
|
||||
|
||||
module_init(evtchn_init);
|
||||
module_exit(evtchn_cleanup);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -62,9 +62,7 @@ typedef struct netif_st {
|
||||
/* Private indexes into shared ring. */
|
||||
NETIF_RING_IDX rx_req_cons;
|
||||
NETIF_RING_IDX rx_resp_prod; /* private version of shared variable */
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
NETIF_RING_IDX rx_resp_prod_copy;
|
||||
#endif
|
||||
NETIF_RING_IDX tx_req_cons;
|
||||
NETIF_RING_IDX tx_resp_prod; /* private version of shared variable */
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ static void make_tx_response(netif_t *netif,
|
||||
static int make_rx_response(netif_t *netif,
|
||||
u16 id,
|
||||
s8 st,
|
||||
unsigned long addr,
|
||||
u16 offset,
|
||||
u16 size,
|
||||
u16 csum_valid);
|
||||
|
||||
@@ -41,11 +41,7 @@ static struct sk_buff_head rx_queue;
|
||||
static multicall_entry_t rx_mcl[NETIF_RX_RING_SIZE*2+1];
|
||||
static mmu_update_t rx_mmu[NETIF_RX_RING_SIZE];
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
static gnttab_transfer_t grant_rx_op[MAX_PENDING_REQS];
|
||||
#else
|
||||
static struct mmuext_op rx_mmuext[NETIF_RX_RING_SIZE];
|
||||
#endif
|
||||
static unsigned char rx_notify[NR_EVENT_CHANNELS];
|
||||
|
||||
/* Don't currently gate addition of an interface to the tx scheduling list. */
|
||||
@@ -72,15 +68,10 @@ static PEND_RING_IDX dealloc_prod, dealloc_cons;
|
||||
|
||||
static struct sk_buff_head tx_queue;
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
static u16 grant_tx_ref[MAX_PENDING_REQS];
|
||||
static gnttab_unmap_grant_ref_t tx_unmap_ops[MAX_PENDING_REQS];
|
||||
static gnttab_map_grant_ref_t tx_map_ops[MAX_PENDING_REQS];
|
||||
|
||||
#else
|
||||
static multicall_entry_t tx_mcl[MAX_PENDING_REQS];
|
||||
#endif
|
||||
|
||||
static struct list_head net_schedule_list;
|
||||
static spinlock_t net_schedule_list_lock;
|
||||
|
||||
@@ -108,7 +99,7 @@ static unsigned long alloc_mfn(void)
|
||||
return mfn;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_XEN_NETDEV_GRANT
|
||||
#if 0
|
||||
static void free_mfn(unsigned long mfn)
|
||||
{
|
||||
unsigned long flags;
|
||||
@@ -180,18 +171,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
dev_kfree_skb(skb);
|
||||
skb = nskb;
|
||||
}
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
#ifdef DEBUG_GRANT
|
||||
printk(KERN_ALERT "#### be_xmit: req_prod=%d req_cons=%d "
|
||||
"id=%04x gr=%04x\n",
|
||||
netif->rx->req_prod,
|
||||
netif->rx_req_cons,
|
||||
netif->rx->ring[
|
||||
MASK_NETIF_RX_IDX(netif->rx_req_cons)].req.id,
|
||||
netif->rx->ring[
|
||||
MASK_NETIF_RX_IDX(netif->rx_req_cons)].req.gref);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
netif->rx_req_cons++;
|
||||
netif_get(netif);
|
||||
|
||||
@@ -232,11 +212,7 @@ static void net_rx_action(unsigned long unused)
|
||||
u16 size, id, evtchn;
|
||||
multicall_entry_t *mcl;
|
||||
mmu_update_t *mmu;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
gnttab_transfer_t *gop;
|
||||
#else
|
||||
struct mmuext_op *mmuext;
|
||||
#endif
|
||||
unsigned long vdata, old_mfn, new_mfn;
|
||||
struct sk_buff_head rxq;
|
||||
struct sk_buff *skb;
|
||||
@@ -247,11 +223,7 @@ static void net_rx_action(unsigned long unused)
|
||||
|
||||
mcl = rx_mcl;
|
||||
mmu = rx_mmu;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
gop = grant_rx_op;
|
||||
#else
|
||||
mmuext = rx_mmuext;
|
||||
#endif
|
||||
|
||||
while ((skb = skb_dequeue(&rx_queue)) != NULL) {
|
||||
netif = netdev_priv(skb->dev);
|
||||
@@ -277,25 +249,13 @@ static void net_rx_action(unsigned long unused)
|
||||
pfn_pte_ma(new_mfn, PAGE_KERNEL), 0);
|
||||
mcl++;
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
gop->mfn = old_mfn;
|
||||
gop->domid = netif->domid;
|
||||
gop->ref = netif->rx->ring[
|
||||
MASK_NETIF_RX_IDX(netif->rx_resp_prod_copy)].req.gref;
|
||||
netif->rx_resp_prod_copy++;
|
||||
gop++;
|
||||
#else
|
||||
mcl->op = __HYPERVISOR_mmuext_op;
|
||||
mcl->args[0] = (unsigned long)mmuext;
|
||||
mcl->args[1] = 1;
|
||||
mcl->args[2] = 0;
|
||||
mcl->args[3] = netif->domid;
|
||||
mcl++;
|
||||
|
||||
mmuext->cmd = MMUEXT_REASSIGN_PAGE;
|
||||
mmuext->arg1.mfn = old_mfn;
|
||||
mmuext++;
|
||||
#endif
|
||||
mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) |
|
||||
MMU_MACHPHYS_UPDATE;
|
||||
mmu->val = __pa(vdata) >> PAGE_SHIFT;
|
||||
@@ -303,9 +263,6 @@ static void net_rx_action(unsigned long unused)
|
||||
|
||||
__skb_queue_tail(&rxq, skb);
|
||||
|
||||
#ifdef DEBUG_GRANT
|
||||
dump_packet('a', old_mfn, vdata);
|
||||
#endif
|
||||
/* Filled the batch queue? */
|
||||
if ((mcl - rx_mcl) == ARRAY_SIZE(rx_mcl))
|
||||
break;
|
||||
@@ -321,17 +278,12 @@ static void net_rx_action(unsigned long unused)
|
||||
mcl->args[3] = DOMID_SELF;
|
||||
mcl++;
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
mcl[-2].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL;
|
||||
#else
|
||||
mcl[-3].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL;
|
||||
#endif
|
||||
BUG_ON(HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl) != 0);
|
||||
|
||||
mcl = rx_mcl;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
if(HYPERVISOR_grant_table_op(GNTTABOP_transfer, grant_rx_op,
|
||||
gop - grant_rx_op)) {
|
||||
if( HYPERVISOR_grant_table_op(GNTTABOP_transfer, grant_rx_op,
|
||||
gop - grant_rx_op)) {
|
||||
/*
|
||||
* The other side has given us a bad grant ref, or has no
|
||||
* headroom, or has gone away. Unfortunately the current grant
|
||||
@@ -343,20 +295,14 @@ static void net_rx_action(unsigned long unused)
|
||||
grant_rx_op[0].domid, gop - grant_rx_op);
|
||||
}
|
||||
gop = grant_rx_op;
|
||||
#else
|
||||
mmuext = rx_mmuext;
|
||||
#endif
|
||||
|
||||
while ((skb = __skb_dequeue(&rxq)) != NULL) {
|
||||
netif = netdev_priv(skb->dev);
|
||||
size = skb->tail - skb->data;
|
||||
|
||||
/* Rederive the machine addresses. */
|
||||
new_mfn = mcl[0].args[1] >> PAGE_SHIFT;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
old_mfn = 0; /* XXX Fix this so we can free_mfn() on error! */
|
||||
#else
|
||||
old_mfn = mmuext[0].arg1.mfn;
|
||||
#endif
|
||||
atomic_set(&(skb_shinfo(skb)->dataref), 1);
|
||||
skb_shinfo(skb)->nr_frags = 0;
|
||||
skb_shinfo(skb)->frag_list = NULL;
|
||||
@@ -369,27 +315,17 @@ static void net_rx_action(unsigned long unused)
|
||||
|
||||
/* Check the reassignment error code. */
|
||||
status = NETIF_RSP_OKAY;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
if(gop->status != 0) {
|
||||
DPRINTK("Bad status %d from grant transfer to DOM%u\n",
|
||||
gop->status, netif->domid);
|
||||
/* XXX SMH: should free 'old_mfn' here */
|
||||
status = NETIF_RSP_ERROR;
|
||||
}
|
||||
#else
|
||||
if (unlikely(mcl[1].result != 0)) {
|
||||
DPRINTK("Failed MMU update transferring to DOM%u\n",
|
||||
netif->domid);
|
||||
free_mfn(old_mfn);
|
||||
status = NETIF_RSP_ERROR;
|
||||
}
|
||||
#endif
|
||||
evtchn = netif->evtchn;
|
||||
id = netif->rx->ring[
|
||||
MASK_NETIF_RX_IDX(netif->rx_resp_prod)].req.id;
|
||||
if (make_rx_response(netif, id, status,
|
||||
(old_mfn << PAGE_SHIFT) | /* XXX */
|
||||
((unsigned long)skb->data & ~PAGE_MASK),
|
||||
(unsigned long)skb->data & ~PAGE_MASK,
|
||||
size, skb->proto_csum_valid) &&
|
||||
(rx_notify[evtchn] == 0)) {
|
||||
rx_notify[evtchn] = 1;
|
||||
@@ -398,13 +334,8 @@ static void net_rx_action(unsigned long unused)
|
||||
|
||||
netif_put(netif);
|
||||
dev_kfree_skb(skb);
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
mcl++;
|
||||
gop++;
|
||||
#else
|
||||
mcl += 2;
|
||||
mmuext += 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
while (notify_nr != 0) {
|
||||
@@ -486,11 +417,7 @@ static void tx_credit_callback(unsigned long data)
|
||||
|
||||
inline static void net_tx_action_dealloc(void)
|
||||
{
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
gnttab_unmap_grant_ref_t *gop;
|
||||
#else
|
||||
multicall_entry_t *mcl;
|
||||
#endif
|
||||
u16 pending_idx;
|
||||
PEND_RING_IDX dc, dp;
|
||||
netif_t *netif;
|
||||
@@ -498,7 +425,6 @@ inline static void net_tx_action_dealloc(void)
|
||||
dc = dealloc_cons;
|
||||
dp = dealloc_prod;
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
/*
|
||||
* Free up any grants we have finished using
|
||||
*/
|
||||
@@ -513,26 +439,8 @@ inline static void net_tx_action_dealloc(void)
|
||||
}
|
||||
BUG_ON(HYPERVISOR_grant_table_op(
|
||||
GNTTABOP_unmap_grant_ref, tx_unmap_ops, gop - tx_unmap_ops));
|
||||
#else
|
||||
mcl = tx_mcl;
|
||||
while (dc != dp) {
|
||||
pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)];
|
||||
MULTI_update_va_mapping(mcl, MMAP_VADDR(pending_idx),
|
||||
__pte(0), 0);
|
||||
mcl++;
|
||||
}
|
||||
|
||||
mcl[-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL;
|
||||
BUG_ON(HYPERVISOR_multicall(tx_mcl, mcl - tx_mcl) != 0);
|
||||
|
||||
mcl = tx_mcl;
|
||||
#endif
|
||||
while (dealloc_cons != dp) {
|
||||
#ifndef CONFIG_XEN_NETDEV_GRANT
|
||||
/* The update_va_mapping() must not fail. */
|
||||
BUG_ON(mcl[0].result != 0);
|
||||
#endif
|
||||
|
||||
pending_idx = dealloc_ring[MASK_PEND_IDX(dealloc_cons++)];
|
||||
|
||||
netif = pending_tx_info[pending_idx].netif;
|
||||
@@ -556,10 +464,6 @@ inline static void net_tx_action_dealloc(void)
|
||||
add_to_net_schedule_list_tail(netif);
|
||||
|
||||
netif_put(netif);
|
||||
|
||||
#ifndef CONFIG_XEN_NETDEV_GRANT
|
||||
mcl++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,21 +476,13 @@ static void net_tx_action(unsigned long unused)
|
||||
netif_tx_request_t txreq;
|
||||
u16 pending_idx;
|
||||
NETIF_RING_IDX i;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
gnttab_map_grant_ref_t *mop;
|
||||
#else
|
||||
multicall_entry_t *mcl;
|
||||
#endif
|
||||
unsigned int data_len;
|
||||
|
||||
if (dealloc_cons != dealloc_prod)
|
||||
net_tx_action_dealloc();
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
mop = tx_map_ops;
|
||||
#else
|
||||
mcl = tx_mcl;
|
||||
#endif
|
||||
while ((NR_PENDING_REQS < MAX_PENDING_REQS) &&
|
||||
!list_empty(&net_schedule_list)) {
|
||||
/* Get a netif from the list with work to do. */
|
||||
@@ -657,8 +553,7 @@ static void net_tx_action(unsigned long unused)
|
||||
}
|
||||
|
||||
/* No crossing a page as the payload mustn't fragment. */
|
||||
if (unlikely(((txreq.addr & ~PAGE_MASK) + txreq.size) >=
|
||||
PAGE_SIZE)) {
|
||||
if (unlikely((txreq.offset + txreq.size) >= PAGE_SIZE)) {
|
||||
DPRINTK("txreq.addr: %lx, size: %u, end: %lu\n",
|
||||
txreq.addr, txreq.size,
|
||||
(txreq.addr &~PAGE_MASK) + txreq.size);
|
||||
@@ -682,20 +577,12 @@ static void net_tx_action(unsigned long unused)
|
||||
|
||||
/* Packets passed to netif_rx() must have some headroom. */
|
||||
skb_reserve(skb, 16);
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
|
||||
mop->host_addr = MMAP_VADDR(pending_idx);
|
||||
mop->dom = netif->domid;
|
||||
mop->ref = txreq.addr >> PAGE_SHIFT;
|
||||
mop->ref = txreq.gref;
|
||||
mop->flags = GNTMAP_host_map | GNTMAP_readonly;
|
||||
mop++;
|
||||
#else
|
||||
MULTI_update_va_mapping_otherdomain(
|
||||
mcl, MMAP_VADDR(pending_idx),
|
||||
pfn_pte_ma(txreq.addr >> PAGE_SHIFT, PAGE_KERNEL),
|
||||
0, netif->domid);
|
||||
|
||||
mcl++;
|
||||
#endif
|
||||
|
||||
memcpy(&pending_tx_info[pending_idx].req,
|
||||
&txreq, sizeof(txreq));
|
||||
@@ -706,17 +593,10 @@ static void net_tx_action(unsigned long unused)
|
||||
|
||||
pending_cons++;
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
if ((mop - tx_map_ops) >= ARRAY_SIZE(tx_map_ops))
|
||||
break;
|
||||
#else
|
||||
/* Filled the batch queue? */
|
||||
if ((mcl - tx_mcl) == ARRAY_SIZE(tx_mcl))
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
if (mop == tx_map_ops)
|
||||
return;
|
||||
|
||||
@@ -724,14 +604,6 @@ static void net_tx_action(unsigned long unused)
|
||||
GNTTABOP_map_grant_ref, tx_map_ops, mop - tx_map_ops));
|
||||
|
||||
mop = tx_map_ops;
|
||||
#else
|
||||
if (mcl == tx_mcl)
|
||||
return;
|
||||
|
||||
BUG_ON(HYPERVISOR_multicall(tx_mcl, mcl - tx_mcl) != 0);
|
||||
|
||||
mcl = tx_mcl;
|
||||
#endif
|
||||
while ((skb = __skb_dequeue(&tx_queue)) != NULL) {
|
||||
pending_idx = *((u16 *)skb->data);
|
||||
netif = pending_tx_info[pending_idx].netif;
|
||||
@@ -739,7 +611,6 @@ static void net_tx_action(unsigned long unused)
|
||||
sizeof(txreq));
|
||||
|
||||
/* Check the remap error code. */
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
if (unlikely(mop->handle < 0)) {
|
||||
printk(KERN_ALERT "#### netback grant fails\n");
|
||||
make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
|
||||
@@ -754,30 +625,13 @@ static void net_tx_action(unsigned long unused)
|
||||
__pa(MMAP_VADDR(pending_idx)) >> PAGE_SHIFT] =
|
||||
FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT);
|
||||
grant_tx_ref[pending_idx] = mop->handle;
|
||||
#else
|
||||
if (unlikely(mcl[0].result != 0)) {
|
||||
DPRINTK("Bad page frame\n");
|
||||
make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
|
||||
netif_put(netif);
|
||||
kfree_skb(skb);
|
||||
mcl++;
|
||||
pending_ring[MASK_PEND_IDX(pending_prod++)] =
|
||||
pending_idx;
|
||||
continue;
|
||||
}
|
||||
|
||||
phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx)) >>
|
||||
PAGE_SHIFT] =
|
||||
FOREIGN_FRAME(txreq.addr >> PAGE_SHIFT);
|
||||
#endif
|
||||
|
||||
data_len = (txreq.size > PKT_PROT_LEN) ?
|
||||
PKT_PROT_LEN : txreq.size;
|
||||
|
||||
__skb_put(skb, data_len);
|
||||
memcpy(skb->data,
|
||||
(void *)(MMAP_VADDR(pending_idx)|
|
||||
(txreq.addr&~PAGE_MASK)),
|
||||
(void *)(MMAP_VADDR(pending_idx)|txreq.offset),
|
||||
data_len);
|
||||
if (data_len < txreq.size) {
|
||||
/* Append the packet payload as a fragment. */
|
||||
@@ -786,7 +640,7 @@ static void net_tx_action(unsigned long unused)
|
||||
skb_shinfo(skb)->frags[0].size =
|
||||
txreq.size - data_len;
|
||||
skb_shinfo(skb)->frags[0].page_offset =
|
||||
(txreq.addr + data_len) & ~PAGE_MASK;
|
||||
txreq.offset + data_len;
|
||||
skb_shinfo(skb)->nr_frags = 1;
|
||||
} else {
|
||||
/* Schedule a response immediately. */
|
||||
@@ -813,11 +667,7 @@ static void net_tx_action(unsigned long unused)
|
||||
netif_rx(skb);
|
||||
netif->dev->last_rx = jiffies;
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
mop++;
|
||||
#else
|
||||
mcl++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -874,7 +724,7 @@ static void make_tx_response(netif_t *netif,
|
||||
static int make_rx_response(netif_t *netif,
|
||||
u16 id,
|
||||
s8 st,
|
||||
unsigned long addr,
|
||||
u16 offset,
|
||||
u16 size,
|
||||
u16 csum_valid)
|
||||
{
|
||||
@@ -882,7 +732,7 @@ static int make_rx_response(netif_t *netif,
|
||||
netif_rx_response_t *resp;
|
||||
|
||||
resp = &netif->rx->ring[MASK_NETIF_RX_IDX(i)].resp;
|
||||
resp->addr = addr;
|
||||
resp->offset = offset;
|
||||
resp->csum_valid = csum_valid;
|
||||
resp->id = id;
|
||||
resp->status = (s16)size;
|
||||
@@ -937,9 +787,6 @@ static int __init netback_init(void)
|
||||
return 0;
|
||||
|
||||
IPRINTK("Initialising Xen netif backend.\n");
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
IPRINTK("Using grant tables.\n");
|
||||
#endif
|
||||
|
||||
/* We can increase reservation by this much in net_rx_action(). */
|
||||
balloon_update_driver_allowance(NETIF_RX_RING_SIZE);
|
||||
|
||||
@@ -256,8 +256,8 @@ static void network_tx_buf_gc(struct net_device *dev)
|
||||
for (i = np->tx_resp_cons; i != prod; i++) {
|
||||
id = np->tx->ring[MASK_NETIF_TX_IDX(i)].resp.id;
|
||||
skb = np->tx_skbs[id];
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
if (unlikely(gnttab_query_foreign_access(np->grant_tx_ref[id]) != 0)) {
|
||||
if (unlikely(gnttab_query_foreign_access(
|
||||
np->grant_tx_ref[id]) != 0)) {
|
||||
printk(KERN_ALERT "network_tx_buf_gc: warning "
|
||||
"-- grant still in use by backend "
|
||||
"domain.\n");
|
||||
@@ -268,7 +268,6 @@ static void network_tx_buf_gc(struct net_device *dev)
|
||||
gnttab_release_grant_reference(
|
||||
&np->gref_tx_head, np->grant_tx_ref[id]);
|
||||
np->grant_tx_ref[id] = GRANT_INVALID_REF;
|
||||
#endif
|
||||
ADD_ID_TO_FREELIST(np->tx_skbs, id);
|
||||
dev_kfree_skb_irq(skb);
|
||||
}
|
||||
@@ -287,10 +286,7 @@ static void network_tx_buf_gc(struct net_device *dev)
|
||||
mb();
|
||||
} while (prod != np->tx->resp_prod);
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
out:
|
||||
#endif
|
||||
|
||||
if (np->tx_full && ((np->tx->req_prod - prod) < NETIF_TX_RING_SIZE)) {
|
||||
np->tx_full = 0;
|
||||
if (np->user_state == UST_OPEN)
|
||||
@@ -307,9 +303,7 @@ static void network_alloc_rx_buffers(struct net_device *dev)
|
||||
int i, batch_target;
|
||||
NETIF_RING_IDX req_prod = np->rx->req_prod;
|
||||
struct xen_memory_reservation reservation;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
grant_ref_t ref;
|
||||
#endif
|
||||
|
||||
if (unlikely(np->backend_state != BEST_CONNECTED))
|
||||
return;
|
||||
@@ -343,13 +337,11 @@ static void network_alloc_rx_buffers(struct net_device *dev)
|
||||
np->rx_skbs[id] = skb;
|
||||
|
||||
np->rx->ring[MASK_NETIF_RX_IDX(req_prod + i)].req.id = id;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
ref = gnttab_claim_grant_reference(&np->gref_rx_head);
|
||||
BUG_ON((signed short)ref < 0);
|
||||
np->grant_rx_ref[id] = ref;
|
||||
gnttab_grant_foreign_transfer_ref(ref, np->backend_id);
|
||||
np->rx->ring[MASK_NETIF_RX_IDX(req_prod + i)].req.gref = ref;
|
||||
#endif
|
||||
rx_pfn_array[i] = virt_to_mfn(skb->head);
|
||||
|
||||
/* Remove this page from map before passing back to Xen. */
|
||||
@@ -400,10 +392,8 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
struct net_private *np = netdev_priv(dev);
|
||||
netif_tx_request_t *tx;
|
||||
NETIF_RING_IDX i;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
grant_ref_t ref;
|
||||
unsigned long mfn;
|
||||
#endif
|
||||
|
||||
if (unlikely(np->tx_full)) {
|
||||
printk(KERN_ALERT "%s: full queue wasn't stopped!\n",
|
||||
@@ -439,18 +429,13 @@ static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
tx = &np->tx->ring[MASK_NETIF_TX_IDX(i)].req;
|
||||
|
||||
tx->id = id;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
ref = gnttab_claim_grant_reference(&np->gref_tx_head);
|
||||
BUG_ON((signed short)ref < 0);
|
||||
mfn = virt_to_mfn(skb->data);
|
||||
gnttab_grant_foreign_access_ref(
|
||||
ref, np->backend_id, mfn, GNTMAP_readonly);
|
||||
tx->addr = ref << PAGE_SHIFT;
|
||||
np->grant_tx_ref[id] = ref;
|
||||
#else
|
||||
tx->addr = virt_to_mfn(skb->data) << PAGE_SHIFT;
|
||||
#endif
|
||||
tx->addr |= (unsigned long)skb->data & ~PAGE_MASK;
|
||||
tx->gref = np->grant_tx_ref[id] = ref;
|
||||
tx->offset = (unsigned long)skb->data & ~PAGE_MASK;
|
||||
tx->size = skb->len;
|
||||
tx->csum_blank = (skb->ip_summed == CHECKSUM_HW);
|
||||
|
||||
@@ -511,10 +496,8 @@ static int netif_poll(struct net_device *dev, int *pbudget)
|
||||
int work_done, budget, more_to_do = 1;
|
||||
struct sk_buff_head rxq;
|
||||
unsigned long flags;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
unsigned long mfn;
|
||||
grant_ref_t ref;
|
||||
#endif
|
||||
|
||||
spin_lock(&np->rx_lock);
|
||||
|
||||
@@ -550,7 +533,6 @@ static int netif_poll(struct net_device *dev, int *pbudget)
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
ref = np->grant_rx_ref[rx->id];
|
||||
|
||||
if(ref == GRANT_INVALID_REF) {
|
||||
@@ -568,17 +550,12 @@ static int netif_poll(struct net_device *dev, int *pbudget)
|
||||
np->grant_rx_ref[rx->id] = GRANT_INVALID_REF;
|
||||
mfn = gnttab_end_foreign_transfer_ref(ref);
|
||||
gnttab_release_grant_reference(&np->gref_rx_head, ref);
|
||||
#endif
|
||||
|
||||
skb = np->rx_skbs[rx->id];
|
||||
ADD_ID_TO_FREELIST(np->rx_skbs, rx->id);
|
||||
|
||||
/* NB. We handle skb overflow later. */
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
skb->data = skb->head + rx->addr;
|
||||
#else
|
||||
skb->data = skb->head + (rx->addr & ~PAGE_MASK);
|
||||
#endif
|
||||
skb->data = skb->head + rx->offset;
|
||||
skb->len = rx->status;
|
||||
skb->tail = skb->data + skb->len;
|
||||
|
||||
@@ -589,30 +566,14 @@ static int netif_poll(struct net_device *dev, int *pbudget)
|
||||
np->stats.rx_bytes += rx->status;
|
||||
|
||||
/* Remap the page. */
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
|
||||
#else
|
||||
mmu->ptr = (rx->addr & PAGE_MASK) | MMU_MACHPHYS_UPDATE;
|
||||
#endif
|
||||
mmu->val = __pa(skb->head) >> PAGE_SHIFT;
|
||||
mmu++;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
MULTI_update_va_mapping(mcl, (unsigned long)skb->head,
|
||||
pfn_pte_ma(mfn, PAGE_KERNEL), 0);
|
||||
#else
|
||||
MULTI_update_va_mapping(mcl, (unsigned long)skb->head,
|
||||
pfn_pte_ma(rx->addr >> PAGE_SHIFT,
|
||||
PAGE_KERNEL), 0);
|
||||
#endif
|
||||
mcl++;
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
phys_to_machine_mapping[__pa(skb->head) >> PAGE_SHIFT] = mfn;
|
||||
#else
|
||||
phys_to_machine_mapping[__pa(skb->head) >> PAGE_SHIFT] =
|
||||
rx->addr >> PAGE_SHIFT;
|
||||
#endif
|
||||
|
||||
|
||||
__skb_queue_tail(&rxq, skb);
|
||||
}
|
||||
@@ -773,16 +734,12 @@ static void network_connect(struct net_device *dev)
|
||||
tx = &np->tx->ring[requeue_idx++].req;
|
||||
|
||||
tx->id = i;
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
gnttab_grant_foreign_access_ref(
|
||||
np->grant_tx_ref[i], np->backend_id,
|
||||
virt_to_mfn(np->tx_skbs[i]->data),
|
||||
GNTMAP_readonly);
|
||||
tx->addr = np->grant_tx_ref[i] << PAGE_SHIFT;
|
||||
#else
|
||||
tx->addr = virt_to_mfn(skb->data) << PAGE_SHIFT;
|
||||
#endif
|
||||
tx->addr |= (unsigned long)skb->data & ~PAGE_MASK;
|
||||
tx->gref = np->grant_tx_ref[i];
|
||||
tx->offset = (unsigned long)skb->data & ~PAGE_MASK;
|
||||
tx->size = skb->len;
|
||||
|
||||
np->stats.tx_bytes += skb->len;
|
||||
@@ -795,12 +752,10 @@ static void network_connect(struct net_device *dev)
|
||||
/* Rebuild the RX buffer freelist and the RX ring itself. */
|
||||
for (requeue_idx = 0, i = 1; i <= NETIF_RX_RING_SIZE; i++) {
|
||||
if ((unsigned long)np->rx_skbs[i] >= __PAGE_OFFSET) {
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
gnttab_grant_foreign_transfer_ref(
|
||||
np->grant_rx_ref[i], np->backend_id);
|
||||
np->rx->ring[requeue_idx].req.gref =
|
||||
np->grant_rx_ref[i];
|
||||
#endif
|
||||
np->rx->ring[requeue_idx].req.id = i;
|
||||
requeue_idx++;
|
||||
}
|
||||
@@ -862,11 +817,9 @@ connect_device(struct net_private *np, unsigned int evtchn)
|
||||
|
||||
static void netif_uninit(struct net_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
struct net_private *np = netdev_priv(dev);
|
||||
gnttab_free_grant_references(np->gref_tx_head);
|
||||
gnttab_free_grant_references(np->gref_rx_head);
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct ethtool_ops network_ethtool_ops =
|
||||
@@ -911,19 +864,14 @@ static int create_netdev(int handle, struct xenbus_device *dev,
|
||||
/* Initialise {tx,rx}_skbs as a free chain containing every entry. */
|
||||
for (i = 0; i <= NETIF_TX_RING_SIZE; i++) {
|
||||
np->tx_skbs[i] = (void *)((unsigned long) i+1);
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
np->grant_tx_ref[i] = GRANT_INVALID_REF;
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i = 0; i <= NETIF_RX_RING_SIZE; i++) {
|
||||
np->rx_skbs[i] = (void *)((unsigned long) i+1);
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
np->grant_rx_ref[i] = GRANT_INVALID_REF;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
/* A grant for every tx ring slot */
|
||||
if (gnttab_alloc_grant_references(NETIF_TX_RING_SIZE,
|
||||
&np->gref_tx_head) < 0) {
|
||||
@@ -937,7 +885,6 @@ static int create_netdev(int handle, struct xenbus_device *dev,
|
||||
gnttab_free_grant_references(np->gref_tx_head);
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
|
||||
netdev->open = network_open;
|
||||
netdev->hard_start_xmit = network_start_xmit;
|
||||
@@ -971,10 +918,8 @@ static int create_netdev(int handle, struct xenbus_device *dev,
|
||||
return err;
|
||||
|
||||
exit_free_grefs:
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
gnttab_free_grant_references(np->gref_tx_head);
|
||||
gnttab_free_grant_references(np->gref_rx_head);
|
||||
#endif
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -1024,10 +969,8 @@ static int setup_device(struct xenbus_device *dev, struct netfront_info *info)
|
||||
evtchn_op_t op = { .cmd = EVTCHNOP_alloc_unbound };
|
||||
int err;
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
info->tx_ring_ref = GRANT_INVALID_REF;
|
||||
info->rx_ring_ref = GRANT_INVALID_REF;
|
||||
#endif
|
||||
|
||||
info->tx = (netif_tx_interface_t *)__get_free_page(GFP_KERNEL);
|
||||
if (info->tx == 0) {
|
||||
@@ -1045,7 +988,6 @@ static int setup_device(struct xenbus_device *dev, struct netfront_info *info)
|
||||
memset(info->rx, 0, PAGE_SIZE);
|
||||
info->backend_state = BEST_DISCONNECTED;
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
err = gnttab_grant_foreign_access(info->backend_id,
|
||||
virt_to_mfn(info->tx), 0);
|
||||
if (err < 0) {
|
||||
@@ -1062,11 +1004,6 @@ static int setup_device(struct xenbus_device *dev, struct netfront_info *info)
|
||||
}
|
||||
info->rx_ring_ref = err;
|
||||
|
||||
#else
|
||||
info->tx_ring_ref = virt_to_mfn(info->tx);
|
||||
info->rx_ring_ref = virt_to_mfn(info->rx);
|
||||
#endif
|
||||
|
||||
op.u.alloc_unbound.dom = info->backend_id;
|
||||
err = HYPERVISOR_event_channel_op(&op);
|
||||
if (err) {
|
||||
@@ -1084,7 +1021,6 @@ static int setup_device(struct xenbus_device *dev, struct netfront_info *info)
|
||||
free_page((unsigned long)info->rx);
|
||||
info->rx = 0;
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
if (info->tx_ring_ref != GRANT_INVALID_REF)
|
||||
gnttab_end_foreign_access(info->tx_ring_ref, 0);
|
||||
info->tx_ring_ref = GRANT_INVALID_REF;
|
||||
@@ -1092,7 +1028,6 @@ static int setup_device(struct xenbus_device *dev, struct netfront_info *info)
|
||||
if (info->rx_ring_ref != GRANT_INVALID_REF)
|
||||
gnttab_end_foreign_access(info->rx_ring_ref, 0);
|
||||
info->rx_ring_ref = GRANT_INVALID_REF;
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -1106,7 +1041,6 @@ static void netif_free(struct netfront_info *info)
|
||||
free_page((unsigned long)info->rx);
|
||||
info->rx = 0;
|
||||
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
if (info->tx_ring_ref != GRANT_INVALID_REF)
|
||||
gnttab_end_foreign_access(info->tx_ring_ref, 0);
|
||||
info->tx_ring_ref = GRANT_INVALID_REF;
|
||||
@@ -1114,7 +1048,6 @@ static void netif_free(struct netfront_info *info)
|
||||
if (info->rx_ring_ref != GRANT_INVALID_REF)
|
||||
gnttab_end_foreign_access(info->rx_ring_ref, 0);
|
||||
info->rx_ring_ref = GRANT_INVALID_REF;
|
||||
#endif
|
||||
|
||||
unbind_evtchn_from_irqhandler(info->evtchn, info->netdev);
|
||||
info->evtchn = 0;
|
||||
|
||||
@@ -41,232 +41,253 @@ static struct proc_dir_entry *privcmd_intf;
|
||||
static int privcmd_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long data)
|
||||
{
|
||||
int ret = -ENOSYS;
|
||||
int ret = -ENOSYS;
|
||||
|
||||
switch ( cmd )
|
||||
{
|
||||
case IOCTL_PRIVCMD_HYPERCALL:
|
||||
{
|
||||
privcmd_hypercall_t hypercall;
|
||||
switch (cmd) {
|
||||
case IOCTL_PRIVCMD_HYPERCALL: {
|
||||
privcmd_hypercall_t hypercall;
|
||||
|
||||
if ( copy_from_user(&hypercall, (void *)data, sizeof(hypercall)) )
|
||||
return -EFAULT;
|
||||
if (copy_from_user(&hypercall, (void *)data,
|
||||
sizeof(hypercall)))
|
||||
return -EFAULT;
|
||||
|
||||
#if defined(__i386__)
|
||||
__asm__ __volatile__ (
|
||||
"pushl %%ebx; pushl %%ecx; pushl %%edx; pushl %%esi; pushl %%edi; "
|
||||
"movl 4(%%eax),%%ebx ;"
|
||||
"movl 8(%%eax),%%ecx ;"
|
||||
"movl 12(%%eax),%%edx ;"
|
||||
"movl 16(%%eax),%%esi ;"
|
||||
"movl 20(%%eax),%%edi ;"
|
||||
"movl (%%eax),%%eax ;"
|
||||
TRAP_INSTR "; "
|
||||
"popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx"
|
||||
: "=a" (ret) : "0" (&hypercall) : "memory" );
|
||||
__asm__ __volatile__ (
|
||||
"pushl %%ebx; pushl %%ecx; pushl %%edx; "
|
||||
"pushl %%esi; pushl %%edi; "
|
||||
"movl 4(%%eax),%%ebx ;"
|
||||
"movl 8(%%eax),%%ecx ;"
|
||||
"movl 12(%%eax),%%edx ;"
|
||||
"movl 16(%%eax),%%esi ;"
|
||||
"movl 20(%%eax),%%edi ;"
|
||||
"movl (%%eax),%%eax ;"
|
||||
TRAP_INSTR "; "
|
||||
"popl %%edi; popl %%esi; popl %%edx; "
|
||||
"popl %%ecx; popl %%ebx"
|
||||
: "=a" (ret) : "0" (&hypercall) : "memory" );
|
||||
#elif defined (__x86_64__)
|
||||
{
|
||||
long ign1, ign2, ign3;
|
||||
__asm__ __volatile__ (
|
||||
"movq %8,%%r10; movq %9,%%r8;" TRAP_INSTR
|
||||
: "=a" (ret), "=D" (ign1), "=S" (ign2), "=d" (ign3)
|
||||
: "0" ((unsigned long)hypercall.op),
|
||||
"1" ((unsigned long)hypercall.arg[0]),
|
||||
"2" ((unsigned long)hypercall.arg[1]),
|
||||
"3" ((unsigned long)hypercall.arg[2]),
|
||||
"g" ((unsigned long)hypercall.arg[3]),
|
||||
"g" ((unsigned long)hypercall.arg[4])
|
||||
: "r11","rcx","r8","r10","memory");
|
||||
}
|
||||
{
|
||||
long ign1, ign2, ign3;
|
||||
__asm__ __volatile__ (
|
||||
"movq %8,%%r10; movq %9,%%r8;" TRAP_INSTR
|
||||
: "=a" (ret), "=D" (ign1),
|
||||
"=S" (ign2), "=d" (ign3)
|
||||
: "0" ((unsigned long)hypercall.op),
|
||||
"1" ((unsigned long)hypercall.arg[0]),
|
||||
"2" ((unsigned long)hypercall.arg[1]),
|
||||
"3" ((unsigned long)hypercall.arg[2]),
|
||||
"g" ((unsigned long)hypercall.arg[3]),
|
||||
"g" ((unsigned long)hypercall.arg[4])
|
||||
: "r11","rcx","r8","r10","memory");
|
||||
}
|
||||
#elif defined (__ia64__)
|
||||
__asm__ __volatile__ (
|
||||
";; mov r14=%2; mov r15=%3; mov r16=%4; mov r17=%5; mov r18=%6;"
|
||||
"mov r2=%1; break 0x1000;; mov %0=r8 ;;"
|
||||
: "=r" (ret)
|
||||
: "r" (hypercall.op),
|
||||
"r" (hypercall.arg[0]),
|
||||
"r" (hypercall.arg[1]),
|
||||
"r" (hypercall.arg[2]),
|
||||
"r" (hypercall.arg[3]),
|
||||
"r" (hypercall.arg[4])
|
||||
: "r14","r15","r16","r17","r18","r2","r8","memory");
|
||||
__asm__ __volatile__ (
|
||||
";; mov r14=%2; mov r15=%3; "
|
||||
"mov r16=%4; mov r17=%5; mov r18=%6;"
|
||||
"mov r2=%1; break 0x1000;; mov %0=r8 ;;"
|
||||
: "=r" (ret)
|
||||
: "r" (hypercall.op),
|
||||
"r" (hypercall.arg[0]),
|
||||
"r" (hypercall.arg[1]),
|
||||
"r" (hypercall.arg[2]),
|
||||
"r" (hypercall.arg[3]),
|
||||
"r" (hypercall.arg[4])
|
||||
: "r14","r15","r16","r17","r18","r2","r8","memory");
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
#if defined(CONFIG_XEN_PRIVILEGED_GUEST)
|
||||
case IOCTL_PRIVCMD_MMAP:
|
||||
{
|
||||
case IOCTL_PRIVCMD_MMAP: {
|
||||
#define PRIVCMD_MMAP_SZ 32
|
||||
privcmd_mmap_t mmapcmd;
|
||||
privcmd_mmap_entry_t msg[PRIVCMD_MMAP_SZ], *p;
|
||||
int i, rc;
|
||||
privcmd_mmap_t mmapcmd;
|
||||
privcmd_mmap_entry_t msg[PRIVCMD_MMAP_SZ], *p;
|
||||
int i, rc;
|
||||
|
||||
if ( copy_from_user(&mmapcmd, (void *)data, sizeof(mmapcmd)) )
|
||||
return -EFAULT;
|
||||
if (copy_from_user(&mmapcmd, (void *)data, sizeof(mmapcmd)))
|
||||
return -EFAULT;
|
||||
|
||||
p = mmapcmd.entry;
|
||||
p = mmapcmd.entry;
|
||||
|
||||
for (i=0; i<mmapcmd.num; i+=PRIVCMD_MMAP_SZ, p+=PRIVCMD_MMAP_SZ)
|
||||
{
|
||||
int j, n = ((mmapcmd.num-i)>PRIVCMD_MMAP_SZ)?
|
||||
PRIVCMD_MMAP_SZ:(mmapcmd.num-i);
|
||||
for (i = 0; i < mmapcmd.num;
|
||||
i += PRIVCMD_MMAP_SZ, p += PRIVCMD_MMAP_SZ) {
|
||||
int j, n = ((mmapcmd.num-i)>PRIVCMD_MMAP_SZ)?
|
||||
PRIVCMD_MMAP_SZ:(mmapcmd.num-i);
|
||||
|
||||
|
||||
if ( copy_from_user(&msg, p, n*sizeof(privcmd_mmap_entry_t)) )
|
||||
return -EFAULT;
|
||||
if (copy_from_user(&msg, p,
|
||||
n*sizeof(privcmd_mmap_entry_t)))
|
||||
return -EFAULT;
|
||||
|
||||
for ( j = 0; j < n; j++ )
|
||||
{
|
||||
struct vm_area_struct *vma =
|
||||
find_vma( current->mm, msg[j].va );
|
||||
for (j = 0; j < n; j++) {
|
||||
struct vm_area_struct *vma =
|
||||
find_vma( current->mm, msg[j].va );
|
||||
|
||||
if ( !vma )
|
||||
return -EINVAL;
|
||||
if (!vma)
|
||||
return -EINVAL;
|
||||
|
||||
if ( msg[j].va > PAGE_OFFSET )
|
||||
return -EINVAL;
|
||||
if (msg[j].va > PAGE_OFFSET)
|
||||
return -EINVAL;
|
||||
|
||||
if ( (msg[j].va + (msg[j].npages<<PAGE_SHIFT)) > vma->vm_end )
|
||||
return -EINVAL;
|
||||
if ((msg[j].va + (msg[j].npages << PAGE_SHIFT))
|
||||
> vma->vm_end )
|
||||
return -EINVAL;
|
||||
|
||||
if ( (rc = direct_remap_pfn_range(vma,
|
||||
msg[j].va&PAGE_MASK,
|
||||
msg[j].mfn,
|
||||
msg[j].npages<<PAGE_SHIFT,
|
||||
vma->vm_page_prot,
|
||||
mmapcmd.dom)) < 0 )
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
if ((rc = direct_remap_pfn_range(
|
||||
vma,
|
||||
msg[j].va&PAGE_MASK,
|
||||
msg[j].mfn,
|
||||
msg[j].npages<<PAGE_SHIFT,
|
||||
vma->vm_page_prot,
|
||||
mmapcmd.dom)) < 0)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case IOCTL_PRIVCMD_MMAPBATCH:
|
||||
{
|
||||
mmu_update_t u;
|
||||
privcmd_mmapbatch_t m;
|
||||
struct vm_area_struct *vma = NULL;
|
||||
unsigned long *p, addr;
|
||||
unsigned long mfn, ptep;
|
||||
int i;
|
||||
case IOCTL_PRIVCMD_MMAPBATCH: {
|
||||
mmu_update_t u;
|
||||
privcmd_mmapbatch_t m;
|
||||
struct vm_area_struct *vma = NULL;
|
||||
unsigned long *p, addr;
|
||||
unsigned long mfn, ptep;
|
||||
int i;
|
||||
|
||||
if ( copy_from_user(&m, (void *)data, sizeof(m)) )
|
||||
{ ret = -EFAULT; goto batch_err; }
|
||||
if (copy_from_user(&m, (void *)data, sizeof(m))) {
|
||||
ret = -EFAULT;
|
||||
goto batch_err;
|
||||
}
|
||||
|
||||
vma = find_vma( current->mm, m.addr );
|
||||
vma = find_vma( current->mm, m.addr );
|
||||
if (!vma) {
|
||||
ret = -EINVAL;
|
||||
goto batch_err;
|
||||
}
|
||||
|
||||
if ( !vma )
|
||||
{ ret = -EINVAL; goto batch_err; }
|
||||
if (m.addr > PAGE_OFFSET) {
|
||||
ret = -EFAULT;
|
||||
goto batch_err;
|
||||
}
|
||||
|
||||
if ( m.addr > PAGE_OFFSET )
|
||||
{ ret = -EFAULT; goto batch_err; }
|
||||
if ((m.addr + (m.num<<PAGE_SHIFT)) > vma->vm_end) {
|
||||
ret = -EFAULT;
|
||||
goto batch_err;
|
||||
}
|
||||
|
||||
if ( (m.addr + (m.num<<PAGE_SHIFT)) > vma->vm_end )
|
||||
{ ret = -EFAULT; goto batch_err; }
|
||||
p = m.arr;
|
||||
addr = m.addr;
|
||||
for (i = 0; i < m.num; i++, addr += PAGE_SIZE, p++) {
|
||||
if (get_user(mfn, p))
|
||||
return -EFAULT;
|
||||
|
||||
p = m.arr;
|
||||
addr = m.addr;
|
||||
for ( i = 0; i < m.num; i++, addr += PAGE_SIZE, p++ )
|
||||
{
|
||||
if ( get_user(mfn, p) )
|
||||
return -EFAULT;
|
||||
ret = create_lookup_pte_addr(vma->vm_mm, addr, &ptep);
|
||||
if (ret)
|
||||
goto batch_err;
|
||||
|
||||
ret = create_lookup_pte_addr(vma->vm_mm, addr, &ptep);
|
||||
if (ret)
|
||||
goto batch_err;
|
||||
u.val = pte_val_ma(pfn_pte_ma(mfn, vma->vm_page_prot));
|
||||
u.ptr = ptep;
|
||||
|
||||
u.val = pte_val_ma(pfn_pte_ma(mfn, vma->vm_page_prot));
|
||||
u.ptr = ptep;
|
||||
if (HYPERVISOR_mmu_update(&u, 1, NULL, m.dom) < 0)
|
||||
put_user(0xF0000000 | mfn, p);
|
||||
}
|
||||
|
||||
if ( unlikely(HYPERVISOR_mmu_update(&u, 1, NULL, m.dom) < 0) )
|
||||
put_user(0xF0000000 | mfn, p);
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
batch_err:
|
||||
printk("batch_err ret=%d vma=%p addr=%lx num=%d arr=%p %lx-%lx\n",
|
||||
ret, vma, m.addr, m.num, m.arr,
|
||||
vma ? vma->vm_start : 0, vma ? vma->vm_end : 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
batch_err:
|
||||
printk("batch_err ret=%d vma=%p addr=%lx "
|
||||
"num=%d arr=%p %lx-%lx\n",
|
||||
ret, vma, m.addr, m.num, m.arr,
|
||||
vma ? vma->vm_start : 0, vma ? vma->vm_end : 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case IOCTL_PRIVCMD_GET_MACH2PHYS_START_MFN:
|
||||
{
|
||||
unsigned long m2pv = (unsigned long)machine_to_phys_mapping;
|
||||
pgd_t *pgd = pgd_offset_k(m2pv);
|
||||
pud_t *pud = pud_offset(pgd, m2pv);
|
||||
pmd_t *pmd = pmd_offset(pud, m2pv);
|
||||
unsigned long m2p_start_mfn = (*(unsigned long *)pmd) >> PAGE_SHIFT;
|
||||
ret = put_user(m2p_start_mfn, (unsigned long *)data) ? -EFAULT: 0;
|
||||
}
|
||||
break;
|
||||
case IOCTL_PRIVCMD_GET_MACH2PHYS_START_MFN: {
|
||||
unsigned long m2pv = (unsigned long)machine_to_phys_mapping;
|
||||
pgd_t *pgd = pgd_offset_k(m2pv);
|
||||
pud_t *pud = pud_offset(pgd, m2pv);
|
||||
pmd_t *pmd = pmd_offset(pud, m2pv);
|
||||
unsigned long m2p_start_mfn =
|
||||
(*(unsigned long *)pmd) >> PAGE_SHIFT;
|
||||
ret = put_user(m2p_start_mfn, (unsigned long *)data) ?
|
||||
-EFAULT: 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case IOCTL_PRIVCMD_INITDOMAIN_STORE:
|
||||
{
|
||||
extern int do_xenbus_probe(void*);
|
||||
unsigned long page;
|
||||
case IOCTL_PRIVCMD_INITDOMAIN_STORE: {
|
||||
extern int do_xenbus_probe(void*);
|
||||
unsigned long page;
|
||||
|
||||
if (xen_start_info->store_evtchn != 0) {
|
||||
ret = xen_start_info->store_mfn;
|
||||
break;
|
||||
}
|
||||
if (xen_start_info->store_evtchn != 0) {
|
||||
ret = xen_start_info->store_mfn;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Allocate page. */
|
||||
page = get_zeroed_page(GFP_KERNEL);
|
||||
if (!page) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
/* Allocate page. */
|
||||
page = get_zeroed_page(GFP_KERNEL);
|
||||
if (!page) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
/* We don't refcnt properly, so set reserved on page.
|
||||
* (this allocation is permanent) */
|
||||
SetPageReserved(virt_to_page(page));
|
||||
/* We don't refcnt properly, so set reserved on page.
|
||||
* (this allocation is permanent) */
|
||||
SetPageReserved(virt_to_page(page));
|
||||
|
||||
/* Initial connect. Setup channel and page. */
|
||||
xen_start_info->store_evtchn = data;
|
||||
xen_start_info->store_mfn = pfn_to_mfn(virt_to_phys((void *)page) >>
|
||||
PAGE_SHIFT);
|
||||
ret = xen_start_info->store_mfn;
|
||||
/* Initial connect. Setup channel and page. */
|
||||
xen_start_info->store_evtchn = data;
|
||||
xen_start_info->store_mfn =
|
||||
pfn_to_mfn(virt_to_phys((void *)page) >>
|
||||
PAGE_SHIFT);
|
||||
ret = xen_start_info->store_mfn;
|
||||
|
||||
/* We'll return then this will wait for daemon to answer */
|
||||
kthread_run(do_xenbus_probe, NULL, "xenbus_probe");
|
||||
}
|
||||
break;
|
||||
/* We'll return then this will wait for daemon to answer */
|
||||
kthread_run(do_xenbus_probe, NULL, "xenbus_probe");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int privcmd_mmap(struct file * file, struct vm_area_struct * vma)
|
||||
{
|
||||
/* DONTCOPY is essential for Xen as copy_page_range is broken. */
|
||||
vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
|
||||
/* DONTCOPY is essential for Xen as copy_page_range is broken. */
|
||||
vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_operations privcmd_file_ops = {
|
||||
.ioctl = privcmd_ioctl,
|
||||
.mmap = privcmd_mmap,
|
||||
.ioctl = privcmd_ioctl,
|
||||
.mmap = privcmd_mmap,
|
||||
};
|
||||
|
||||
|
||||
static int __init privcmd_init(void)
|
||||
{
|
||||
privcmd_intf = create_xen_proc_entry("privcmd", 0400);
|
||||
if ( privcmd_intf != NULL )
|
||||
privcmd_intf->proc_fops = &privcmd_file_ops;
|
||||
privcmd_intf = create_xen_proc_entry("privcmd", 0400);
|
||||
if (privcmd_intf != NULL)
|
||||
privcmd_intf->proc_fops = &privcmd_file_ops;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__initcall(privcmd_init);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -84,3 +84,13 @@ extern int num_frontends;
|
||||
#define MMAP_VADDR(t,_req) ((t)->mmap_vstart + ((_req) * PAGE_SIZE))
|
||||
|
||||
#endif /* __TPMIF__BACKEND__COMMON_H__ */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -566,7 +566,7 @@ vtpm_op_read(struct file *file,
|
||||
* the more time we give the TPM to process the request.
|
||||
*/
|
||||
mod_timer(&pak->processing_timer,
|
||||
jiffies + (num_frontends * 10 * HZ));
|
||||
jiffies + (num_frontends * 60 * HZ));
|
||||
dataex.copied_so_far = 0;
|
||||
}
|
||||
}
|
||||
@@ -850,7 +850,7 @@ static int vtpm_queue_packet(struct packet *pak)
|
||||
write_lock_irqsave(&dataex.pak_lock, flags);
|
||||
list_add_tail(&pak->next, &dataex.pending_pak);
|
||||
/* give the TPM some time to pick up the request */
|
||||
mod_timer(&pak->processing_timer, jiffies + (10 * HZ));
|
||||
mod_timer(&pak->processing_timer, jiffies + (30 * HZ));
|
||||
write_unlock_irqrestore(&dataex.pak_lock,
|
||||
flags);
|
||||
|
||||
@@ -1075,3 +1075,13 @@ tpmback_init(void)
|
||||
}
|
||||
|
||||
__initcall(tpmback_init);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -268,3 +268,13 @@ void tpmif_xenbus_init(void)
|
||||
{
|
||||
xenbus_register_backend(&tpmback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -741,3 +741,13 @@ tpmif_init(void)
|
||||
}
|
||||
|
||||
__initcall(tpmif_init);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -38,3 +38,13 @@ struct tx_buffer
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -1,84 +0,0 @@
|
||||
|
||||
#ifndef __USBIF__BACKEND__COMMON_H__
|
||||
#define __USBIF__BACKEND__COMMON_H__
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/hypervisor.h>
|
||||
#include <asm-xen/driver_util.h>
|
||||
#include <asm-xen/xen-public/io/usbif.h>
|
||||
|
||||
#if 0
|
||||
#define ASSERT(_p) \
|
||||
if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
|
||||
__LINE__, __FILE__); *(int*)0=0; }
|
||||
#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \
|
||||
__FILE__ , __LINE__ , ## _a )
|
||||
#else
|
||||
#define ASSERT(_p) ((void)0)
|
||||
#define DPRINTK(_f, _a...) ((void)0)
|
||||
#endif
|
||||
|
||||
typedef struct usbif_priv_st usbif_priv_t;
|
||||
|
||||
struct usbif_priv_st {
|
||||
/* Unique identifier for this interface. */
|
||||
domid_t domid;
|
||||
unsigned int handle;
|
||||
/* Physical parameters of the comms window. */
|
||||
unsigned long shmem_frame;
|
||||
unsigned int evtchn;
|
||||
/* Comms Information */
|
||||
usbif_back_ring_t usb_ring;
|
||||
struct vm_struct *usb_ring_area;
|
||||
/* Private fields. */
|
||||
enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
|
||||
/*
|
||||
* DISCONNECT response is deferred until pending requests are ack'ed.
|
||||
* We therefore need to store the id from the original request.
|
||||
*/
|
||||
u8 disconnect_rspid;
|
||||
usbif_priv_t *hash_next;
|
||||
struct list_head usbif_list;
|
||||
spinlock_t usb_ring_lock;
|
||||
atomic_t refcnt;
|
||||
|
||||
struct work_struct work;
|
||||
};
|
||||
|
||||
void usbif_create(usbif_be_create_t *create);
|
||||
void usbif_destroy(usbif_be_destroy_t *destroy);
|
||||
void usbif_connect(usbif_be_connect_t *connect);
|
||||
int usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id);
|
||||
void usbif_disconnect_complete(usbif_priv_t *up);
|
||||
|
||||
void usbif_release_port(usbif_be_release_port_t *msg);
|
||||
int usbif_claim_port(usbif_be_claim_port_t *msg);
|
||||
void usbif_release_ports(usbif_priv_t *up);
|
||||
|
||||
usbif_priv_t *usbif_find(domid_t domid);
|
||||
#define usbif_get(_b) (atomic_inc(&(_b)->refcnt))
|
||||
#define usbif_put(_b) \
|
||||
do { \
|
||||
if ( atomic_dec_and_test(&(_b)->refcnt) ) \
|
||||
usbif_disconnect_complete(_b); \
|
||||
} while (0)
|
||||
|
||||
|
||||
void usbif_interface_init(void);
|
||||
void usbif_ctrlif_init(void);
|
||||
|
||||
void usbif_deschedule(usbif_priv_t *up);
|
||||
void remove_from_usbif_list(usbif_priv_t *up);
|
||||
|
||||
irqreturn_t usbif_be_int(int irq, void *dev_id, struct pt_regs *regs);
|
||||
|
||||
#endif /* __USBIF__BACKEND__COMMON_H__ */
|
||||
@@ -1,61 +0,0 @@
|
||||
/******************************************************************************
|
||||
* arch/xen/drivers/usbif/backend/control.c
|
||||
*
|
||||
* Routines for interfacing with the control plane.
|
||||
*
|
||||
* Copyright (c) 2004, Keir Fraser
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static void usbif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
|
||||
{
|
||||
DPRINTK("Received usbif backend message, subtype=%d\n", msg->subtype);
|
||||
|
||||
switch ( msg->subtype )
|
||||
{
|
||||
case CMSG_USBIF_BE_CREATE:
|
||||
usbif_create((usbif_be_create_t *)&msg->msg[0]);
|
||||
break;
|
||||
case CMSG_USBIF_BE_DESTROY:
|
||||
usbif_destroy((usbif_be_destroy_t *)&msg->msg[0]);
|
||||
break;
|
||||
case CMSG_USBIF_BE_CONNECT:
|
||||
usbif_connect((usbif_be_connect_t *)&msg->msg[0]);
|
||||
break;
|
||||
case CMSG_USBIF_BE_DISCONNECT:
|
||||
if ( !usbif_disconnect((usbif_be_disconnect_t *)&msg->msg[0],msg->id) )
|
||||
return; /* Sending the response is deferred until later. */
|
||||
break;
|
||||
case CMSG_USBIF_BE_CLAIM_PORT:
|
||||
usbif_claim_port((usbif_be_claim_port_t *)&msg->msg[0]);
|
||||
break;
|
||||
case CMSG_USBIF_BE_RELEASE_PORT:
|
||||
usbif_release_port((usbif_be_release_port_t *)&msg->msg[0]);
|
||||
break;
|
||||
default:
|
||||
DPRINTK("Parse error while reading message subtype %d, len %d\n",
|
||||
msg->subtype, msg->length);
|
||||
msg->length = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ctrl_if_send_response(msg);
|
||||
}
|
||||
|
||||
void usbif_ctrlif_init(void)
|
||||
{
|
||||
ctrl_msg_t cmsg;
|
||||
usbif_be_driver_status_changed_t st;
|
||||
|
||||
(void)ctrl_if_register_receiver(CMSG_USBIF_BE, usbif_ctrlif_rx,
|
||||
CALLBACK_IN_BLOCKING_CONTEXT);
|
||||
|
||||
/* Send a driver-UP notification to the domain controller. */
|
||||
cmsg.type = CMSG_USBIF_BE;
|
||||
cmsg.subtype = CMSG_USBIF_BE_DRIVER_STATUS_CHANGED;
|
||||
cmsg.length = sizeof(usbif_be_driver_status_changed_t);
|
||||
st.status = USBIF_DRIVER_STATUS_UP;
|
||||
memcpy(cmsg.msg, &st, sizeof(st));
|
||||
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
@@ -1,241 +0,0 @@
|
||||
/******************************************************************************
|
||||
* arch/xen/drivers/usbif/backend/interface.c
|
||||
*
|
||||
* USB device interface management.
|
||||
*
|
||||
* by Mark Williamson, Copyright (c) 2004
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define USBIF_HASHSZ 1024
|
||||
#define USBIF_HASH(_d) (((int)(_d))&(USBIF_HASHSZ-1))
|
||||
|
||||
static kmem_cache_t *usbif_priv_cachep;
|
||||
static usbif_priv_t *usbif_priv_hash[USBIF_HASHSZ];
|
||||
|
||||
usbif_priv_t *usbif_find(domid_t domid)
|
||||
{
|
||||
usbif_priv_t *up = usbif_priv_hash[USBIF_HASH(domid)];
|
||||
while ( (up != NULL ) && ( up->domid != domid ) )
|
||||
up = up->hash_next;
|
||||
return up;
|
||||
}
|
||||
|
||||
static void __usbif_disconnect_complete(void *arg)
|
||||
{
|
||||
usbif_priv_t *usbif = (usbif_priv_t *)arg;
|
||||
ctrl_msg_t cmsg;
|
||||
usbif_be_disconnect_t disc;
|
||||
|
||||
/*
|
||||
* These can't be done in usbif_disconnect() because at that point there
|
||||
* may be outstanding requests at the device whose asynchronous responses
|
||||
* must still be notified to the remote driver.
|
||||
*/
|
||||
free_vm_area(usbif->usb_ring_area);
|
||||
|
||||
/* Construct the deferred response message. */
|
||||
cmsg.type = CMSG_USBIF_BE;
|
||||
cmsg.subtype = CMSG_USBIF_BE_DISCONNECT;
|
||||
cmsg.id = usbif->disconnect_rspid;
|
||||
cmsg.length = sizeof(usbif_be_disconnect_t);
|
||||
disc.domid = usbif->domid;
|
||||
disc.status = USBIF_BE_STATUS_OKAY;
|
||||
memcpy(cmsg.msg, &disc, sizeof(disc));
|
||||
|
||||
/*
|
||||
* Make sure message is constructed /before/ status change, because
|
||||
* after the status change the 'usbif' structure could be deallocated at
|
||||
* any time. Also make sure we send the response /after/ status change,
|
||||
* as otherwise a subsequent CONNECT request could spuriously fail if
|
||||
* another CPU doesn't see the status change yet.
|
||||
*/
|
||||
mb();
|
||||
if ( usbif->status != DISCONNECTING )
|
||||
BUG();
|
||||
usbif->status = DISCONNECTED;
|
||||
mb();
|
||||
|
||||
/* Send the successful response. */
|
||||
ctrl_if_send_response(&cmsg);
|
||||
}
|
||||
|
||||
void usbif_disconnect_complete(usbif_priv_t *up)
|
||||
{
|
||||
INIT_WORK(&up->work, __usbif_disconnect_complete, (void *)up);
|
||||
schedule_work(&up->work);
|
||||
}
|
||||
|
||||
void usbif_create(usbif_be_create_t *create)
|
||||
{
|
||||
domid_t domid = create->domid;
|
||||
usbif_priv_t **pup, *up;
|
||||
|
||||
if ( (up = kmem_cache_alloc(usbif_priv_cachep, GFP_KERNEL)) == NULL )
|
||||
{
|
||||
DPRINTK("Could not create usbif: out of memory\n");
|
||||
create->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
memset(up, 0, sizeof(*up));
|
||||
up->domid = domid;
|
||||
up->status = DISCONNECTED;
|
||||
spin_lock_init(&up->usb_ring_lock);
|
||||
atomic_set(&up->refcnt, 0);
|
||||
|
||||
pup = &usbif_priv_hash[USBIF_HASH(domid)];
|
||||
while ( *pup != NULL )
|
||||
{
|
||||
if ( (*pup)->domid == domid )
|
||||
{
|
||||
create->status = USBIF_BE_STATUS_INTERFACE_EXISTS;
|
||||
kmem_cache_free(usbif_priv_cachep, up);
|
||||
return;
|
||||
}
|
||||
pup = &(*pup)->hash_next;
|
||||
}
|
||||
|
||||
up->hash_next = *pup;
|
||||
*pup = up;
|
||||
|
||||
create->status = USBIF_BE_STATUS_OKAY;
|
||||
}
|
||||
|
||||
void usbif_destroy(usbif_be_destroy_t *destroy)
|
||||
{
|
||||
domid_t domid = destroy->domid;
|
||||
usbif_priv_t **pup, *up;
|
||||
|
||||
pup = &usbif_priv_hash[USBIF_HASH(domid)];
|
||||
while ( (up = *pup) != NULL )
|
||||
{
|
||||
if ( up->domid == domid )
|
||||
{
|
||||
if ( up->status != DISCONNECTED )
|
||||
goto still_connected;
|
||||
goto destroy;
|
||||
}
|
||||
pup = &up->hash_next;
|
||||
}
|
||||
|
||||
destroy->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
|
||||
return;
|
||||
|
||||
still_connected:
|
||||
destroy->status = USBIF_BE_STATUS_INTERFACE_CONNECTED;
|
||||
return;
|
||||
|
||||
destroy:
|
||||
*pup = up->hash_next;
|
||||
usbif_release_ports(up);
|
||||
kmem_cache_free(usbif_priv_cachep, up);
|
||||
destroy->status = USBIF_BE_STATUS_OKAY;
|
||||
}
|
||||
|
||||
void usbif_connect(usbif_be_connect_t *connect)
|
||||
{
|
||||
domid_t domid = connect->domid;
|
||||
unsigned int evtchn = connect->evtchn;
|
||||
unsigned long shmem_frame = connect->shmem_frame;
|
||||
pgprot_t prot;
|
||||
int error;
|
||||
usbif_priv_t *up;
|
||||
usbif_sring_t *sring;
|
||||
|
||||
up = usbif_find(domid);
|
||||
if ( unlikely(up == NULL) )
|
||||
{
|
||||
DPRINTK("usbif_connect attempted for non-existent usbif (%u)\n",
|
||||
connect->domid);
|
||||
connect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (up->usb_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
|
||||
{
|
||||
connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
|
||||
return;
|
||||
}
|
||||
|
||||
prot = __pgprot(_KERNPG_TABLE);
|
||||
error = direct_remap_pfn_range(&init_mm, AREALLOC_AREADDR(area->addr),
|
||||
shmem_frame, PAGE_SIZE,
|
||||
prot, domid);
|
||||
if ( error != 0 )
|
||||
{
|
||||
if ( error == -ENOMEM )
|
||||
connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
|
||||
else if ( error == -EFAULT )
|
||||
connect->status = USBIF_BE_STATUS_MAPPING_ERROR;
|
||||
else
|
||||
connect->status = USBIF_BE_STATUS_ERROR;
|
||||
free_vm_area(up->usb_ring_area);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( up->status != DISCONNECTED )
|
||||
{
|
||||
connect->status = USBIF_BE_STATUS_INTERFACE_CONNECTED;
|
||||
free_vm_area(up->usb_ring_area);
|
||||
return;
|
||||
}
|
||||
|
||||
sring = (usbif_sring_t *)area->addr;
|
||||
SHARED_RING_INIT(sring);
|
||||
BACK_RING_INIT(&up->usb_ring, sring, PAGE_SIZE);
|
||||
|
||||
up->evtchn = evtchn;
|
||||
up->shmem_frame = shmem_frame;
|
||||
up->status = CONNECTED;
|
||||
usbif_get(up);
|
||||
|
||||
(void)bind_evtchn_to_irqhandler(
|
||||
evtchn, usbif_be_int, 0, "usbif-backend", up);
|
||||
|
||||
connect->status = USBIF_BE_STATUS_OKAY;
|
||||
}
|
||||
|
||||
/* Remove URBs for this interface before destroying it. */
|
||||
void usbif_deschedule(usbif_priv_t *up)
|
||||
{
|
||||
remove_from_usbif_list(up);
|
||||
}
|
||||
|
||||
int usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id)
|
||||
{
|
||||
domid_t domid = disconnect->domid;
|
||||
usbif_priv_t *up;
|
||||
|
||||
up = usbif_find(domid);
|
||||
if ( unlikely(up == NULL) )
|
||||
{
|
||||
DPRINTK("usbif_disconnect attempted for non-existent usbif"
|
||||
" (%u)\n", disconnect->domid);
|
||||
disconnect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
|
||||
return 1; /* Caller will send response error message. */
|
||||
}
|
||||
|
||||
if ( up->status == CONNECTED )
|
||||
{
|
||||
up->status = DISCONNECTING;
|
||||
up->disconnect_rspid = rsp_id;
|
||||
wmb(); /* Let other CPUs see the status change. */
|
||||
unbind_evtchn_from_irqhandler(up->evtchn, up);
|
||||
usbif_deschedule(up);
|
||||
usbif_put(up);
|
||||
return 0; /* Caller should not send response message. */
|
||||
}
|
||||
|
||||
disconnect->status = USBIF_BE_STATUS_OKAY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void __init usbif_interface_init(void)
|
||||
{
|
||||
usbif_priv_cachep = kmem_cache_create("usbif_priv_cache",
|
||||
sizeof(usbif_priv_t),
|
||||
0, 0, NULL, NULL);
|
||||
memset(usbif_priv_hash, 0, sizeof(usbif_priv_hash));
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,182 +0,0 @@
|
||||
/******************************************************************************
|
||||
* xhci.h
|
||||
*
|
||||
* Private definitions for the Xen Virtual USB Controller. Based on
|
||||
* drivers/usb/host/uhci.h from Linux. Copyright for the imported content is
|
||||
* retained by the original authors.
|
||||
*
|
||||
* Modifications are:
|
||||
* Copyright (C) 2004 Intel Research Cambridge
|
||||
* Copyright (C) 2004, 2005 Mark Williamson
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_XHCI_H
|
||||
#define __LINUX_XHCI_H
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/usb.h>
|
||||
#include <asm-xen/xen-public/io/usbif.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
/* xhci_port_t - current known state of a virtual hub ports */
|
||||
typedef struct {
|
||||
unsigned int cs :1; /* Connection status. */
|
||||
unsigned int cs_chg :1; /* Connection status change. */
|
||||
unsigned int pe :1; /* Port enable. */
|
||||
unsigned int pe_chg :1; /* Port enable change. */
|
||||
unsigned int susp :1; /* Suspended. */
|
||||
unsigned int lsda :1; /* Low speed device attached. */
|
||||
unsigned int pr :1; /* Port reset. */
|
||||
} xhci_port_t;
|
||||
|
||||
/* struct virt_root_hub - state related to the virtual root hub */
|
||||
struct virt_root_hub {
|
||||
struct usb_device *dev;
|
||||
int devnum; /* Address of Root Hub endpoint */
|
||||
struct urb *urb;
|
||||
void *int_addr;
|
||||
int send;
|
||||
int interval;
|
||||
int numports;
|
||||
int c_p_r[8];
|
||||
struct timer_list rh_int_timer;
|
||||
spinlock_t port_state_lock;
|
||||
xhci_port_t *ports;
|
||||
};
|
||||
|
||||
/* struct xhci - contains the state associated with a single USB interface */
|
||||
struct xhci {
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
/* procfs */
|
||||
int num;
|
||||
struct proc_dir_entry *proc_entry;
|
||||
#endif
|
||||
|
||||
int evtchn; /* Interdom channel to backend */
|
||||
enum {
|
||||
USBIF_STATE_CONNECTED = 2,
|
||||
USBIF_STATE_DISCONNECTED = 1,
|
||||
USBIF_STATE_CLOSED = 0
|
||||
} state; /* State of this USB interface */
|
||||
unsigned long recovery; /* boolean recovery in progress flag */
|
||||
|
||||
unsigned long bandwidth;
|
||||
|
||||
struct usb_bus *bus;
|
||||
|
||||
/* Main list of URB's currently controlled by this HC */
|
||||
spinlock_t urb_list_lock;
|
||||
struct list_head urb_list; /* P: xhci->urb_list_lock */
|
||||
|
||||
/* List of URB's awaiting completion callback */
|
||||
spinlock_t complete_list_lock;
|
||||
struct list_head complete_list; /* P: xhci->complete_list_lock */
|
||||
|
||||
struct virt_root_hub rh; /* private data of the virtual root hub */
|
||||
|
||||
spinlock_t ring_lock;
|
||||
usbif_front_ring_t usb_ring;
|
||||
|
||||
int awaiting_reset;
|
||||
};
|
||||
|
||||
/* per-URB private data structure for the host controller */
|
||||
struct urb_priv {
|
||||
struct urb *urb;
|
||||
usbif_iso_t *schedule;
|
||||
struct usb_device *dev;
|
||||
|
||||
int in_progress : 1; /* QH was queued (not linked in) */
|
||||
int short_control_packet : 1; /* If we get a short packet during */
|
||||
/* a control transfer, retrigger */
|
||||
/* the status phase */
|
||||
|
||||
int status; /* Final status */
|
||||
|
||||
unsigned long inserttime; /* In jiffies */
|
||||
|
||||
struct list_head complete_list; /* P: xhci->complete_list_lock */
|
||||
};
|
||||
|
||||
/*
|
||||
* Locking in xhci.c
|
||||
*
|
||||
* spinlocks are used extensively to protect the many lists and data
|
||||
* structures we have. It's not that pretty, but it's necessary. We
|
||||
* need to be done with all of the locks (except complete_list_lock) when
|
||||
* we call urb->complete. I've tried to make it simple enough so I don't
|
||||
* have to spend hours racking my brain trying to figure out if the
|
||||
* locking is safe.
|
||||
*
|
||||
* Here's the safe locking order to prevent deadlocks:
|
||||
*
|
||||
* #1 xhci->urb_list_lock
|
||||
* #2 urb->lock
|
||||
* #3 xhci->urb_remove_list_lock
|
||||
* #4 xhci->complete_list_lock
|
||||
*
|
||||
* If you're going to grab 2 or more locks at once, ALWAYS grab the lock
|
||||
* at the lowest level FIRST and NEVER grab locks at the same level at the
|
||||
* same time.
|
||||
*
|
||||
* So, if you need xhci->urb_list_lock, grab it before you grab urb->lock
|
||||
*/
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Virtual Root HUB
|
||||
------------------------------------------------------------------------- */
|
||||
/* destination of request */
|
||||
#define RH_DEVICE 0x00
|
||||
#define RH_INTERFACE 0x01
|
||||
#define RH_ENDPOINT 0x02
|
||||
#define RH_OTHER 0x03
|
||||
|
||||
#define RH_CLASS 0x20
|
||||
#define RH_VENDOR 0x40
|
||||
|
||||
/* Requests: bRequest << 8 | bmRequestType */
|
||||
#define RH_GET_STATUS 0x0080
|
||||
#define RH_CLEAR_FEATURE 0x0100
|
||||
#define RH_SET_FEATURE 0x0300
|
||||
#define RH_SET_ADDRESS 0x0500
|
||||
#define RH_GET_DESCRIPTOR 0x0680
|
||||
#define RH_SET_DESCRIPTOR 0x0700
|
||||
#define RH_GET_CONFIGURATION 0x0880
|
||||
#define RH_SET_CONFIGURATION 0x0900
|
||||
#define RH_GET_STATE 0x0280
|
||||
#define RH_GET_INTERFACE 0x0A80
|
||||
#define RH_SET_INTERFACE 0x0B00
|
||||
#define RH_SYNC_FRAME 0x0C80
|
||||
/* Our Vendor Specific Request */
|
||||
#define RH_SET_EP 0x2000
|
||||
|
||||
/* Hub port features */
|
||||
#define RH_PORT_CONNECTION 0x00
|
||||
#define RH_PORT_ENABLE 0x01
|
||||
#define RH_PORT_SUSPEND 0x02
|
||||
#define RH_PORT_OVER_CURRENT 0x03
|
||||
#define RH_PORT_RESET 0x04
|
||||
#define RH_PORT_POWER 0x08
|
||||
#define RH_PORT_LOW_SPEED 0x09
|
||||
#define RH_C_PORT_CONNECTION 0x10
|
||||
#define RH_C_PORT_ENABLE 0x11
|
||||
#define RH_C_PORT_SUSPEND 0x12
|
||||
#define RH_C_PORT_OVER_CURRENT 0x13
|
||||
#define RH_C_PORT_RESET 0x14
|
||||
|
||||
/* Hub features */
|
||||
#define RH_C_HUB_LOCAL_POWER 0x00
|
||||
#define RH_C_HUB_OVER_CURRENT 0x01
|
||||
#define RH_DEVICE_REMOTE_WAKEUP 0x00
|
||||
#define RH_ENDPOINT_STALL 0x01
|
||||
|
||||
/* Our Vendor Specific feature */
|
||||
#define RH_REMOVE_EP 0x00
|
||||
|
||||
#define RH_ACK 0x01
|
||||
#define RH_REQ_ERR -1
|
||||
#define RH_NACK 0x00
|
||||
|
||||
#endif
|
||||
|
||||
@@ -231,3 +231,13 @@ void xb_suspend_comms(void)
|
||||
|
||||
unbind_evtchn_from_irqhandler(xen_start_info->store_evtchn, &xb_waitq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -39,3 +39,13 @@ int xs_input_avail(void);
|
||||
extern wait_queue_head_t xb_waitq;
|
||||
|
||||
#endif /* _XENBUS_COMMS_H */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -186,3 +186,13 @@ xenbus_dev_init(void)
|
||||
}
|
||||
|
||||
__initcall(xenbus_dev_init);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -687,3 +687,13 @@ static int __init xenbus_probe_init(void)
|
||||
}
|
||||
|
||||
postcore_initcall(xenbus_probe_init);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -566,3 +566,13 @@ int xs_init(void)
|
||||
return PTR_ERR(watcher);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -305,6 +305,13 @@ class XendDomain:
|
||||
|
||||
@param vmconfig: vm configuration
|
||||
"""
|
||||
# We accept our configuration specified as ['config' [...]], which
|
||||
# some tools or configuration files may be using. For save-restore,
|
||||
# we use the value of XendDomainInfo.sxpr() directly, which has no
|
||||
# such item.
|
||||
nested = sxp.child_value(config, 'config')
|
||||
if nested:
|
||||
config = nested
|
||||
return XendDomainInfo.restore(self.dbmap.getPath(), config)
|
||||
|
||||
def domain_restore(self, src, progress=False):
|
||||
|
||||
@@ -10,10 +10,11 @@
|
||||
#define __XEN_PUBLIC_IO_NETIF_H__
|
||||
|
||||
typedef struct netif_tx_request {
|
||||
unsigned long addr; /* Machine address of packet. */
|
||||
grant_ref_t gref; /* Reference to buffer page */
|
||||
u16 offset:15; /* Offset within buffer page */
|
||||
u16 csum_blank:1; /* Proto csum field blank? */
|
||||
u16 id:15; /* Echoed in response message. */
|
||||
u16 size; /* Packet size in bytes. */
|
||||
u16 id; /* Echoed in response message. */
|
||||
u16 size; /* Packet size in bytes. */
|
||||
} netif_tx_request_t;
|
||||
|
||||
typedef struct netif_tx_response {
|
||||
@@ -22,21 +23,15 @@ typedef struct netif_tx_response {
|
||||
} netif_tx_response_t;
|
||||
|
||||
typedef struct {
|
||||
u16 id; /* Echoed in response message. */
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
grant_ref_t gref; /* 2: Reference to incoming granted frame */
|
||||
#endif
|
||||
u16 id; /* Echoed in response message. */
|
||||
grant_ref_t gref; /* Reference to incoming granted frame */
|
||||
} netif_rx_request_t;
|
||||
|
||||
typedef struct {
|
||||
#ifdef CONFIG_XEN_NETDEV_GRANT
|
||||
u32 addr; /* 0: Offset in page of start of received packet */
|
||||
#else
|
||||
unsigned long addr; /* Machine address of packet. */
|
||||
#endif
|
||||
u16 csum_valid:1; /* Protocol checksum is validated? */
|
||||
u16 id:15;
|
||||
s16 status; /* -ve: BLKIF_RSP_* ; +ve: Rx'ed pkt size. */
|
||||
u16 offset; /* Offset in page of start of received packet */
|
||||
u16 csum_valid; /* Protocol checksum is validated? */
|
||||
u16 id;
|
||||
s16 status; /* -ve: BLKIF_RSP_* ; +ve: Rx'ed pkt size. */
|
||||
} netif_rx_response_t;
|
||||
|
||||
/*
|
||||
@@ -53,18 +48,8 @@ typedef u32 NETIF_RING_IDX;
|
||||
#define MASK_NETIF_RX_IDX(_i) ((_i)&(NETIF_RX_RING_SIZE-1))
|
||||
#define MASK_NETIF_TX_IDX(_i) ((_i)&(NETIF_TX_RING_SIZE-1))
|
||||
|
||||
#ifdef __x86_64__
|
||||
/*
|
||||
* This restriction can be lifted when we move netfront/netback to use
|
||||
* grant tables. This will remove memory_t fields from the above structures
|
||||
* and thus relax natural alignment restrictions.
|
||||
*/
|
||||
#define NETIF_TX_RING_SIZE 128
|
||||
#define NETIF_RX_RING_SIZE 128
|
||||
#else
|
||||
#define NETIF_TX_RING_SIZE 256
|
||||
#define NETIF_RX_RING_SIZE 256
|
||||
#endif
|
||||
|
||||
/* This structure must fit in a memory page. */
|
||||
typedef struct netif_tx_interface {
|
||||
|
||||