diff options
author | dfr <dfr@FreeBSD.org> | 2008-11-22 16:14:52 +0000 |
---|---|---|
committer | dfr <dfr@FreeBSD.org> | 2008-11-22 16:14:52 +0000 |
commit | 19b6af98ec71398e77874582eb84ec5310c7156f (patch) | |
tree | 61eebb1b357f3edaa339d295e26a47a74534ac23 /sys/dev/xen | |
parent | 83299de5870b2dc099c17aec548d3502821bc29b (diff) | |
download | FreeBSD-src-19b6af98ec71398e77874582eb84ec5310c7156f.zip FreeBSD-src-19b6af98ec71398e77874582eb84ec5310c7156f.tar.gz |
Clone Kip's Xen on stable/6 tree so that I can work on improving FreeBSD/amd64
performance in Xen's HVM mode.
Diffstat (limited to 'sys/dev/xen')
-rw-r--r-- | sys/dev/xen/balloon/balloon.c | 446 | ||||
-rw-r--r-- | sys/dev/xen/blkback/blkback.c | 1349 | ||||
-rw-r--r-- | sys/dev/xen/blkfront/blkfront.c | 1026 | ||||
-rw-r--r-- | sys/dev/xen/blkfront/block.h | 97 | ||||
-rw-r--r-- | sys/dev/xen/console/console.c | 559 | ||||
-rw-r--r-- | sys/dev/xen/console/xencons_ring.c | 153 | ||||
-rw-r--r-- | sys/dev/xen/console/xencons_ring.h | 20 | ||||
-rw-r--r-- | sys/dev/xen/evtchn/evtchn_dev.c | 394 | ||||
-rw-r--r-- | sys/dev/xen/netback/netback.c | 1585 | ||||
-rw-r--r-- | sys/dev/xen/netfront/mbufq.h | 123 | ||||
-rw-r--r-- | sys/dev/xen/netfront/netfront.c | 1850 | ||||
-rw-r--r-- | sys/dev/xen/pcifront/pcifront.c | 688 |
12 files changed, 0 insertions, 8290 deletions
diff --git a/sys/dev/xen/balloon/balloon.c b/sys/dev/xen/balloon/balloon.c deleted file mode 100644 index fa49196..0000000 --- a/sys/dev/xen/balloon/balloon.c +++ /dev/null @@ -1,446 +0,0 @@ -/****************************************************************************** - * balloon.c - * - * Xen balloon driver - enables returning/claiming memory to/from Xen. - * - * Copyright (c) 2003, B Dragovic - * Copyright (c) 2003-2004, M Williamson, K Fraser - * Copyright (c) 2005 Dan M. Smith, IBM Corporation - * - * This file may be distributed separately from the Linux kernel, or - * incorporated into other software packages, subject to the following license: - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this source file (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/lock.h> -#include <sys/mutex.h> - -#include <machine/hypervisor-ifs.h> -#include <machine/xen-os.h> -#include <machine/xenbus.h> - -/* - * Protects atomic reservation decrease/increase against concurrent increases. - * Also protects non-atomic updates of current_pages and driver_pages, and - * balloon lists. - */ -struct mtx balloon_lock; -#ifdef notyet - -/* We aim for 'current allocation' == 'target allocation'. */ -static unsigned long current_pages; -static unsigned long target_pages; - -/* VM /proc information for memory */ -extern unsigned long totalram_pages; - -/* We may hit the hard limit in Xen. If we do then we remember it. */ -static unsigned long hard_limit; - -/* - * Drivers may alter the memory reservation independently, but they must - * inform the balloon driver so that we can avoid hitting the hard limit. - */ -static unsigned long driver_pages; - -struct balloon_entry { - vm_page_t page; - STAILQ_ENTRY(balloon_entry) list; -}; - -/* List of ballooned pages, threaded through the mem_map array. */ -static STAILQ_HEAD(,balloon_entry) ballooned_pages; - -static unsigned long balloon_low, balloon_high; - - -/* Main work function, always executed in process context. */ -static void balloon_process(void *unused); - -#define IPRINTK(fmt, args...) \ - printk(KERN_INFO "xen_mem: " fmt, ##args) -#define WPRINTK(fmt, args...) \ - printk(KERN_WARNING "xen_mem: " fmt, ##args) - -/* balloon_append: add the given page to the balloon. */ -static void -balloon_append(vm_page_t page) -{ - struct balloon_entry *entry; - - entry = malloc(sizeof(struct balloon_entry), M_WAITOK); - - STAILQ_INSERT_HEAD(&ballooned_pages, entry, list); - balloon_low++; -} - -/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */ -static vm_page_t -balloon_retrieve(void) -{ - vm_page_t page; - struct balloon_entry *entry; - - if (STAILQ_EMPTY(&ballooned_pages)) - return NULL; - - entry = STAILQ_FIRST(&ballooned_pages); - STAILQ_REMOVE_HEAD(&ballooned_pages, list); - - page = entry->page; - free(entry, M_DEVBUF); - - balloon_low--; - - return page; -} - -static void -balloon_alarm(unsigned long unused) -{ - wakeup(balloon_process); -} - -static unsigned long -current_target(void) -{ - unsigned long target = min(target_pages, hard_limit); - if (target > (current_pages + balloon_low + balloon_high)) - target = current_pages + balloon_low + balloon_high; - return target; -} - -static int -increase_reservation(unsigned long nr_pages) -{ - unsigned long *mfn_list, pfn, i, flags; - struct page *page; - long rc; - struct xen_memory_reservation reservation = { - .address_bits = 0, - .extent_order = 0, - .domid = DOMID_SELF - }; - - if (nr_pages > (PAGE_SIZE / sizeof(unsigned long))) - nr_pages = PAGE_SIZE / sizeof(unsigned long); - - mfn_list = (unsigned long *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); - if (mfn_list == NULL) - return ENOMEM; - - - reservation.extent_start = mfn_list; - reservation.nr_extents = nr_pages; - rc = HYPERVISOR_memory_op( - XENMEM_increase_reservation, &reservation); - if (rc < nr_pages) { - int ret; - /* We hit the Xen hard limit: reprobe. */ - reservation.extent_start = mfn_list; - reservation.nr_extents = rc; - ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, - &reservation); - PANIC_IF(ret != rc); - hard_limit = current_pages + rc - driver_pages; - goto out; - } - - for (i = 0; i < nr_pages; i++) { - page = balloon_retrieve(); - PANIC_IF(page == NULL); - - pfn = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT); - PANIC_IF(phys_to_machine_mapping_valid(pfn)); - - /* Update P->M and M->P tables. */ - PFNTOMFN(pfn) = mfn_list[i]; - xen_machphys_update(mfn_list[i], pfn); - - /* Relinquish the page back to the allocator. */ - ClearPageReserved(page); - set_page_count(page, 1); - vm_page_free(page); - } - - current_pages += nr_pages; - totalram_pages = current_pages; - - out: - balloon_unlock(flags); - - free((mfn_list); - - return 0; -} - -static int -decrease_reservation(unsigned long nr_pages) -{ - unsigned long *mfn_list, pfn, i, flags; - struct page *page; - void *v; - int need_sleep = 0; - int ret; - struct xen_memory_reservation reservation = { - .address_bits = 0, - .extent_order = 0, - .domid = DOMID_SELF - }; - - if (nr_pages > (PAGE_SIZE / sizeof(unsigned long))) - nr_pages = PAGE_SIZE / sizeof(unsigned long); - - mfn_list = (unsigned long *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); - if (mfn_list == NULL) - return ENOMEM; - - for (i = 0; i < nr_pages; i++) { - int color = 0; - if ((page = vm_page_alloc(NULL, color++, - VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | - VM_ALLOC_WIRED | VM_ALLOC_ZERO)) == NULL) { - nr_pages = i; - need_sleep = 1; - break; - } - pfn = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT); - mfn_list[i] = PFNTOMFN(pfn); - } - - balloon_lock(flags); - - /* No more mappings: invalidate P2M and add to balloon. */ - for (i = 0; i < nr_pages; i++) { - pfn = MFNTOPFN(mfn_list[i]); - PFNTOMFN(pfn) = INVALID_P2M_ENTRY; - balloon_append(PHYS_TO_VM_PAGE(pfn << PAGE_SHIFT)); - } - - reservation.extent_start = mfn_list; - reservation.nr_extents = nr_pages; - ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); - PANIC_IF(ret != nr_pages); - - current_pages -= nr_pages; - totalram_pages = current_pages; - - balloon_unlock(flags); - - free(mfn_list, M_DEVBUF); - - return need_sleep; -} - -/* - * We avoid multiple worker processes conflicting via the balloon mutex. - * We may of course race updates of the target counts (which are protected - * by the balloon lock), or with changes to the Xen hard limit, but we will - * recover from these in time. - */ -static void -balloon_process(void *unused) -{ - int need_sleep = 0; - long credit; - - for (;;) { - do { - credit = current_target() - current_pages; - if (credit > 0) - need_sleep = (increase_reservation(credit) != 0); - if (credit < 0) - need_sleep = (decrease_reservation(-credit) != 0); - -#ifndef CONFIG_PREEMPT - if (need_resched()) - schedule(); -#endif - } while ((credit != 0) && !need_sleep); - - /* Schedule more work if there is some still to be done. */ - if (current_target() != current_pages) - timeout(balloon_alarm, NULL, ticks + HZ); - - msleep(balloon_process, balloon_lock, 0, "balloon", -1); - } - -} - -/* Resets the Xen limit, sets new target, and kicks off processing. */ -static void -set_new_target(unsigned long target) -{ - /* No need for lock. Not read-modify-write updates. */ - hard_limit = ~0UL; - target_pages = target; - wakeup(balloon_process); -} - -static struct xenbus_watch target_watch = -{ - .node = "memory/target" -}; - -/* React to a change in the target key */ -static void -watch_target(struct xenbus_watch *watch, - const char **vec, unsigned int len) -{ - unsigned long long new_target; - int err; - - err = xenbus_scanf(NULL, "memory", "target", "%llu", &new_target); - if (err != 1) { - /* This is ok (for domain0 at least) - so just return */ - return; - } - - /* The given memory/target value is in KiB, so it needs converting to - pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10. - */ - set_new_target(new_target >> (PAGE_SHIFT - 10)); - -} - -static void -balloon_init_watcher(void *) -{ - int err; - - err = register_xenbus_watch(&target_watch); - if (err) - printf("Failed to set balloon watcher\n"); - -} - -static void -balloon_init(void *) -{ - unsigned long pfn; - struct page *page; - - IPRINTK("Initialising balloon driver.\n"); - - if (xen_init() < 0) - return -1; - - current_pages = min(xen_start_info->nr_pages, max_pfn); - target_pages = current_pages; - balloon_low = 0; - balloon_high = 0; - driver_pages = 0UL; - hard_limit = ~0UL; - - init_timer(&balloon_timer); - balloon_timer.data = 0; - balloon_timer.function = balloon_alarm; - - /* Initialise the balloon with excess memory space. */ - for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) { - page = PHYS_TO_VM_PAGE(pfn << PAGE_SHIFT); - balloon_append(page); - } - - target_watch.callback = watch_target; - - return 0; -} - -void -balloon_update_driver_allowance(long delta) -{ - unsigned long flags; - - balloon_lock(flags); - driver_pages += delta; - balloon_unlock(flags); -} - -#if 0 -static int dealloc_pte_fn( - pte_t *pte, struct page *pte_page, unsigned long addr, void *data) -{ - unsigned long mfn = pte_mfn(*pte); - int ret; - struct xen_memory_reservation reservation = { - .extent_start = &mfn, - .nr_extents = 1, - .extent_order = 0, - .domid = DOMID_SELF - }; - set_pte_at(&init_mm, addr, pte, __pte_ma(0)); - set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY); - ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation); - PANIC_IF(ret != 1); - return 0; -} - -#endif -vm_page_t -balloon_alloc_empty_page_range(unsigned long nr_pages) -{ - unsigned long flags; - vm_page_t pages; - int i; - unsigned long *mfn_list; - struct xen_memory_reservation reservation = { - .address_bits = 0, - .extent_order = 0, - .domid = DOMID_SELF - }; - - pages = vm_page_alloc_contig(nr_pages, 0, -1, 4, 4) - if (pages == NULL) - return NULL; - - mfn_list = malloc(nr_pages*sizeof(unsigned long), M_DEVBUF, M_WAITOK); - - for (i = 0; i < nr_pages; i++) { - mfn_list[i] = PFNTOMFN(VM_PAGE_TO_PHYS(pages[i]) >> PAGE_SHIFT); - PFNTOMFN(i) = INVALID_P2M_ENTRY; - reservation.extent_start = mfn_list; - reservation.nr_extents = nr_pages; - PANIC_IF(HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation) != nr_pages); - } - - current_pages -= nr_pages; - - wakeup(balloon_process); - - return pages; -} - -void -balloon_dealloc_empty_page_range(vm_page_t page, unsigned long nr_pages) -{ - unsigned long i, flags; - - for (i = 0; i < nr_pages; i++) - balloon_append(page + i); - - wakeup(balloon_process); -} - -#endif diff --git a/sys/dev/xen/blkback/blkback.c b/sys/dev/xen/blkback/blkback.c deleted file mode 100644 index a418c6d..0000000 --- a/sys/dev/xen/blkback/blkback.c +++ /dev/null @@ -1,1349 +0,0 @@ -/* - * Copyright (c) 2006, Cisco Systems, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Cisco Systems, Inc. nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/mbuf.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/socket.h> -#include <sys/queue.h> -#include <sys/taskqueue.h> -#include <sys/namei.h> -#include <sys/proc.h> -#include <sys/filedesc.h> -#include <sys/vnode.h> -#include <sys/fcntl.h> -#include <sys/disk.h> -#include <sys/bio.h> - -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/sysctl.h> - -#include <geom/geom.h> - -#include <vm/vm_extern.h> -#include <vm/vm_kern.h> - -#include <machine/xen-os.h> -#include <machine/hypervisor.h> -#include <machine/hypervisor-ifs.h> -#include <machine/xen_intr.h> -#include <machine/evtchn.h> -#include <machine/xenbus.h> -#include <machine/gnttab.h> -#include <machine/xen-public/memory.h> -#include <dev/xen/xenbus/xenbus_comms.h> - - -#if XEN_BLKBACK_DEBUG -#define DPRINTF(fmt, args...) \ - printf("blkback (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) -#else -#define DPRINTF(fmt, args...) ((void)0) -#endif - -#define WPRINTF(fmt, args...) \ - printf("blkback (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) - -#define BLKBACK_INVALID_HANDLE (~0) - -struct ring_ref { - vm_offset_t va; - grant_handle_t handle; - uint64_t bus_addr; -}; - -typedef struct blkback_info { - - /* Schedule lists */ - STAILQ_ENTRY(blkback_info) next_req; - int on_req_sched_list; - - struct xenbus_device *xdev; - XenbusState frontend_state; - - domid_t domid; - - int state; - int ring_connected; - struct ring_ref rr; - blkif_back_ring_t ring; - evtchn_port_t evtchn; - int irq; - void *irq_cookie; - - int ref_cnt; - - int handle; - char *mode; - char *type; - char *dev_name; - - struct vnode *vn; - struct cdev *cdev; - struct cdevsw *csw; - u_int sector_size; - int sector_size_shift; - off_t media_size; - u_int media_num_sectors; - int major; - int minor; - int read_only; - - struct mtx blk_ring_lock; - - device_t ndev; - - /* Stats */ - int st_rd_req; - int st_wr_req; - int st_oo_req; - int st_err_req; -} blkif_t; - -/* - * These are rather arbitrary. They are fairly large because adjacent requests - * pulled from a communication ring are quite likely to end up being part of - * the same scatter/gather request at the disc. - * - * ** TRY INCREASING 'blkif_reqs' IF WRITE SPEEDS SEEM TOO LOW ** - * - * This will increase the chances of being able to write whole tracks. - * 64 should be enough to keep us competitive with Linux. - */ -static int blkif_reqs = 64; -TUNABLE_INT("xen.vbd.blkif_reqs", &blkif_reqs); - -static int mmap_pages; - -/* - * Each outstanding request that we've passed to the lower device layers has a - * 'pending_req' allocated to it. Each buffer_head that completes decrements - * the pendcnt towards zero. When it hits zero, the specified domain has a - * response queued for it, with the saved 'id' passed back. - */ -typedef struct pending_req { - blkif_t *blkif; - uint64_t id; - int nr_pages; - int pendcnt; - unsigned short operation; - int status; - STAILQ_ENTRY(pending_req) free_list; -} pending_req_t; - -static pending_req_t *pending_reqs; -static STAILQ_HEAD(pending_reqs_list, pending_req) pending_free = - STAILQ_HEAD_INITIALIZER(pending_free); -static struct mtx pending_free_lock; - -static STAILQ_HEAD(blkback_req_sched_list, blkback_info) req_sched_list = - STAILQ_HEAD_INITIALIZER(req_sched_list); -static struct mtx req_sched_list_lock; - -static unsigned long mmap_vstart; -static unsigned long *pending_vaddrs; -static grant_handle_t *pending_grant_handles; - -static struct task blk_req_task; - -/* Protos */ -static void disconnect_ring(blkif_t *blkif); -static int vbd_add_dev(struct xenbus_device *xdev); - -static inline int vaddr_pagenr(pending_req_t *req, int seg) -{ - return (req - pending_reqs) * BLKIF_MAX_SEGMENTS_PER_REQUEST + seg; -} - -static inline unsigned long vaddr(pending_req_t *req, int seg) -{ - return pending_vaddrs[vaddr_pagenr(req, seg)]; -} - -#define pending_handle(_req, _seg) \ - (pending_grant_handles[vaddr_pagenr(_req, _seg)]) - -static unsigned long -alloc_empty_page_range(unsigned long nr_pages) -{ - void *pages; - int i = 0, j = 0; - multicall_entry_t mcl[17]; - unsigned long mfn_list[16]; - struct xen_memory_reservation reservation = { - .extent_start = mfn_list, - .nr_extents = 0, - .address_bits = 0, - .extent_order = 0, - .domid = DOMID_SELF - }; - - pages = malloc(nr_pages*PAGE_SIZE, M_DEVBUF, M_NOWAIT); - if (pages == NULL) - return 0; - - memset(mcl, 0, sizeof(mcl)); - - while (i < nr_pages) { - unsigned long va = (unsigned long)pages + (i++ * PAGE_SIZE); - - mcl[j].op = __HYPERVISOR_update_va_mapping; - mcl[j].args[0] = va; - - mfn_list[j++] = vtomach(va) >> PAGE_SHIFT; - - xen_phys_machine[(vtophys(va) >> PAGE_SHIFT)] = INVALID_P2M_ENTRY; - - if (j == 16 || i == nr_pages) { - mcl[j-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_LOCAL; - - reservation.nr_extents = j; - - mcl[j].op = __HYPERVISOR_memory_op; - mcl[j].args[0] = XENMEM_decrease_reservation; - mcl[j].args[1] = (unsigned long)&reservation; - - (void)HYPERVISOR_multicall(mcl, j+1); - - mcl[j-1].args[MULTI_UVMFLAGS_INDEX] = 0; - j = 0; - } - } - - return (unsigned long)pages; -} - -static pending_req_t * -alloc_req(void) -{ - pending_req_t *req; - mtx_lock(&pending_free_lock); - if ((req = STAILQ_FIRST(&pending_free))) { - STAILQ_REMOVE(&pending_free, req, pending_req, free_list); - STAILQ_NEXT(req, free_list) = NULL; - } - mtx_unlock(&pending_free_lock); - return req; -} - -static void -free_req(pending_req_t *req) -{ - int was_empty; - - mtx_lock(&pending_free_lock); - was_empty = STAILQ_EMPTY(&pending_free); - STAILQ_INSERT_TAIL(&pending_free, req, free_list); - mtx_unlock(&pending_free_lock); - if (was_empty) - taskqueue_enqueue(taskqueue_swi, &blk_req_task); -} - -static void -fast_flush_area(pending_req_t *req) -{ - struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; - unsigned int i, invcount = 0; - grant_handle_t handle; - int ret; - - for (i = 0; i < req->nr_pages; i++) { - handle = pending_handle(req, i); - if (handle == BLKBACK_INVALID_HANDLE) - continue; - unmap[invcount].host_addr = vaddr(req, i); - unmap[invcount].dev_bus_addr = 0; - unmap[invcount].handle = handle; - pending_handle(req, i) = BLKBACK_INVALID_HANDLE; - invcount++; - } - - ret = HYPERVISOR_grant_table_op( - GNTTABOP_unmap_grant_ref, unmap, invcount); - PANIC_IF(ret); -} - -static void -blkif_get(blkif_t *blkif) -{ - atomic_add_int(&blkif->ref_cnt, 1); -} - -static void -blkif_put(blkif_t *blkif) -{ - if (atomic_fetchadd_int(&blkif->ref_cnt, -1) == 1) { - DPRINTF("Removing %x\n", (unsigned int)blkif); - disconnect_ring(blkif); - if (blkif->mode) - free(blkif->mode, M_DEVBUF); - if (blkif->type) - free(blkif->type, M_DEVBUF); - if (blkif->dev_name) - free(blkif->dev_name, M_DEVBUF); - free(blkif, M_DEVBUF); - } -} - -static int -blkif_create(struct xenbus_device *xdev, long handle, char *mode, char *type, char *params) -{ - blkif_t *blkif; - - blkif = (blkif_t *)malloc(sizeof(*blkif), M_DEVBUF, M_NOWAIT | M_ZERO); - if (!blkif) - return ENOMEM; - - DPRINTF("Created %x\n", (unsigned int)blkif); - - blkif->ref_cnt = 1; - blkif->domid = xdev->otherend_id; - blkif->handle = handle; - blkif->mode = mode; - blkif->type = type; - blkif->dev_name = params; - blkif->xdev = xdev; - xdev->data = blkif; - - mtx_init(&blkif->blk_ring_lock, "blk_ring_ock", "blkback ring lock", MTX_DEF); - - if (strcmp(mode, "w")) - blkif->read_only = 1; - - return 0; -} - -static void -add_to_req_schedule_list_tail(blkif_t *blkif) -{ - if (!blkif->on_req_sched_list) { - mtx_lock(&req_sched_list_lock); - if (!blkif->on_req_sched_list && (blkif->state == XenbusStateConnected)) { - blkif_get(blkif); - STAILQ_INSERT_TAIL(&req_sched_list, blkif, next_req); - blkif->on_req_sched_list = 1; - taskqueue_enqueue(taskqueue_swi, &blk_req_task); - } - mtx_unlock(&req_sched_list_lock); - } -} - -/* This routine does not call blkif_get(), does not schedule the blk_req_task to run, - and assumes that the state is connected */ -static void -add_to_req_schedule_list_tail2(blkif_t *blkif) -{ - mtx_lock(&req_sched_list_lock); - if (!blkif->on_req_sched_list) { - STAILQ_INSERT_TAIL(&req_sched_list, blkif, next_req); - blkif->on_req_sched_list = 1; - } - mtx_unlock(&req_sched_list_lock); -} - -/* Removes blkif from front of list and does not call blkif_put() (caller must) */ -static blkif_t * -remove_from_req_schedule_list(void) -{ - blkif_t *blkif; - - mtx_lock(&req_sched_list_lock); - - if ((blkif = STAILQ_FIRST(&req_sched_list))) { - STAILQ_REMOVE(&req_sched_list, blkif, blkback_info, next_req); - STAILQ_NEXT(blkif, next_req) = NULL; - blkif->on_req_sched_list = 0; - } - - mtx_unlock(&req_sched_list_lock); - - return blkif; -} - -static void -make_response(blkif_t *blkif, uint64_t id, - unsigned short op, int st) -{ - blkif_response_t *resp; - blkif_back_ring_t *blk_ring = &blkif->ring; - int more_to_do = 0; - int notify; - - mtx_lock(&blkif->blk_ring_lock); - - - /* Place on the response ring for the relevant domain. */ - resp = RING_GET_RESPONSE(blk_ring, blk_ring->rsp_prod_pvt); - resp->id = id; - resp->operation = op; - resp->status = st; - blk_ring->rsp_prod_pvt++; - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(blk_ring, notify); - - if (blk_ring->rsp_prod_pvt == blk_ring->req_cons) { - /* - * Tail check for pending requests. Allows frontend to avoid - * notifications if requests are already in flight (lower - * overheads and promotes batching). - */ - RING_FINAL_CHECK_FOR_REQUESTS(blk_ring, more_to_do); - - } else if (RING_HAS_UNCONSUMED_REQUESTS(blk_ring)) - more_to_do = 1; - - mtx_unlock(&blkif->blk_ring_lock); - - if (more_to_do) - add_to_req_schedule_list_tail(blkif); - - if (notify) - notify_remote_via_irq(blkif->irq); -} - -static void -end_block_io_op(struct bio *bio) -{ - pending_req_t *pending_req = bio->bio_caller2; - - if (bio->bio_error) { - DPRINTF("BIO returned error %d for operation on device %s\n", - bio->bio_error, pending_req->blkif->dev_name); - pending_req->status = BLKIF_RSP_ERROR; - pending_req->blkif->st_err_req++; - } - -#if 0 - printf("done: bio=%x error=%x completed=%llu resid=%lu flags=%x\n", - (unsigned int)bio, bio->bio_error, bio->bio_completed, bio->bio_resid, bio->bio_flags); -#endif - - if (atomic_fetchadd_int(&pending_req->pendcnt, -1) == 1) { - fast_flush_area(pending_req); - make_response(pending_req->blkif, pending_req->id, - pending_req->operation, pending_req->status); - blkif_put(pending_req->blkif); - free_req(pending_req); - } - - g_destroy_bio(bio); -} - -static void -dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req, pending_req_t *pending_req) -{ - struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST]; - struct { - unsigned long buf; unsigned int nsec; - } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; - unsigned int nseg = req->nr_segments, nr_sects = 0; - struct bio *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST]; - int operation, ret, i, nbio = 0; - - /* Check that number of segments is sane. */ - if (unlikely(nseg == 0) || - unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) { - DPRINTF("Bad number of segments in request (%d)\n", nseg); - goto fail_response; - } - - if (req->operation == BLKIF_OP_WRITE) { - if (blkif->read_only) { - DPRINTF("Attempt to write to read only device %s\n", blkif->dev_name); - goto fail_response; - } - operation = BIO_WRITE; - } else - operation = BIO_READ; - - pending_req->blkif = blkif; - pending_req->id = req->id; - pending_req->operation = req->operation; - pending_req->status = BLKIF_RSP_OKAY; - pending_req->nr_pages = nseg; - - for (i = 0; i < nseg; i++) { - seg[i].nsec = req->seg[i].last_sect - - req->seg[i].first_sect + 1; - - if ((req->seg[i].last_sect >= (PAGE_SIZE >> 9)) || - (seg[i].nsec <= 0)) - goto fail_response; - nr_sects += seg[i].nsec; - - map[i].host_addr = vaddr(pending_req, i); - map[i].dom = blkif->domid; - map[i].ref = req->seg[i].gref; - map[i].flags = GNTMAP_host_map; - if (operation == BIO_WRITE) - map[i].flags |= GNTMAP_readonly; - } - - /* Convert to the disk's sector size */ - nr_sects = (nr_sects << 9) >> blkif->sector_size_shift; - - ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nseg); - PANIC_IF(ret); - - for (i = 0; i < nseg; i++) { - if (unlikely(map[i].status != 0)) { - DPRINTF("invalid buffer -- could not remap it\n"); - goto fail_flush; - } - - pending_handle(pending_req, i) = map[i].handle; -#if 0 - /* Can't do this in FreeBSD since vtophys() returns the pfn */ - /* of the remote domain who loaned us the machine page - DPT */ - xen_phys_machine[(vtophys(vaddr(pending_req, i)) >> PAGE_SHIFT)] = - map[i]dev_bus_addr >> PAGE_SHIFT; -#endif - seg[i].buf = map[i].dev_bus_addr | - (req->seg[i].first_sect << 9); - } - - if (req->sector_number + nr_sects > blkif->media_num_sectors) { - DPRINTF("%s of [%llu,%llu] extends past end of device %s\n", - operation == BIO_READ ? "read" : "write", - req->sector_number, - req->sector_number + nr_sects, blkif->dev_name); - goto fail_flush; - } - - for (i = 0; i < nseg; i++) { - struct bio *bio; - - if ((int)seg[i].nsec & ((blkif->sector_size >> 9) - 1)) { - DPRINTF("Misaligned I/O request from domain %d", blkif->domid); - goto fail_put_bio; - } - - bio = biolist[nbio++] = g_new_bio(); - if (unlikely(bio == NULL)) - goto fail_put_bio; - - bio->bio_cmd = operation; - bio->bio_offset = req->sector_number << blkif->sector_size_shift; - bio->bio_length = seg[i].nsec << 9; - bio->bio_bcount = bio->bio_length; - bio->bio_data = (caddr_t)(vaddr(pending_req, i) | (seg[i].buf & PAGE_MASK)); - bio->bio_done = end_block_io_op; - bio->bio_caller2 = pending_req; - bio->bio_dev = blkif->cdev; - - req->sector_number += (seg[i].nsec << 9) >> blkif->sector_size_shift; -#if 0 - printf("new: bio=%x cmd=%d sect=%llu nsect=%u iosize_max=%u @ %08lx\n", - (unsigned int)bio, req->operation, req->sector_number, seg[i].nsec, - blkif->cdev->si_iosize_max, seg[i].buf); -#endif - } - - pending_req->pendcnt = nbio; - blkif_get(blkif); - - for (i = 0; i < nbio; i++) - (*blkif->csw->d_strategy)(biolist[i]); - - return; - - fail_put_bio: - for (i = 0; i < (nbio-1); i++) - g_destroy_bio(biolist[i]); - fail_flush: - fast_flush_area(pending_req); - fail_response: - make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR); - free_req(pending_req); -} - -static void -blk_req_action(void *context, int pending) -{ - blkif_t *blkif; - - DPRINTF("\n"); - - while (!STAILQ_EMPTY(&req_sched_list)) { - blkif_back_ring_t *blk_ring; - RING_IDX rc, rp; - - blkif = remove_from_req_schedule_list(); - - blk_ring = &blkif->ring; - rc = blk_ring->req_cons; - rp = blk_ring->sring->req_prod; - rmb(); /* Ensure we see queued requests up to 'rp'. */ - - while ((rc != rp) && !RING_REQUEST_CONS_OVERFLOW(blk_ring, rc)) { - blkif_request_t *req; - pending_req_t *pending_req; - - pending_req = alloc_req(); - if (pending_req == NULL) - goto out_of_preqs; - - req = RING_GET_REQUEST(blk_ring, rc); - blk_ring->req_cons = ++rc; /* before make_response() */ - - switch (req->operation) { - case BLKIF_OP_READ: - blkif->st_rd_req++; - dispatch_rw_block_io(blkif, req, pending_req); - break; - case BLKIF_OP_WRITE: - blkif->st_wr_req++; - dispatch_rw_block_io(blkif, req, pending_req); - break; - default: - blkif->st_err_req++; - DPRINTF("error: unknown block io operation [%d]\n", - req->operation); - make_response(blkif, req->id, req->operation, - BLKIF_RSP_ERROR); - free_req(pending_req); - break; - } - } - - blkif_put(blkif); - } - - return; - - out_of_preqs: - /* We ran out of pending req structs */ - /* Just requeue interface and wait to be rescheduled to run when one is freed */ - add_to_req_schedule_list_tail2(blkif); - blkif->st_oo_req++; -} - -/* Handle interrupt from a frontend */ -static void -blkback_intr(void *arg) -{ - blkif_t *blkif = arg; - DPRINTF("%x\n", (unsigned int)blkif); - add_to_req_schedule_list_tail(blkif); -} - -/* Map grant ref for ring */ -static int -map_ring(grant_ref_t ref, domid_t dom, struct ring_ref *ring) -{ - struct gnttab_map_grant_ref op; - - ring->va = kmem_alloc_nofault(kernel_map, PAGE_SIZE); - if (ring->va == 0) - return ENOMEM; - - op.host_addr = ring->va; - op.flags = GNTMAP_host_map; - op.ref = ref; - op.dom = dom; - HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); - if (op.status) { - WPRINTF("grant table op err=%d\n", op.status); - kmem_free(kernel_map, ring->va, PAGE_SIZE); - ring->va = 0; - return EACCES; - } - - ring->handle = op.handle; - ring->bus_addr = op.dev_bus_addr; - - return 0; -} - -/* Unmap grant ref for ring */ -static void -unmap_ring(struct ring_ref *ring) -{ - struct gnttab_unmap_grant_ref op; - - op.host_addr = ring->va; - op.dev_bus_addr = ring->bus_addr; - op.handle = ring->handle; - HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1); - if (op.status) - WPRINTF("grant table op err=%d\n", op.status); - - kmem_free(kernel_map, ring->va, PAGE_SIZE); - ring->va = 0; -} - -static int -connect_ring(blkif_t *blkif) -{ - struct xenbus_device *xdev = blkif->xdev; - blkif_sring_t *ring; - unsigned long ring_ref; - evtchn_port_t evtchn; - evtchn_op_t op = { .cmd = EVTCHNOP_bind_interdomain }; - int err; - - if (blkif->ring_connected) - return 0; - - // Grab FE data and map his memory - err = xenbus_gather(NULL, xdev->otherend, - "ring-ref", "%lu", &ring_ref, - "event-channel", "%u", &evtchn, NULL); - if (err) { - xenbus_dev_fatal(xdev, err, - "reading %s/ring-ref and event-channel", - xdev->otherend); - return err; - } - - err = map_ring(ring_ref, blkif->domid, &blkif->rr); - if (err) { - xenbus_dev_fatal(xdev, err, "mapping ring"); - return err; - } - ring = (blkif_sring_t *)blkif->rr.va; - BACK_RING_INIT(&blkif->ring, ring, PAGE_SIZE); - - op.u.bind_interdomain.remote_dom = blkif->domid; - op.u.bind_interdomain.remote_port = evtchn; - err = HYPERVISOR_event_channel_op(&op); - if (err) { - unmap_ring(&blkif->rr); - xenbus_dev_fatal(xdev, err, "binding event channel"); - return err; - } - blkif->evtchn = op.u.bind_interdomain.local_port; - - /* bind evtchn to irq handler */ - blkif->irq = - bind_evtchn_to_irqhandler(blkif->evtchn, "blkback", - blkback_intr, blkif, INTR_TYPE_NET|INTR_MPSAFE, &blkif->irq_cookie); - - blkif->ring_connected = 1; - - DPRINTF("%x rings connected! evtchn=%d irq=%d\n", - (unsigned int)blkif, blkif->evtchn, blkif->irq); - - return 0; -} - -static void -disconnect_ring(blkif_t *blkif) -{ - DPRINTF("\n"); - - if (blkif->ring_connected) { - unbind_from_irqhandler(blkif->irq, blkif->irq_cookie); - blkif->irq = 0; - unmap_ring(&blkif->rr); - blkif->ring_connected = 0; - } -} - -static void -connect(blkif_t *blkif) -{ - struct xenbus_transaction *xbt; - struct xenbus_device *xdev = blkif->xdev; - int err; - - if (!blkif->ring_connected || - blkif->vn == NULL || - blkif->state == XenbusStateConnected) - return; - - DPRINTF("%s\n", xdev->otherend); - - /* Supply the information about the device the frontend needs */ -again: - xbt = xenbus_transaction_start(); - if (IS_ERR(xbt)) { - xenbus_dev_fatal(xdev, PTR_ERR(xbt), - "Error writing configuration for backend " - "(start transaction)"); - return; - } - - err = xenbus_printf(xbt, xdev->nodename, "sectors", "%u", - blkif->media_num_sectors); - if (err) { - xenbus_dev_fatal(xdev, err, "writing %s/sectors", - xdev->nodename); - goto abort; - } - - err = xenbus_printf(xbt, xdev->nodename, "info", "%u", - blkif->read_only ? VDISK_READONLY : 0); - if (err) { - xenbus_dev_fatal(xdev, err, "writing %s/info", - xdev->nodename); - goto abort; - } - err = xenbus_printf(xbt, xdev->nodename, "sector-size", "%u", - blkif->sector_size); - if (err) { - xenbus_dev_fatal(xdev, err, "writing %s/sector-size", - xdev->nodename); - goto abort; - } - - err = xenbus_transaction_end(xbt, 0); - if (err == -EAGAIN) - goto again; - if (err) - xenbus_dev_fatal(xdev, err, "ending transaction"); - - err = xenbus_switch_state(xdev, NULL, XenbusStateConnected); - if (err) - xenbus_dev_fatal(xdev, err, "switching to Connected state", - xdev->nodename); - - blkif->state = XenbusStateConnected; - - return; - - abort: - xenbus_transaction_end(xbt, 1); -} - -static int -blkback_probe(struct xenbus_device *xdev, const struct xenbus_device_id *id) -{ - int err; - char *p, *mode = NULL, *type = NULL, *params = NULL; - long handle; - - DPRINTF("node=%s\n", xdev->nodename); - - p = strrchr(xdev->otherend, '/') + 1; - handle = strtoul(p, NULL, 0); - - mode = xenbus_read(NULL, xdev->nodename, "mode", NULL); - if (IS_ERR(mode)) { - xenbus_dev_fatal(xdev, PTR_ERR(mode), "reading mode"); - err = PTR_ERR(mode); - goto error; - } - - type = xenbus_read(NULL, xdev->nodename, "type", NULL); - if (IS_ERR(type)) { - xenbus_dev_fatal(xdev, PTR_ERR(type), "reading type"); - err = PTR_ERR(type); - goto error; - } - - params = xenbus_read(NULL, xdev->nodename, "params", NULL); - if (IS_ERR(type)) { - xenbus_dev_fatal(xdev, PTR_ERR(params), "reading params"); - err = PTR_ERR(params); - goto error; - } - - err = blkif_create(xdev, handle, mode, type, params); - if (err) { - xenbus_dev_fatal(xdev, err, "creating blkif"); - goto error; - } - - err = vbd_add_dev(xdev); - if (err) { - blkif_put((blkif_t *)xdev->data); - xenbus_dev_fatal(xdev, err, "adding vbd device"); - } - - return err; - - error: - if (mode) - free(mode, M_DEVBUF); - if (type) - free(type, M_DEVBUF); - if (params) - free(params, M_DEVBUF); - return err; -} - -static int -blkback_remove(struct xenbus_device *xdev) -{ - blkif_t *blkif = xdev->data; - device_t ndev; - - DPRINTF("node=%s\n", xdev->nodename); - - blkif->state = XenbusStateClosing; - - if ((ndev = blkif->ndev)) { - blkif->ndev = NULL; - mtx_lock(&Giant); - device_detach(ndev); - mtx_unlock(&Giant); - } - - xdev->data = NULL; - blkif->xdev = NULL; - blkif_put(blkif); - - return 0; -} - -static int -blkback_resume(struct xenbus_device *xdev) -{ - DPRINTF("node=%s\n", xdev->nodename); - return 0; -} - -static void -frontend_changed(struct xenbus_device *xdev, - XenbusState frontend_state) -{ - blkif_t *blkif = xdev->data; - - DPRINTF("state=%d\n", frontend_state); - - blkif->frontend_state = frontend_state; - - switch (frontend_state) { - case XenbusStateInitialising: - break; - case XenbusStateInitialised: - case XenbusStateConnected: - connect_ring(blkif); - connect(blkif); - break; - case XenbusStateClosing: - xenbus_switch_state(xdev, NULL, XenbusStateClosing); - break; - case XenbusStateClosed: - xenbus_remove_device(xdev); - break; - case XenbusStateUnknown: - case XenbusStateInitWait: - xenbus_dev_fatal(xdev, EINVAL, "saw state %d at frontend", - frontend_state); - break; - } -} - -/* ** Driver registration ** */ - -static struct xenbus_device_id blkback_ids[] = { - { "vbd" }, - { "" } -}; - -static struct xenbus_driver blkback = { - .name = "blkback", - .ids = blkback_ids, - .probe = blkback_probe, - .remove = blkback_remove, - .resume = blkback_resume, - .otherend_changed = frontend_changed, -}; - -static void -blkback_init(void *unused) -{ - int i; - - TASK_INIT(&blk_req_task, 0, blk_req_action, NULL); - mtx_init(&req_sched_list_lock, "blk_req_sched_lock", "blkback req sched lock", MTX_DEF); - - mtx_init(&pending_free_lock, "blk_pending_req_ock", "blkback pending request lock", MTX_DEF); - - mmap_pages = blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST; - pending_reqs = malloc(sizeof(pending_reqs[0]) * - blkif_reqs, M_DEVBUF, M_ZERO|M_NOWAIT); - pending_grant_handles = malloc(sizeof(pending_grant_handles[0]) * - mmap_pages, M_DEVBUF, M_NOWAIT); - pending_vaddrs = malloc(sizeof(pending_vaddrs[0]) * - mmap_pages, M_DEVBUF, M_NOWAIT); - mmap_vstart = alloc_empty_page_range(mmap_pages); - if (!pending_reqs || !pending_grant_handles || !pending_vaddrs || !mmap_vstart) { - if (pending_reqs) - free(pending_reqs, M_DEVBUF); - if (pending_grant_handles) - free(pending_grant_handles, M_DEVBUF); - if (pending_vaddrs) - free(pending_vaddrs, M_DEVBUF); - WPRINTF("out of memory\n"); - return; - } - - for (i = 0; i < mmap_pages; i++) { - pending_vaddrs[i] = mmap_vstart + (i << PAGE_SHIFT); - pending_grant_handles[i] = BLKBACK_INVALID_HANDLE; - } - - for (i = 0; i < blkif_reqs; i++) { - STAILQ_INSERT_TAIL(&pending_free, &pending_reqs[i], free_list); - } - - DPRINTF("registering %s\n", blkback.name); - xenbus_register_backend(&blkback); -} - -SYSINIT(xbbedev, SI_SUB_PSEUDO, SI_ORDER_ANY, blkback_init, NULL) - -static void -close_device(blkif_t *blkif) -{ - DPRINTF("closing dev=%s\n", blkif->dev_name); - if (blkif->vn) { - int flags = FREAD; - - if (!blkif->read_only) - flags |= FWRITE; - - if (blkif->csw) { - dev_relthread(blkif->cdev); - blkif->csw = NULL; - } - - (void)vn_close(blkif->vn, flags, NOCRED, curthread); - blkif->vn = NULL; - } -} - -static int -open_device(blkif_t *blkif) -{ - struct nameidata nd; - struct vattr vattr; - struct cdev *dev; - struct cdevsw *devsw; - int flags = FREAD, err = 0; - - DPRINTF("opening dev=%s\n", blkif->dev_name); - - if (!blkif->read_only) - flags |= FWRITE; - - if (!curthread->td_proc->p_fd->fd_cdir) { - curthread->td_proc->p_fd->fd_cdir = rootvnode; - VREF(rootvnode); - } - if (!curthread->td_proc->p_fd->fd_rdir) { - curthread->td_proc->p_fd->fd_rdir = rootvnode; - VREF(rootvnode); - } - if (!curthread->td_proc->p_fd->fd_jdir) { - curthread->td_proc->p_fd->fd_jdir = rootvnode; - VREF(rootvnode); - } - - again: - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, blkif->dev_name, curthread); - err = vn_open(&nd, &flags, 0, -1); - if (err) { - if (blkif->dev_name[0] != '/') { - char *dev_path = "/dev/"; - char *dev_name; - - /* Try adding device path at beginning of name */ - dev_name = malloc(strlen(blkif->dev_name) + strlen(dev_path) + 1, M_DEVBUF, M_NOWAIT); - if (dev_name) { - sprintf(dev_name, "%s%s", dev_path, blkif->dev_name); - free(blkif->dev_name, M_DEVBUF); - blkif->dev_name = dev_name; - goto again; - } - } - xenbus_dev_fatal(blkif->xdev, err, "error opening device %s", blkif->dev_name); - return err; - } - NDFREE(&nd, NDF_ONLY_PNBUF); - - blkif->vn = nd.ni_vp; - - /* We only support disks for now */ - if (!vn_isdisk(blkif->vn, &err)) { - xenbus_dev_fatal(blkif->xdev, err, "device %s is not a disk", blkif->dev_name); - VOP_UNLOCK(blkif->vn, 0, curthread); - goto error; - } - - blkif->cdev = blkif->vn->v_rdev; - blkif->csw = dev_refthread(blkif->cdev); - PANIC_IF(blkif->csw == NULL); - - err = VOP_GETATTR(blkif->vn, &vattr, NOCRED); - if (err) { - xenbus_dev_fatal(blkif->xdev, err, - "error getting vnode attributes for device %s", blkif->dev_name); - VOP_UNLOCK(blkif->vn, 0, curthread); - goto error; - } - - VOP_UNLOCK(blkif->vn, 0, curthread); - - dev = blkif->vn->v_rdev; - devsw = dev->si_devsw; - if (!devsw->d_ioctl) { - err = ENODEV; - xenbus_dev_fatal(blkif->xdev, err, - "no d_ioctl for device %s!", blkif->dev_name); - goto error; - } - - err = (*devsw->d_ioctl)(dev, DIOCGSECTORSIZE, (caddr_t)&blkif->sector_size, FREAD, curthread); - if (err) { - xenbus_dev_fatal(blkif->xdev, err, - "error calling ioctl DIOCGSECTORSIZE for device %s", blkif->dev_name); - goto error; - } - blkif->sector_size_shift = fls(blkif->sector_size) - 1; - - err = (*devsw->d_ioctl)(dev, DIOCGMEDIASIZE, (caddr_t)&blkif->media_size, FREAD, curthread); - if (err) { - xenbus_dev_fatal(blkif->xdev, err, - "error calling ioctl DIOCGMEDIASIZE for device %s", blkif->dev_name); - goto error; - } - blkif->media_num_sectors = blkif->media_size >> blkif->sector_size_shift; - - blkif->major = umajor(vattr.va_rdev); - blkif->minor = uminor(vattr.va_rdev); - - DPRINTF("opened dev=%s major=%d minor=%d sector_size=%u media_size=%lld\n", - blkif->dev_name, blkif->major, blkif->minor, blkif->sector_size, blkif->media_size); - - return 0; - - error: - close_device(blkif); - return err; -} - -static int -vbd_add_dev(struct xenbus_device *xdev) -{ - blkif_t *blkif = xdev->data; - device_t nexus, ndev; - devclass_t dc; - int err = 0; - - mtx_lock(&Giant); - - /* We will add a vbd device as a child of nexus0 (for now) */ - if (!(dc = devclass_find("nexus")) || - !(nexus = devclass_get_device(dc, 0))) { - WPRINTF("could not find nexus0!\n"); - err = ENOENT; - goto done; - } - - - /* Create a newbus device representing the vbd */ - ndev = BUS_ADD_CHILD(nexus, 0, "vbd", blkif->handle); - if (!ndev) { - WPRINTF("could not create newbus device vbd%d!\n", blkif->handle); - err = EFAULT; - goto done; - } - - blkif_get(blkif); - device_set_ivars(ndev, blkif); - blkif->ndev = ndev; - - device_probe_and_attach(ndev); - - done: - - mtx_unlock(&Giant); - - return err; -} - -enum { - VBD_SYSCTL_DOMID, - VBD_SYSCTL_ST_RD_REQ, - VBD_SYSCTL_ST_WR_REQ, - VBD_SYSCTL_ST_OO_REQ, - VBD_SYSCTL_ST_ERR_REQ, - VBD_SYSCTL_RING, -}; - -static char * -vbd_sysctl_ring_info(blkif_t *blkif, int cmd) -{ - char *buf = malloc(256, M_DEVBUF, M_WAITOK); - if (buf) { - if (!blkif->ring_connected) - sprintf(buf, "ring not connected\n"); - else { - blkif_back_ring_t *ring = &blkif->ring; - sprintf(buf, "nr_ents=%x req_cons=%x" - " req_prod=%x req_event=%x" - " rsp_prod=%x rsp_event=%x", - ring->nr_ents, ring->req_cons, - ring->sring->req_prod, ring->sring->req_event, - ring->sring->rsp_prod, ring->sring->rsp_event); - } - } - return buf; -} - -static int -vbd_sysctl_handler(SYSCTL_HANDLER_ARGS) -{ - device_t dev = (device_t)arg1; - blkif_t *blkif = (blkif_t *)device_get_ivars(dev); - const char *value; - char *buf = NULL; - int err; - - switch (arg2) { - case VBD_SYSCTL_DOMID: - return sysctl_handle_int(oidp, NULL, blkif->domid, req); - case VBD_SYSCTL_ST_RD_REQ: - return sysctl_handle_int(oidp, NULL, blkif->st_rd_req, req); - case VBD_SYSCTL_ST_WR_REQ: - return sysctl_handle_int(oidp, NULL, blkif->st_wr_req, req); - case VBD_SYSCTL_ST_OO_REQ: - return sysctl_handle_int(oidp, NULL, blkif->st_oo_req, req); - case VBD_SYSCTL_ST_ERR_REQ: - return sysctl_handle_int(oidp, NULL, blkif->st_err_req, req); - case VBD_SYSCTL_RING: - value = buf = vbd_sysctl_ring_info(blkif, arg2); - break; - default: - return (EINVAL); - } - - err = SYSCTL_OUT(req, value, strlen(value)); - if (buf != NULL) - free(buf, M_DEVBUF); - - return err; -} - -/* Newbus vbd device driver probe */ -static int -vbd_probe(device_t dev) -{ - DPRINTF("vbd%d\n", device_get_unit(dev)); - return 0; -} - -/* Newbus vbd device driver attach */ -static int -vbd_attach(device_t dev) -{ - blkif_t *blkif = (blkif_t *)device_get_ivars(dev); - - DPRINTF("%s\n", blkif->dev_name); - - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "domid", CTLTYPE_INT|CTLFLAG_RD, - dev, VBD_SYSCTL_DOMID, vbd_sysctl_handler, "I", - "domid of frontend"); - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "rd_reqs", CTLTYPE_INT|CTLFLAG_RD, - dev, VBD_SYSCTL_ST_RD_REQ, vbd_sysctl_handler, "I", - "number of read reqs"); - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "wr_reqs", CTLTYPE_INT|CTLFLAG_RD, - dev, VBD_SYSCTL_ST_WR_REQ, vbd_sysctl_handler, "I", - "number of write reqs"); - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "oo_reqs", CTLTYPE_INT|CTLFLAG_RD, - dev, VBD_SYSCTL_ST_OO_REQ, vbd_sysctl_handler, "I", - "number of deferred reqs"); - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "err_reqs", CTLTYPE_INT|CTLFLAG_RD, - dev, VBD_SYSCTL_ST_ERR_REQ, vbd_sysctl_handler, "I", - "number of reqs that returned error"); -#if XEN_BLKBACK_DEBUG - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "ring", CTLFLAG_RD, - dev, VBD_SYSCTL_RING, vbd_sysctl_handler, "A", - "req ring info"); -#endif - - if (!open_device(blkif)) - connect(blkif); - - return bus_generic_attach(dev); -} - -/* Newbus vbd device driver detach */ -static int -vbd_detach(device_t dev) -{ - blkif_t *blkif = (blkif_t *)device_get_ivars(dev); - - DPRINTF("%s\n", blkif->dev_name); - - close_device(blkif); - - bus_generic_detach(dev); - - blkif_put(blkif); - - return 0; -} - -static device_method_t vbd_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, vbd_probe), - DEVMETHOD(device_attach, vbd_attach), - DEVMETHOD(device_detach, vbd_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - {0, 0} -}; - -static devclass_t vbd_devclass; - -static driver_t vbd_driver = { - "vbd", - vbd_methods, - 0, -}; - -DRIVER_MODULE(vbd, nexus, vbd_driver, vbd_devclass, 0, 0); - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: t - * End: - */ diff --git a/sys/dev/xen/blkfront/blkfront.c b/sys/dev/xen/blkfront/blkfront.c deleted file mode 100644 index 3bdc4f8..0000000 --- a/sys/dev/xen/blkfront/blkfront.c +++ /dev/null @@ -1,1026 +0,0 @@ -/*- - * All rights reserved. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ - -/* - * XenoBSD block device driver - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <vm/vm.h> -#include <vm/pmap.h> - -#include <sys/bio.h> -#include <sys/bus.h> -#include <sys/conf.h> -#include <sys/module.h> - -#include <machine/bus.h> -#include <sys/rman.h> -#include <machine/resource.h> -#include <machine/intr_machdep.h> -#include <machine/vmparam.h> - -#include <machine/xen/hypervisor.h> -#include <machine/xen/xen-os.h> -#include <machine/xen/xen_intr.h> -#include <machine/xen/xenbus.h> -#include <machine/xen/evtchn.h> -#include <xen/interface/grant_table.h> - -#include <geom/geom_disk.h> -#include <machine/xen/xenfunc.h> -#include <xen/gnttab.h> - -#include <dev/xen/blkfront/block.h> - -#define ASSERT(S) KASSERT(S, (#S)) -/* prototypes */ -struct xb_softc; -static void xb_startio(struct xb_softc *sc); -static void connect(struct blkfront_info *); -static void blkfront_closing(struct xenbus_device *); -static int blkfront_remove(struct xenbus_device *); -static int talk_to_backend(struct xenbus_device *, struct blkfront_info *); -static int setup_blkring(struct xenbus_device *, struct blkfront_info *); -static void blkif_int(void *); -#if 0 -static void blkif_restart_queue(void *arg); -#endif -static void blkif_recover(struct blkfront_info *); -static void blkif_completion(struct blk_shadow *); -static void blkif_free(struct blkfront_info *, int); - -#define GRANT_INVALID_REF 0 -#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE) - -LIST_HEAD(xb_softc_list_head, xb_softc) xbsl_head; - -/* Control whether runtime update of vbds is enabled. */ -#define ENABLE_VBD_UPDATE 0 - -#if ENABLE_VBD_UPDATE -static void vbd_update(void); -#endif - - -#define BLKIF_STATE_DISCONNECTED 0 -#define BLKIF_STATE_CONNECTED 1 -#define BLKIF_STATE_SUSPENDED 2 - -#ifdef notyet -static char *blkif_state_name[] = { - [BLKIF_STATE_DISCONNECTED] = "disconnected", - [BLKIF_STATE_CONNECTED] = "connected", - [BLKIF_STATE_SUSPENDED] = "closed", -}; - -static char * blkif_status_name[] = { - [BLKIF_INTERFACE_STATUS_CLOSED] = "closed", - [BLKIF_INTERFACE_STATUS_DISCONNECTED] = "disconnected", - [BLKIF_INTERFACE_STATUS_CONNECTED] = "connected", - [BLKIF_INTERFACE_STATUS_CHANGED] = "changed", -}; -#endif -#define WPRINTK(fmt, args...) printf("[XEN] " fmt, ##args) -#if 0 -#define DPRINTK(fmt, args...) printf("[XEN] %s:%d" fmt ".\n", __FUNCTION__, __LINE__,##args) -#else -#define DPRINTK(fmt, args...) -#endif - -static grant_ref_t gref_head; -#define MAXIMUM_OUTSTANDING_BLOCK_REQS \ - (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE) - -static void kick_pending_request_queues(struct blkfront_info *); -static int blkif_open(struct disk *dp); -static int blkif_close(struct disk *dp); -static int blkif_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td); -static int blkif_queue_request(struct bio *bp); -static void xb_strategy(struct bio *bp); - - - -/* XXX move to xb_vbd.c when VBD update support is added */ -#define MAX_VBDS 64 - -#define XBD_SECTOR_SIZE 512 /* XXX: assume for now */ -#define XBD_SECTOR_SHFT 9 - -static struct mtx blkif_io_lock; - -static vm_paddr_t -pfn_to_mfn(vm_paddr_t pfn) -{ - return (phystomach(pfn << PAGE_SHIFT) >> PAGE_SHIFT); -} - - -int -xlvbd_add(blkif_sector_t capacity, int unit, uint16_t vdisk_info, uint16_t sector_size, - struct blkfront_info *info) -{ - struct xb_softc *sc; - int error = 0; - int unitno = unit - 767; - - sc = (struct xb_softc *)malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); - sc->xb_unit = unitno; - sc->xb_info = info; - info->sc = sc; - - memset(&sc->xb_disk, 0, sizeof(sc->xb_disk)); - sc->xb_disk = disk_alloc(); - sc->xb_disk->d_unit = unitno; - sc->xb_disk->d_open = blkif_open; - sc->xb_disk->d_close = blkif_close; - sc->xb_disk->d_ioctl = blkif_ioctl; - sc->xb_disk->d_strategy = xb_strategy; - sc->xb_disk->d_name = "xbd"; - sc->xb_disk->d_drv1 = sc; - sc->xb_disk->d_sectorsize = sector_size; - - /* XXX */ - sc->xb_disk->d_mediasize = capacity << XBD_SECTOR_SHFT; -#if 0 - sc->xb_disk->d_maxsize = DFLTPHYS; -#else /* XXX: xen can't handle large single i/o requests */ - sc->xb_disk->d_maxsize = 4096; -#endif -#ifdef notyet - XENPRINTF("attaching device 0x%x unit %d capacity %llu\n", - xb_diskinfo[sc->xb_unit].device, sc->xb_unit, - sc->xb_disk->d_mediasize); -#endif - sc->xb_disk->d_flags = 0; - disk_create(sc->xb_disk, DISK_VERSION_00); - bioq_init(&sc->xb_bioq); - - return error; -} - -void -xlvbd_del(struct blkfront_info *info) -{ - struct xb_softc *sc; - - sc = info->sc; - disk_destroy(sc->xb_disk); -} -/************************ end VBD support *****************/ - -/* - * Read/write routine for a buffer. Finds the proper unit, place it on - * the sortq and kick the controller. - */ -static void -xb_strategy(struct bio *bp) -{ - struct xb_softc *sc = (struct xb_softc *)bp->bio_disk->d_drv1; - - /* bogus disk? */ - if (sc == NULL) { - bp->bio_error = EINVAL; - bp->bio_flags |= BIO_ERROR; - goto bad; - } - - DPRINTK(""); - - /* - * Place it in the queue of disk activities for this disk - */ - mtx_lock(&blkif_io_lock); - bioq_disksort(&sc->xb_bioq, bp); - - xb_startio(sc); - mtx_unlock(&blkif_io_lock); - return; - - bad: - /* - * Correctly set the bio to indicate a failed tranfer. - */ - bp->bio_resid = bp->bio_bcount; - biodone(bp); - return; -} - - -/* Setup supplies the backend dir, virtual device. - -We place an event channel and shared frame entries. -We watch backend to wait if it's ok. */ -static int blkfront_probe(struct xenbus_device *dev, - const struct xenbus_device_id *id) -{ - int err, vdevice, i; - struct blkfront_info *info; - - /* FIXME: Use dynamic device id if this is not set. */ - err = xenbus_scanf(XBT_NIL, dev->nodename, - "virtual-device", "%i", &vdevice); - if (err != 1) { - xenbus_dev_fatal(dev, err, "reading virtual-device"); - printf("couldn't find virtual device"); - return (err); - } - - info = malloc(sizeof(*info), M_DEVBUF, M_NOWAIT|M_ZERO); - if (info == NULL) { - xenbus_dev_fatal(dev, ENOMEM, "allocating info structure"); - return ENOMEM; - } - - /* - * XXX debug only - */ - for (i = 0; i < sizeof(*info); i++) - if (((uint8_t *)info)[i] != 0) - panic("non-null memory"); - - info->shadow_free = 0; - info->xbdev = dev; - info->vdevice = vdevice; - info->connected = BLKIF_STATE_DISCONNECTED; - - /* work queue needed ? */ - for (i = 0; i < BLK_RING_SIZE; i++) - info->shadow[i].req.id = i+1; - info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; - - /* Front end dir is a number, which is used as the id. */ - info->handle = strtoul(strrchr(dev->nodename,'/')+1, NULL, 0); - dev->dev_driver_data = info; - - err = talk_to_backend(dev, info); - if (err) { - free(info, M_DEVBUF); - dev->dev_driver_data = NULL; - return err; - } - - return 0; -} - - -static int blkfront_resume(struct xenbus_device *dev) -{ - struct blkfront_info *info = dev->dev_driver_data; - int err; - - DPRINTK("blkfront_resume: %s\n", dev->nodename); - - blkif_free(info, 1); - - err = talk_to_backend(dev, info); - if (!err) - blkif_recover(info); - - return err; -} - -/* Common code used when first setting up, and when resuming. */ -static int talk_to_backend(struct xenbus_device *dev, - struct blkfront_info *info) -{ - const char *message = NULL; - struct xenbus_transaction xbt; - int err; - - /* Create shared ring, alloc event channel. */ - err = setup_blkring(dev, info); - if (err) - goto out; - - again: - err = xenbus_transaction_start(&xbt); - if (err) { - xenbus_dev_fatal(dev, err, "starting transaction"); - goto destroy_blkring; - } - - err = xenbus_printf(xbt, dev->nodename, - "ring-ref","%u", info->ring_ref); - if (err) { - message = "writing ring-ref"; - goto abort_transaction; - } - err = xenbus_printf(xbt, dev->nodename, - "event-channel", "%u", irq_to_evtchn_port(info->irq)); - if (err) { - message = "writing event-channel"; - goto abort_transaction; - } - - err = xenbus_transaction_end(xbt, 0); - if (err) { - if (err == -EAGAIN) - goto again; - xenbus_dev_fatal(dev, err, "completing transaction"); - goto destroy_blkring; - } - xenbus_switch_state(dev, XenbusStateInitialised); - - return 0; - - abort_transaction: - xenbus_transaction_end(xbt, 1); - if (message) - xenbus_dev_fatal(dev, err, "%s", message); - destroy_blkring: - blkif_free(info, 0); - out: - return err; -} - -static int -setup_blkring(struct xenbus_device *dev, struct blkfront_info *info) -{ - blkif_sring_t *sring; - int err; - - info->ring_ref = GRANT_INVALID_REF; - - sring = (blkif_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); - if (sring == NULL) { - xenbus_dev_fatal(dev, ENOMEM, "allocating shared ring"); - return ENOMEM; - } - SHARED_RING_INIT(sring); - FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); - - err = xenbus_grant_ring(dev, (vtomach(info->ring.sring) >> PAGE_SHIFT)); - if (err < 0) { - free(sring, M_DEVBUF); - info->ring.sring = NULL; - goto fail; - } - info->ring_ref = err; - - err = bind_listening_port_to_irqhandler(dev->otherend_id, - "xbd", (driver_intr_t *)blkif_int, info, - INTR_TYPE_BIO | INTR_MPSAFE, NULL); - if (err <= 0) { - xenbus_dev_fatal(dev, err, - "bind_evtchn_to_irqhandler failed"); - goto fail; - } - info->irq = err; - - return 0; - fail: - blkif_free(info, 0); - return err; -} - - -/** - * Callback received when the backend's state changes. - */ -static void backend_changed(struct xenbus_device *dev, - XenbusState backend_state) -{ - struct blkfront_info *info = dev->dev_driver_data; - - DPRINTK("blkfront:backend_changed.\n"); - - switch (backend_state) { - case XenbusStateUnknown: - case XenbusStateInitialising: - case XenbusStateInitWait: - case XenbusStateInitialised: - case XenbusStateClosed: - case XenbusStateReconfigured: - case XenbusStateReconfiguring: - break; - - case XenbusStateConnected: - connect(info); - break; - - case XenbusStateClosing: - if (info->users > 0) - xenbus_dev_error(dev, -EBUSY, - "Device in use; refusing to close"); - else - blkfront_closing(dev); -#ifdef notyet - bd = bdget(info->dev); - if (bd == NULL) - xenbus_dev_fatal(dev, -ENODEV, "bdget failed"); - - down(&bd->bd_sem); - if (info->users > 0) - xenbus_dev_error(dev, -EBUSY, - "Device in use; refusing to close"); - else - blkfront_closing(dev); - up(&bd->bd_sem); - bdput(bd); -#endif - } -} - -/* -** Invoked when the backend is finally 'ready' (and has told produced -** the details about the physical device - #sectors, size, etc). -*/ -static void -connect(struct blkfront_info *info) -{ - unsigned long sectors, sector_size; - unsigned int binfo; - int err; - - if( (info->connected == BLKIF_STATE_CONNECTED) || - (info->connected == BLKIF_STATE_SUSPENDED) ) - return; - - DPRINTK("blkfront.c:connect:%s.\n", info->xbdev->otherend); - - err = xenbus_gather(XBT_NIL, info->xbdev->otherend, - "sectors", "%lu", §ors, - "info", "%u", &binfo, - "sector-size", "%lu", §or_size, - NULL); - if (err) { - xenbus_dev_fatal(info->xbdev, err, - "reading backend fields at %s", - info->xbdev->otherend); - return; - } - err = xenbus_gather(XBT_NIL, info->xbdev->otherend, - "feature-barrier", "%lu", &info->feature_barrier, - NULL); - if (err) - info->feature_barrier = 0; - - xlvbd_add(sectors, info->vdevice, binfo, sector_size, info); - - (void)xenbus_switch_state(info->xbdev, XenbusStateConnected); - - /* Kick pending requests. */ - mtx_lock(&blkif_io_lock); - info->connected = BLKIF_STATE_CONNECTED; - kick_pending_request_queues(info); - mtx_unlock(&blkif_io_lock); - info->is_ready = 1; - -#if 0 - add_disk(info->gd); -#endif -} - -/** - * Handle the change of state of the backend to Closing. We must delete our - * device-layer structures now, to ensure that writes are flushed through to - * the backend. Once is this done, we can switch to Closed in - * acknowledgement. - */ -static void blkfront_closing(struct xenbus_device *dev) -{ - struct blkfront_info *info = dev->dev_driver_data; - - DPRINTK("blkfront_closing: %s removed\n", dev->nodename); - - if (info->mi) { - DPRINTK("Calling xlvbd_del\n"); - xlvbd_del(info); - info->mi = NULL; - } - - xenbus_switch_state(dev, XenbusStateClosed); -} - - -static int blkfront_remove(struct xenbus_device *dev) -{ - struct blkfront_info *info = dev->dev_driver_data; - - DPRINTK("blkfront_remove: %s removed\n", dev->nodename); - - blkif_free(info, 0); - - free(info, M_DEVBUF); - - return 0; -} - - -static inline int -GET_ID_FROM_FREELIST(struct blkfront_info *info) -{ - unsigned long nfree = info->shadow_free; - - KASSERT(nfree <= BLK_RING_SIZE, ("free %lu > RING_SIZE", nfree)); - info->shadow_free = info->shadow[nfree].req.id; - info->shadow[nfree].req.id = 0x0fffffee; /* debug */ - return nfree; -} - -static inline void -ADD_ID_TO_FREELIST(struct blkfront_info *info, unsigned long id) -{ - info->shadow[id].req.id = info->shadow_free; - info->shadow[id].request = 0; - info->shadow_free = id; -} - -static inline void -flush_requests(struct blkfront_info *info) -{ - int notify; - - RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify); - - if (notify) - notify_remote_via_irq(info->irq); -} - -static void -kick_pending_request_queues(struct blkfront_info *info) -{ - /* XXX check if we can't simplify */ -#if 0 - if (!RING_FULL(&info->ring)) { - /* Re-enable calldowns. */ - blk_start_queue(info->rq); - /* Kick things off immediately. */ - do_blkif_request(info->rq); - } -#endif - if (!RING_FULL(&info->ring)) { -#if 0 - sc = LIST_FIRST(&xbsl_head); - LIST_REMOVE(sc, entry); - /* Re-enable calldowns. */ - blk_start_queue(di->rq); -#endif - /* Kick things off immediately. */ - xb_startio(info->sc); - } -} - -#if 0 -/* XXX */ -static void blkif_restart_queue(void *arg) -{ - struct blkfront_info *info = (struct blkfront_info *)arg; - - mtx_lock(&blkif_io_lock); - kick_pending_request_queues(info); - mtx_unlock(&blkif_io_lock); -} -#endif - -static void blkif_restart_queue_callback(void *arg) -{ -#if 0 - struct blkfront_info *info = (struct blkfront_info *)arg; - /* XXX BSD equiv ? */ - - schedule_work(&info->work); -#endif -} - -static int -blkif_open(struct disk *dp) -{ - struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; - - if (sc == NULL) { - printk("xb%d: not found", sc->xb_unit); - return (ENXIO); - } - - sc->xb_flags |= XB_OPEN; - sc->xb_info->users++; - return (0); -} - -static int -blkif_close(struct disk *dp) -{ - struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; - - if (sc == NULL) - return (ENXIO); - sc->xb_flags &= ~XB_OPEN; - if (--(sc->xb_info->users) == 0) { - /* Check whether we have been instructed to close. We will - have ignored this request initially, as the device was - still mounted. */ - struct xenbus_device * dev = sc->xb_info->xbdev; - XenbusState state = xenbus_read_driver_state(dev->otherend); - - if (state == XenbusStateClosing) - blkfront_closing(dev); - } - return (0); -} - -static int -blkif_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) -{ - struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; - - if (sc == NULL) - return (ENXIO); - - return (ENOTTY); -} - - -/* - * blkif_queue_request - * - * request block io - * - * id: for guest use only. - * operation: BLKIF_OP_{READ,WRITE,PROBE} - * buffer: buffer to read/write into. this should be a - * virtual address in the guest os. - */ -static int blkif_queue_request(struct bio *bp) -{ - caddr_t alignbuf; - vm_paddr_t buffer_ma; - blkif_request_t *ring_req; - unsigned long id; - uint64_t fsect, lsect; - struct xb_softc *sc = (struct xb_softc *)bp->bio_disk->d_drv1; - struct blkfront_info *info = sc->xb_info; - int ref; - - if (unlikely(sc->xb_info->connected != BLKIF_STATE_CONNECTED)) - return 1; - - if (gnttab_alloc_grant_references( - BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) { - gnttab_request_free_callback( - &info->callback, - blkif_restart_queue_callback, - info, - BLKIF_MAX_SEGMENTS_PER_REQUEST); - return 1; - } - - /* Check if the buffer is properly aligned */ - if ((vm_offset_t)bp->bio_data & PAGE_MASK) { - int align = (bp->bio_bcount < PAGE_SIZE/2) ? XBD_SECTOR_SIZE : - PAGE_SIZE; - caddr_t newbuf = malloc(bp->bio_bcount + align, M_DEVBUF, - M_NOWAIT); - - alignbuf = (char *)roundup2((u_long)newbuf, align); - - /* save a copy of the current buffer */ - bp->bio_driver1 = newbuf; - bp->bio_driver2 = alignbuf; - - /* Copy the data for a write */ - if (bp->bio_cmd == BIO_WRITE) - bcopy(bp->bio_data, alignbuf, bp->bio_bcount); - } else - alignbuf = bp->bio_data; - - /* Fill out a communications ring structure. */ - ring_req = RING_GET_REQUEST(&info->ring, - info->ring.req_prod_pvt); - id = GET_ID_FROM_FREELIST(info); - info->shadow[id].request = (unsigned long)bp; - - ring_req->id = id; - ring_req->operation = (bp->bio_cmd == BIO_READ) ? BLKIF_OP_READ : - BLKIF_OP_WRITE; - - ring_req->sector_number= (blkif_sector_t)bp->bio_pblkno; - ring_req->handle = (blkif_vdev_t)(uintptr_t)sc->xb_disk; - - ring_req->nr_segments = 0; /* XXX not doing scatter/gather since buffer - * chaining is not supported. - */ - - buffer_ma = vtomach(alignbuf); - fsect = (buffer_ma & PAGE_MASK) >> XBD_SECTOR_SHFT; - lsect = fsect + (bp->bio_bcount >> XBD_SECTOR_SHFT) - 1; - /* install a grant reference. */ - ref = gnttab_claim_grant_reference(&gref_head); - KASSERT( ref != -ENOSPC, ("grant_reference failed") ); - - gnttab_grant_foreign_access_ref( - ref, - info->xbdev->otherend_id, - buffer_ma >> PAGE_SHIFT, - ring_req->operation & 1 ); /* ??? */ - info->shadow[id].frame[ring_req->nr_segments] = - buffer_ma >> PAGE_SHIFT; - - ring_req->seg[ring_req->nr_segments] = - (struct blkif_request_segment) { - .gref = ref, - .first_sect = fsect, - .last_sect = lsect }; - - ring_req->nr_segments++; - KASSERT((buffer_ma & (XBD_SECTOR_SIZE-1)) == 0, - ("XEN buffer must be sector aligned")); - KASSERT(lsect <= 7, - ("XEN disk driver data cannot cross a page boundary")); - - buffer_ma &= ~PAGE_MASK; - - info->ring.req_prod_pvt++; - - /* Keep a private copy so we can reissue requests when recovering. */ - info->shadow[id].req = *ring_req; - - gnttab_free_grant_references(gref_head); - - return 0; -} - - - -/* - * Dequeue buffers and place them in the shared communication ring. - * Return when no more requests can be accepted or all buffers have - * been queued. - * - * Signal XEN once the ring has been filled out. - */ -static void -xb_startio(struct xb_softc *sc) -{ - struct bio *bp; - int queued = 0; - struct blkfront_info *info = sc->xb_info; - DPRINTK(""); - - mtx_assert(&blkif_io_lock, MA_OWNED); - - while ((bp = bioq_takefirst(&sc->xb_bioq)) != NULL) { - - if (RING_FULL(&info->ring)) - goto wait; - - if (blkif_queue_request(bp)) { - wait: - bioq_insert_head(&sc->xb_bioq, bp); - break; - } - queued++; - } - - if (queued != 0) - flush_requests(sc->xb_info); -} - -static void -blkif_int(void *xsc) -{ - struct xb_softc *sc = NULL; - struct bio *bp; - blkif_response_t *bret; - RING_IDX i, rp; - struct blkfront_info *info = xsc; - DPRINTK(""); - - TRACE_ENTER; - - mtx_lock(&blkif_io_lock); - - if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) { - mtx_unlock(&blkif_io_lock); - return; - } - - again: - rp = info->ring.sring->rsp_prod; - rmb(); /* Ensure we see queued responses up to 'rp'. */ - - for (i = info->ring.rsp_cons; i != rp; i++) { - unsigned long id; - - bret = RING_GET_RESPONSE(&info->ring, i); - id = bret->id; - bp = (struct bio *)info->shadow[id].request; - - blkif_completion(&info->shadow[id]); - - ADD_ID_TO_FREELIST(info, id); - - switch (bret->operation) { - case BLKIF_OP_READ: - /* had an unaligned buffer that needs to be copied */ - if (bp->bio_driver1) - bcopy(bp->bio_driver2, bp->bio_data, bp->bio_bcount); - /* FALLTHROUGH */ - case BLKIF_OP_WRITE: - - /* free the copy buffer */ - if (bp->bio_driver1) { - free(bp->bio_driver1, M_DEVBUF); - bp->bio_driver1 = NULL; - } - - if ( unlikely(bret->status != BLKIF_RSP_OKAY) ) { - printf("Bad return from blkdev data request: %x\n", - bret->status); - bp->bio_flags |= BIO_ERROR; - } - - sc = (struct xb_softc *)bp->bio_disk->d_drv1; - - if (bp->bio_flags & BIO_ERROR) - bp->bio_error = EIO; - else - bp->bio_resid = 0; - - biodone(bp); - break; - default: - panic("received invalid operation"); - break; - } - } - - info->ring.rsp_cons = i; - - if (i != info->ring.req_prod_pvt) { - int more_to_do; - RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do); - if (more_to_do) - goto again; - } else { - info->ring.sring->rsp_event = i + 1; - } - - kick_pending_request_queues(info); - - mtx_unlock(&blkif_io_lock); -} - -static void -blkif_free(struct blkfront_info *info, int suspend) -{ - -/* Prevent new requests being issued until we fix things up. */ - mtx_lock(&blkif_io_lock); - info->connected = suspend ? - BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED; - mtx_unlock(&blkif_io_lock); - - /* Free resources associated with old device channel. */ - if (info->ring_ref != GRANT_INVALID_REF) { - gnttab_end_foreign_access(info->ring_ref, - info->ring.sring); - info->ring_ref = GRANT_INVALID_REF; - info->ring.sring = NULL; - } - if (info->irq) - unbind_from_irqhandler(info->irq, info); - info->irq = 0; - -} - -static void -blkif_completion(struct blk_shadow *s) -{ - int i; - - for (i = 0; i < s->req.nr_segments; i++) - gnttab_end_foreign_access(s->req.seg[i].gref, 0UL); -} - -static void -blkif_recover(struct blkfront_info *info) -{ - int i, j; - blkif_request_t *req; - struct blk_shadow *copy; - - /* Stage 1: Make a safe copy of the shadow state. */ - copy = (struct blk_shadow *)malloc(sizeof(info->shadow), M_DEVBUF, M_NOWAIT|M_ZERO); - PANIC_IF(copy == NULL); - memcpy(copy, info->shadow, sizeof(info->shadow)); - - /* Stage 2: Set up free list. */ - memset(&info->shadow, 0, sizeof(info->shadow)); - for (i = 0; i < BLK_RING_SIZE; i++) - info->shadow[i].req.id = i+1; - info->shadow_free = info->ring.req_prod_pvt; - info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; - - /* Stage 3: Find pending requests and requeue them. */ - for (i = 0; i < BLK_RING_SIZE; i++) { - /* Not in use? */ - if (copy[i].request == 0) - continue; - - /* Grab a request slot and copy shadow state into it. */ - req = RING_GET_REQUEST( - &info->ring, info->ring.req_prod_pvt); - *req = copy[i].req; - - /* We get a new request id, and must reset the shadow state. */ - req->id = GET_ID_FROM_FREELIST(info); - memcpy(&info->shadow[req->id], ©[i], sizeof(copy[i])); - - /* Rewrite any grant references invalidated by suspend/resume. */ - for (j = 0; j < req->nr_segments; j++) - gnttab_grant_foreign_access_ref( - req->seg[j].gref, - info->xbdev->otherend_id, - pfn_to_mfn(info->shadow[req->id].frame[j]), - 0 /* assume not readonly */); - - info->shadow[req->id].req = *req; - - info->ring.req_prod_pvt++; - } - - free(copy, M_DEVBUF); - - xenbus_switch_state(info->xbdev, XenbusStateConnected); - - /* Now safe for us to use the shared ring */ - mtx_lock(&blkif_io_lock); - info->connected = BLKIF_STATE_CONNECTED; - mtx_unlock(&blkif_io_lock); - - /* Send off requeued requests */ - mtx_lock(&blkif_io_lock); - flush_requests(info); - - /* Kick any other new requests queued since we resumed */ - kick_pending_request_queues(info); - mtx_unlock(&blkif_io_lock); -} - -static int -blkfront_is_ready(struct xenbus_device *dev) -{ - struct blkfront_info *info = dev->dev_driver_data; - - return info->is_ready; -} - -static struct xenbus_device_id blkfront_ids[] = { - { "vbd" }, - { "" } -}; - - -static struct xenbus_driver blkfront = { - .name = "vbd", - .ids = blkfront_ids, - .probe = blkfront_probe, - .remove = blkfront_remove, - .resume = blkfront_resume, - .otherend_changed = backend_changed, - .is_ready = blkfront_is_ready, -}; - - - -static void -xenbus_init(void) -{ - xenbus_register_frontend(&blkfront); -} - -MTX_SYSINIT(ioreq, &blkif_io_lock, "BIO LOCK", MTX_NOWITNESS); /* XXX how does one enroll a lock? */ -SYSINIT(xbdev, SI_SUB_PSEUDO, SI_ORDER_SECOND, xenbus_init, NULL); - - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 8 - * tab-width: 4 - * indent-tabs-mode: t - * End: - */ diff --git a/sys/dev/xen/blkfront/block.h b/sys/dev/xen/blkfront/block.h deleted file mode 100644 index 0d14459..0000000 --- a/sys/dev/xen/blkfront/block.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * $FreeBSD$ - */ - - -#ifndef __XEN_DRIVERS_BLOCK_H__ -#define __XEN_DRIVERS_BLOCK_H__ -#include <xen/interface/io/blkif.h> - -struct xlbd_type_info -{ - int partn_shift; - int disks_per_major; - char *devname; - char *diskname; -}; - -struct xlbd_major_info -{ - int major; - int index; - int usage; - struct xlbd_type_info *type; -}; - -struct blk_shadow { - blkif_request_t req; - unsigned long request; - unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST]; -}; - -#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE) - - -struct xb_softc { - device_t xb_dev; - struct disk *xb_disk; /* disk params */ - struct bio_queue_head xb_bioq; /* sort queue */ - int xb_unit; - int xb_flags; - struct blkfront_info *xb_info; - LIST_ENTRY(xb_softc) entry; -#define XB_OPEN (1<<0) /* drive is open (can't shut down) */ -}; - - -/* - * We have one of these per vbd, whether ide, scsi or 'other'. They - * hang in private_data off the gendisk structure. We may end up - * putting all kinds of interesting stuff here :-) - */ -struct blkfront_info -{ - struct xenbus_device *xbdev; - dev_t dev; - struct gendisk *gd; - int vdevice; - blkif_vdev_t handle; - int connected; - int ring_ref; - blkif_front_ring_t ring; - unsigned int irq; - struct xlbd_major_info *mi; -#if 0 - request_queue_t *rq; - struct work_struct work; -#endif - struct gnttab_free_callback callback; - struct blk_shadow shadow[BLK_RING_SIZE]; - unsigned long shadow_free; - struct xb_softc *sc; - int feature_barrier; - int is_ready; - /** - * The number of people holding this device open. We won't allow a - * hot-unplug unless this is 0. - */ - int users; -}; -/* Note that xlvbd_add doesn't call add_disk for you: you're expected - to call add_disk on info->gd once the disk is properly connected - up. */ -int xlvbd_add(blkif_sector_t capacity, int device, - uint16_t vdisk_info, uint16_t sector_size, struct blkfront_info *info); -void xlvbd_del(struct blkfront_info *info); - -#endif /* __XEN_DRIVERS_BLOCK_H__ */ - diff --git a/sys/dev/xen/console/console.c b/sys/dev/xen/console/console.c deleted file mode 100644 index 64c2dfd..0000000 --- a/sys/dev/xen/console/console.c +++ /dev/null @@ -1,559 +0,0 @@ -#include <sys/cdefs.h> - - -#include <sys/param.h> -#include <sys/module.h> -#include <sys/systm.h> -#include <sys/consio.h> -#include <sys/proc.h> -#include <sys/uio.h> -#include <sys/tty.h> -#include <sys/systm.h> -#include <sys/taskqueue.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/bus.h> -#include <machine/stdarg.h> -#include <machine/xen/xen-os.h> -#include <machine/xen/hypervisor.h> -#include <machine/xen/xen_intr.h> -#include <sys/cons.h> -#include <sys/proc.h> - -#include <dev/xen/console/xencons_ring.h> -#include <xen/interface/io/console.h> - - -#include "opt_ddb.h" -#ifdef DDB -#include <ddb/ddb.h> -#endif - -static char driver_name[] = "xc"; -devclass_t xc_devclass; /* do not make static */ -static void xcstart (struct tty *); -static int xcparam (struct tty *, struct termios *); -static void xcstop (struct tty *, int); -static void xc_timeout(void *); -static void __xencons_tx_flush(void); -static boolean_t xcons_putc(int c); - -/* switch console so that shutdown can occur gracefully */ -static void xc_shutdown(void *arg, int howto); -static int xc_mute; - -static void xcons_force_flush(void); -static void xencons_priv_interrupt(void *); - -static cn_probe_t xccnprobe; -static cn_init_t xccninit; -static cn_getc_t xccngetc; -static cn_putc_t xccnputc; -static cn_putc_t xccnputc_dom0; -static cn_checkc_t xccncheckc; - -#define XC_POLLTIME (hz/10) - -CONS_DRIVER(xc, xccnprobe, xccninit, NULL, xccngetc, - xccncheckc, xccnputc, NULL); - -static int xen_console_up; -static boolean_t xc_start_needed; -static struct callout xc_callout; -struct mtx cn_mtx; - -#define RBUF_SIZE 1024 -#define RBUF_MASK(_i) ((_i)&(RBUF_SIZE-1)) -#define WBUF_SIZE 4096 -#define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1)) -static char wbuf[WBUF_SIZE]; -static char rbuf[RBUF_SIZE]; -static int rc, rp; -static unsigned int cnsl_evt_reg; -static unsigned int wc, wp; /* write_cons, write_prod */ - -#define CDEV_MAJOR 12 -#define XCUNIT(x) (minor(x)) -#define ISTTYOPEN(tp) ((tp) && ((tp)->t_state & TS_ISOPEN)) -#define CN_LOCK_INIT(x, _name) \ - mtx_init(&x, _name, NULL, MTX_SPIN|MTX_RECURSE) - -#define CN_LOCK(l) \ - do { \ - if (panicstr == NULL) \ - mtx_lock_spin(&(l)); \ - } while (0) -#define CN_UNLOCK(l) \ - do { \ - if (panicstr == NULL) \ - mtx_unlock_spin(&(l)); \ - } while (0) -#define CN_LOCK_ASSERT(x) mtx_assert(&x, MA_OWNED) -#define CN_LOCK_DESTROY(x) mtx_destroy(&x) - - -static struct tty *xccons; - -struct xc_softc { - int xc_unit; - struct cdev *xc_dev; -}; - - -static d_open_t xcopen; -static d_close_t xcclose; -static d_ioctl_t xcioctl; - -static struct cdevsw xc_cdevsw = { - .d_version = D_VERSION, - .d_flags = D_TTY | D_NEEDGIANT, - .d_name = driver_name, - .d_open = xcopen, - .d_close = xcclose, - .d_read = ttyread, - .d_write = ttywrite, - .d_ioctl = xcioctl, - .d_poll = ttypoll, - .d_kqfilter = ttykqfilter, -}; - -static void -xccnprobe(struct consdev *cp) -{ - cp->cn_pri = CN_REMOTE; - cp->cn_tp = xccons; - sprintf(cp->cn_name, "%s0", driver_name); -} - - -static void -xccninit(struct consdev *cp) -{ - CN_LOCK_INIT(cn_mtx,"XCONS LOCK"); - -} -int -xccngetc(struct consdev *dev) -{ - int c; - if (xc_mute) - return 0; - do { - if ((c = xccncheckc(dev)) == -1) { - /* polling without sleeping in Xen doesn't work well. - * Sleeping gives other things like clock a chance to - * run - */ - tsleep(&cn_mtx, PWAIT | PCATCH, "console sleep", - XC_POLLTIME); - } - } while(c == -1); - return c; -} - -int -xccncheckc(struct consdev *dev) -{ - int ret = (xc_mute ? 0 : -1); - if (xencons_has_input()) - xencons_handle_input(NULL); - - CN_LOCK(cn_mtx); - if ((rp - rc)) { - /* we need to return only one char */ - ret = (int)rbuf[RBUF_MASK(rc)]; - rc++; - } - CN_UNLOCK(cn_mtx); - return(ret); -} - -static void -xccnputc(struct consdev *dev, int c) -{ - xcons_putc(c); -} - -static void -xccnputc_dom0(struct consdev *dev, int c) -{ - HYPERVISOR_console_io(CONSOLEIO_write, 1, (char *)&c); -} - -extern int db_active; -static boolean_t -xcons_putc(int c) -{ - int force_flush = xc_mute || -#ifdef DDB - db_active || -#endif - panicstr; /* we're not gonna recover, so force - * flush - */ - - if ((wp-wc) < (WBUF_SIZE-1)) { - if ((wbuf[WBUF_MASK(wp++)] = c) == '\n') { - wbuf[WBUF_MASK(wp++)] = '\r'; -#ifdef notyet - if (force_flush) - xcons_force_flush(); -#endif - } - } else if (force_flush) { -#ifdef notyet - xcons_force_flush(); -#endif - } - if (cnsl_evt_reg) - __xencons_tx_flush(); - - /* inform start path that we're pretty full */ - return ((wp - wc) >= WBUF_SIZE - 100) ? TRUE : FALSE; -} - -static void -xc_identify(driver_t *driver, device_t parent) -{ - device_t child; - child = BUS_ADD_CHILD(parent, 0, driver_name, 0); - device_set_driver(child, driver); - device_set_desc(child, "Xen Console"); -} - -static int -xc_probe(device_t dev) -{ - struct xc_softc *sc = (struct xc_softc *)device_get_softc(dev); - - sc->xc_unit = device_get_unit(dev); - return (0); -} - -static int -xc_attach(device_t dev) -{ - struct xc_softc *sc = (struct xc_softc *)device_get_softc(dev); - - - if (xen_start_info->flags & SIF_INITDOMAIN) { - xc_consdev.cn_putc = xccnputc_dom0; - } - - sc->xc_dev = make_dev(&xc_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "xc%r", 0); - xccons = ttyalloc(); - - sc->xc_dev->si_drv1 = (void *)sc; - sc->xc_dev->si_tty = xccons; - - xccons->t_oproc = xcstart; - xccons->t_param = xcparam; - xccons->t_stop = xcstop; - xccons->t_dev = sc->xc_dev; - - callout_init(&xc_callout, 0); - - xencons_ring_init(); - - cnsl_evt_reg = 1; - callout_reset(&xc_callout, XC_POLLTIME, xc_timeout, xccons); - - if (xen_start_info->flags & SIF_INITDOMAIN) { - PANIC_IF(bind_virq_to_irqhandler( - VIRQ_CONSOLE, - 0, - "console", - xencons_priv_interrupt, - INTR_TYPE_TTY) < 0); - - } - - - /* register handler to flush console on shutdown */ - if ((EVENTHANDLER_REGISTER(shutdown_post_sync, xc_shutdown, - NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) - printf("xencons: shutdown event registration failed!\n"); - - return (0); -} - -/* - * return 0 for all console input, force flush all output. - */ -static void -xc_shutdown(void *arg, int howto) -{ - xc_mute = 1; - xcons_force_flush(); -} - -void -xencons_rx(char *buf, unsigned len) -{ - int i; - struct tty *tp = xccons; - - for (i = 0; i < len; i++) { - if (xen_console_up) - (*linesw[tp->t_line]->l_rint)(buf[i], tp); - else - rbuf[RBUF_MASK(rp++)] = buf[i]; - } -} - -static void -__xencons_tx_flush(void) -{ - int sz, work_done = 0; - - CN_LOCK(cn_mtx); - while (wc != wp) { - int sent; - sz = wp - wc; - if (sz > (WBUF_SIZE - WBUF_MASK(wc))) - sz = WBUF_SIZE - WBUF_MASK(wc); - if (xen_start_info->flags & SIF_INITDOMAIN) { - HYPERVISOR_console_io(CONSOLEIO_write, sz, &wbuf[WBUF_MASK(wc)]); - wc += sz; - } else { - sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz); - if (sent == 0) - break; - wc += sent; - } - work_done = 1; - } - CN_UNLOCK(cn_mtx); - - /* - * ttwakeup calls routines using blocking locks - * - */ - if (work_done && xen_console_up && curthread->td_critnest == 0) - ttwakeup(xccons); -} - -void -xencons_tx(void) -{ - __xencons_tx_flush(); -} - -static void -xencons_priv_interrupt(void *arg) -{ - - static char rbuf[16]; - int l; - - while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0) - xencons_rx(rbuf, l); - - xencons_tx(); -} - -int -xcopen(struct cdev *dev, int flag, int mode, struct thread *td) -{ - struct xc_softc *sc; - int unit = XCUNIT(dev); - struct tty *tp; - int s, error; - - sc = (struct xc_softc *)device_get_softc( - devclass_get_device(xc_devclass, unit)); - if (sc == NULL) - return (ENXIO); - - tp = dev->si_tty; - s = spltty(); - if (!ISTTYOPEN(tp)) { - tp->t_state |= TS_CARR_ON; - ttychars(tp); - tp->t_iflag = TTYDEF_IFLAG; - tp->t_oflag = TTYDEF_OFLAG; - tp->t_cflag = TTYDEF_CFLAG|CLOCAL; - tp->t_lflag = TTYDEF_LFLAG; - tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; - xcparam(tp, &tp->t_termios); - ttsetwater(tp); - } else if (tp->t_state & TS_XCLUDE && suser(td)) { - splx(s); - return (EBUSY); - } - splx(s); - - xen_console_up = 1; - - error = (*linesw[tp->t_line]->l_open)(dev, tp); - return error; -} - -int -xcclose(struct cdev *dev, int flag, int mode, struct thread *td) -{ - struct tty *tp = dev->si_tty; - - if (tp == NULL) - return (0); - xen_console_up = 0; - - spltty(); - (*linesw[tp->t_line]->l_close)(tp, flag); - tty_close(tp); - spl0(); - return (0); -} - - -int -xcioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) -{ - struct tty *tp = dev->si_tty; - int error; - - error = (*linesw[tp->t_line]->l_ioctl)(tp, cmd, data, flag, td); - if (error != ENOIOCTL) - return (error); - - error = ttioctl(tp, cmd, data, flag); - - if (error != ENOIOCTL) - return (error); - - return (ENOTTY); -} - -static inline int -__xencons_put_char(int ch) -{ - char _ch = (char)ch; - if ((wp - wc) == WBUF_SIZE) - return 0; - wbuf[WBUF_MASK(wp++)] = _ch; - return 1; -} - - -static void -xcstart(struct tty *tp) -{ - boolean_t cons_full = FALSE; - - CN_LOCK(cn_mtx); - if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { - CN_UNLOCK(cn_mtx); - - ttwwakeup(tp); - return; - } - - tp->t_state |= TS_BUSY; - CN_UNLOCK(cn_mtx); - - while (tp->t_outq.c_cc != 0 && !cons_full) - cons_full = xcons_putc(getc(&tp->t_outq)); - - /* if the console is close to full leave our state as busy */ - if (!cons_full) { - CN_LOCK(cn_mtx); - tp->t_state &= ~TS_BUSY; - CN_UNLOCK(cn_mtx); - ttwwakeup(tp); - } else { - /* let the timeout kick us in a bit */ - xc_start_needed = TRUE; - } - -} - -static void -xcstop(struct tty *tp, int flag) -{ - - if (tp->t_state & TS_BUSY) { - if ((tp->t_state & TS_TTSTOP) == 0) { - tp->t_state |= TS_FLUSH; - } - } -} - -static void -xc_timeout(void *v) -{ - struct tty *tp; - int c; - - tp = (struct tty *)v; - - while ((c = xccncheckc(NULL)) != -1) { - if (tp->t_state & TS_ISOPEN) { - (*linesw[tp->t_line]->l_rint)(c, tp); - } - } - - if (xc_start_needed) { - xc_start_needed = FALSE; - xcstart(tp); - } - - callout_reset(&xc_callout, XC_POLLTIME, xc_timeout, tp); -} - -/* - * Set line parameters. - */ -int -xcparam(struct tty *tp, struct termios *t) -{ - tp->t_ispeed = t->c_ispeed; - tp->t_ospeed = t->c_ospeed; - tp->t_cflag = t->c_cflag; - return (0); -} - - -static device_method_t xc_methods[] = { - DEVMETHOD(device_identify, xc_identify), - DEVMETHOD(device_probe, xc_probe), - DEVMETHOD(device_attach, xc_attach), - {0, 0} -}; - -static driver_t xc_driver = { - driver_name, - xc_methods, - sizeof(struct xc_softc), -}; - -/*** Forcibly flush console data before dying. ***/ -void -xcons_force_flush(void) -{ - int sz; - - if (xen_start_info->flags & SIF_INITDOMAIN) - return; - - /* Spin until console data is flushed through to the domain controller. */ - while (wc != wp) { - int sent = 0; - if ((sz = wp - wc) == 0) - continue; - - sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz); - if (sent > 0) - wc += sent; - } -} - -DRIVER_MODULE(xc, nexus, xc_driver, xc_devclass, 0, 0); -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 8 - * tab-width: 4 - * indent-tabs-mode: t - * End: - */ diff --git a/sys/dev/xen/console/xencons_ring.c b/sys/dev/xen/console/xencons_ring.c deleted file mode 100644 index 3d232376..0000000 --- a/sys/dev/xen/console/xencons_ring.c +++ /dev/null @@ -1,153 +0,0 @@ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/module.h> -#include <sys/systm.h> -#include <sys/consio.h> -#include <sys/proc.h> -#include <sys/uio.h> -#include <sys/tty.h> -#include <sys/systm.h> -#include <sys/taskqueue.h> -#include <sys/conf.h> -#include <sys/kernel.h> -#include <sys/bus.h> -#include <machine/stdarg.h> -#include <machine/xen/xen-os.h> -#include <machine/xen/hypervisor.h> -#include <machine/xen/xen_intr.h> -#include <sys/cons.h> - - -#include <dev/xen/console/xencons_ring.h> -#include <machine/xen/evtchn.h> -#include <xen/interface/io/console.h> - - -#define console_evtchn console.domU.evtchn -extern char *console_page; - -static inline struct xencons_interface * -xencons_interface(void) -{ - return (struct xencons_interface *)console_page; -} - - -int -xencons_has_input(void) -{ - struct xencons_interface *intf; - - intf = xencons_interface(); - - return (intf->in_cons != intf->in_prod); -} - - -int -xencons_ring_send(const char *data, unsigned len) -{ - struct xencons_interface *intf; - XENCONS_RING_IDX cons, prod; - int sent; - - intf = xencons_interface(); - cons = intf->out_cons; - prod = intf->out_prod; - sent = 0; - - mb(); - PANIC_IF((prod - cons) > sizeof(intf->out)); - - while ((sent < len) && ((prod - cons) < sizeof(intf->out))) - intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++]; - - wmb(); - intf->out_prod = prod; - - notify_remote_via_evtchn(xen_start_info->console_evtchn); - - return sent; - -} - - -static xencons_receiver_func *xencons_receiver; - -void -xencons_handle_input(void *unused) -{ - struct xencons_interface *intf; - XENCONS_RING_IDX cons, prod; - - intf = xencons_interface(); - - cons = intf->in_cons; - prod = intf->in_prod; - - /* XXX needs locking */ - while (cons != prod) { - xencons_rx(intf->in + MASK_XENCONS_IDX(cons, intf->in), 1); - cons++; - } - - mb(); - intf->in_cons = cons; - - notify_remote_via_evtchn(xen_start_info->console_evtchn); - - xencons_tx(); -} - -void -xencons_ring_register_receiver(xencons_receiver_func *f) -{ - xencons_receiver = f; -} - -int -xencons_ring_init(void) -{ - int err; - - if (!xen_start_info->console_evtchn) - return 0; - - err = bind_caller_port_to_irqhandler(xen_start_info->console_evtchn, - "xencons", xencons_handle_input, NULL, - INTR_TYPE_MISC | INTR_MPSAFE, NULL); - if (err) { - return err; - } - - return 0; -} -#ifdef notyet -void -xencons_suspend(void) -{ - - if (!xen_start_info->console_evtchn) - return; - - unbind_evtchn_from_irqhandler(xen_start_info->console_evtchn, NULL); -} - -void -xencons_resume(void) -{ - - (void)xencons_ring_init(); -} -#endif -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 8 - * tab-width: 4 - * indent-tabs-mode: t - * End: - */ diff --git a/sys/dev/xen/console/xencons_ring.h b/sys/dev/xen/console/xencons_ring.h deleted file mode 100644 index fc97d95..0000000 --- a/sys/dev/xen/console/xencons_ring.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * $FreeBSD$ - * - */ -#ifndef _XENCONS_RING_H -#define _XENCONS_RING_H - -int xencons_ring_init(void); -int xencons_ring_send(const char *data, unsigned len); -void xencons_rx(char *buf, unsigned len); -void xencons_tx(void); - - -typedef void (xencons_receiver_func)(char *buf, unsigned len); -void xencons_ring_register_receiver(xencons_receiver_func *f); - -void xencons_handle_input(void *unused); -int xencons_has_input(void); - -#endif /* _XENCONS_RING_H */ diff --git a/sys/dev/xen/evtchn/evtchn_dev.c b/sys/dev/xen/evtchn/evtchn_dev.c deleted file mode 100644 index a206708..0000000 --- a/sys/dev/xen/evtchn/evtchn_dev.c +++ /dev/null @@ -1,394 +0,0 @@ -/****************************************************************************** - * evtchn.c - * - * Xenolinux driver for receiving and demuxing event-channel signals. - * - * Copyright (c) 2004, K A Fraser - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/uio.h> -#include <sys/bus.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/mutex.h> -#include <sys/selinfo.h> -#include <sys/poll.h> -#include <sys/conf.h> -#include <sys/fcntl.h> -#include <sys/ioccom.h> - -#include <machine/cpufunc.h> -#include <machine/intr_machdep.h> -#include <machine/xen-os.h> -#include <machine/xen_intr.h> -#include <machine/bus.h> -#include <sys/rman.h> -#include <machine/resource.h> -#include <machine/synch_bitops.h> - -#include <machine/hypervisor.h> - - -typedef struct evtchn_sotfc { - - struct selinfo ev_rsel; -} evtchn_softc_t; - - -#ifdef linuxcrap -/* NB. This must be shared amongst drivers if more things go in /dev/xen */ -static devfs_handle_t xen_dev_dir; -#endif - -/* Only one process may open /dev/xen/evtchn at any time. */ -static unsigned long evtchn_dev_inuse; - -/* 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)) -static uint16_t *ring; -static unsigned int ring_cons, ring_prod, ring_overflow; - -/* Which ports is user-space bound to? */ -static uint32_t bound_ports[32]; - -/* Unique address for processes to sleep on */ -static void *evtchn_waddr = ˚ - -static struct mtx lock, upcall_lock; - -static d_read_t evtchn_read; -static d_write_t evtchn_write; -static d_ioctl_t evtchn_ioctl; -static d_poll_t evtchn_poll; -static d_open_t evtchn_open; -static d_close_t evtchn_close; - - -void -evtchn_device_upcall(int port) -{ - mtx_lock(&upcall_lock); - - mask_evtchn(port); - clear_evtchn(port); - - if ( ring != NULL ) { - if ( (ring_prod - ring_cons) < EVTCHN_RING_SIZE ) { - ring[EVTCHN_RING_MASK(ring_prod)] = (uint16_t)port; - if ( ring_cons == ring_prod++ ) { - wakeup(evtchn_waddr); - } - } - else { - ring_overflow = 1; - } - } - - mtx_unlock(&upcall_lock); -} - -static void -__evtchn_reset_buffer_ring(void) -{ - /* Initialise the ring to empty. Clear errors. */ - ring_cons = ring_prod = ring_overflow = 0; -} - -static int -evtchn_read(struct cdev *dev, struct uio *uio, int ioflag) -{ - int rc; - unsigned int count, c, p, sst = 0, bytes1 = 0, bytes2 = 0; - count = uio->uio_resid; - - count &= ~1; /* even number of bytes */ - - if ( count == 0 ) - { - rc = 0; - goto out; - } - - if ( count > PAGE_SIZE ) - count = PAGE_SIZE; - - for ( ; ; ) { - if ( (c = ring_cons) != (p = ring_prod) ) - break; - - if ( ring_overflow ) { - rc = EFBIG; - goto out; - } - - if (sst != 0) { - rc = EINTR; - goto out; - } - - /* PCATCH == check for signals before and after sleeping - * PWAIT == priority of waiting on resource - */ - sst = tsleep(evtchn_waddr, PWAIT|PCATCH, "evchwt", 10); - } - - /* 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(uint16_t); - bytes2 = EVTCHN_RING_MASK(p) * sizeof(uint16_t); - } - else { - bytes1 = (p - c) * sizeof(uint16_t); - 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; - } - - if ( uiomove(&ring[EVTCHN_RING_MASK(c)], bytes1, uio) || - ((bytes2 != 0) && uiomove(&ring[0], bytes2, uio))) - /* keeping this around as its replacement is not equivalent - * copyout(&ring[0], &buf[bytes1], bytes2) - */ - { - rc = EFAULT; - goto out; - } - - ring_cons += (bytes1 + bytes2) / sizeof(uint16_t); - - rc = bytes1 + bytes2; - - out: - - return rc; -} - -static int -evtchn_write(struct cdev *dev, struct uio *uio, int ioflag) -{ - int rc, i, count; - - count = uio->uio_resid; - - uint16_t *kbuf = (uint16_t *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); - - - if ( kbuf == NULL ) - return ENOMEM; - - count &= ~1; /* even number of bytes */ - - if ( count == 0 ) { - rc = 0; - goto out; - } - - if ( count > PAGE_SIZE ) - count = PAGE_SIZE; - - if ( uiomove(kbuf, count, uio) != 0 ) { - rc = EFAULT; - goto out; - } - - mtx_lock_spin(&lock); - for ( i = 0; i < (count/2); i++ ) - if ( test_bit(kbuf[i], &bound_ports[0]) ) - unmask_evtchn(kbuf[i]); - mtx_unlock_spin(&lock); - - rc = count; - - out: - free(kbuf, M_DEVBUF); - return rc; -} - -static int -evtchn_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg, - int mode, struct thread *td __unused) -{ - int rc = 0; - - mtx_lock_spin(&lock); - - switch ( cmd ) - { - case EVTCHN_RESET: - __evtchn_reset_buffer_ring(); - break; - case EVTCHN_BIND: - if ( !synch_test_and_set_bit((int)arg, &bound_ports[0]) ) - unmask_evtchn((int)arg); - else - rc = EINVAL; - break; - case EVTCHN_UNBIND: - if ( synch_test_and_clear_bit((int)arg, &bound_ports[0]) ) - mask_evtchn((int)arg); - else - rc = EINVAL; - break; - default: - rc = ENOSYS; - break; - } - - mtx_unlock_spin(&lock); - - return rc; -} - -static int -evtchn_poll(struct cdev *dev, int poll_events, struct thread *td) -{ - - evtchn_softc_t *sc; - unsigned int mask = POLLOUT | POLLWRNORM; - - sc = dev->si_drv1; - - if ( ring_cons != ring_prod ) - mask |= POLLIN | POLLRDNORM; - else if ( ring_overflow ) - mask = POLLERR; - else - selrecord(td, &sc->ev_rsel); - - - return mask; -} - - -static int -evtchn_open(struct cdev *dev, int flag, int otyp, struct thread *td) -{ - uint16_t *_ring; - - if (flag & O_NONBLOCK) - return EBUSY; - - if ( synch_test_and_set_bit(0, &evtchn_dev_inuse) ) - return EBUSY; - - if ( (_ring = (uint16_t *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK)) == NULL ) - return ENOMEM; - - mtx_lock_spin(&lock); - ring = _ring; - __evtchn_reset_buffer_ring(); - mtx_unlock_spin(&lock); - - - return 0; -} - -static int -evtchn_close(struct cdev *dev, int flag, int otyp, struct thread *td __unused) -{ - int i; - - mtx_lock_spin(&lock); - if (ring != NULL) { - free(ring, M_DEVBUF); - ring = NULL; - } - for ( i = 0; i < NR_EVENT_CHANNELS; i++ ) - if ( synch_test_and_clear_bit(i, &bound_ports[0]) ) - mask_evtchn(i); - mtx_unlock_spin(&lock); - - evtchn_dev_inuse = 0; - - return 0; -} - -static struct cdevsw evtchn_devsw = { - d_version: D_VERSION, - d_open: evtchn_open, - d_close: evtchn_close, - d_read: evtchn_read, - d_write: evtchn_write, - d_ioctl: evtchn_ioctl, - d_poll: evtchn_poll, - d_name: "evtchn", - d_flags: 0, -}; - - -/* XXX - if this device is ever supposed to support use by more than one process - * this global static will have to go away - */ -static struct cdev *evtchn_dev; - - - -static int -evtchn_init(void *dummy __unused) -{ - /* XXX I believe we don't need these leaving them here for now until we - * have some semblance of it working - */ - mtx_init(&upcall_lock, "evtchup", NULL, MTX_DEF); - - /* (DEVFS) create '/dev/misc/evtchn'. */ - evtchn_dev = make_dev(&evtchn_devsw, 0, UID_ROOT, GID_WHEEL, 0600, "xen/evtchn"); - - mtx_init(&lock, "evch", NULL, MTX_SPIN | MTX_NOWITNESS); - - evtchn_dev->si_drv1 = malloc(sizeof(evtchn_softc_t), M_DEVBUF, M_WAITOK); - bzero(evtchn_dev->si_drv1, sizeof(evtchn_softc_t)); - - /* XXX I don't think we need any of this rubbish */ -#if 0 - if ( err != 0 ) - { - printk(KERN_ALERT "Could not register /dev/misc/evtchn\n"); - return err; - } - - /* (DEVFS) create directory '/dev/xen'. */ - xen_dev_dir = devfs_mk_dir(NULL, "xen", NULL); - - /* (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; -} - - -SYSINIT(evtchn_init, SI_SUB_DRIVERS, SI_ORDER_FIRST, evtchn_init, NULL); - - diff --git a/sys/dev/xen/netback/netback.c b/sys/dev/xen/netback/netback.c deleted file mode 100644 index 950a68c..0000000 --- a/sys/dev/xen/netback/netback.c +++ /dev/null @@ -1,1585 +0,0 @@ -/* - * Copyright (c) 2006, Cisco Systems, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Cisco Systems, Inc. nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/socket.h> -#include <sys/queue.h> -#include <sys/taskqueue.h> - -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/sysctl.h> - -#include <net/if.h> -#include <net/if_arp.h> -#include <net/if_types.h> -#include <net/ethernet.h> -#include <net/if_bridgevar.h> - -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/in_var.h> -#include <netinet/ip.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> - -#include <vm/vm_extern.h> -#include <vm/vm_kern.h> - -#include <machine/in_cksum.h> -#include <machine/xen-os.h> -#include <machine/hypervisor.h> -#include <machine/hypervisor-ifs.h> -#include <machine/xen_intr.h> -#include <machine/evtchn.h> -#include <machine/xenbus.h> -#include <machine/gnttab.h> -#include <machine/xen-public/memory.h> -#include <dev/xen/xenbus/xenbus_comms.h> - - -#ifdef XEN_NETBACK_DEBUG -#define DPRINTF(fmt, args...) \ - printf("netback (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) -#else -#define DPRINTF(fmt, args...) ((void)0) -#endif - -#ifdef XEN_NETBACK_DEBUG_LOTS -#define DDPRINTF(fmt, args...) \ - printf("netback (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) -#define DPRINTF_MBUF(_m) print_mbuf(_m, 0) -#define DPRINTF_MBUF_LEN(_m, _len) print_mbuf(_m, _len) -#else -#define DDPRINTF(fmt, args...) ((void)0) -#define DPRINTF_MBUF(_m) ((void)0) -#define DPRINTF_MBUF_LEN(_m, _len) ((void)0) -#endif - -#define WPRINTF(fmt, args...) \ - printf("netback (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) - -#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) -#define BUG_ON PANIC_IF - -#define IFNAME(_np) (_np)->ifp->if_xname - -#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE) -#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE) - -struct ring_ref { - vm_offset_t va; - grant_handle_t handle; - uint64_t bus_addr; -}; - -typedef struct netback_info { - - /* Schedule lists */ - STAILQ_ENTRY(netback_info) next_tx; - STAILQ_ENTRY(netback_info) next_rx; - int on_tx_sched_list; - int on_rx_sched_list; - - struct xenbus_device *xdev; - XenbusState frontend_state; - - domid_t domid; - int handle; - char *bridge; - - int rings_connected; - struct ring_ref tx_ring_ref; - struct ring_ref rx_ring_ref; - netif_tx_back_ring_t tx; - netif_rx_back_ring_t rx; - evtchn_port_t evtchn; - int irq; - void *irq_cookie; - - struct ifnet *ifp; - int ref_cnt; - - device_t ndev; - int attached; -} netif_t; - - -#define MAX_PENDING_REQS 256 -#define PKT_PROT_LEN 64 - -static struct { - netif_tx_request_t req; - netif_t *netif; -} pending_tx_info[MAX_PENDING_REQS]; -static uint16_t pending_ring[MAX_PENDING_REQS]; -typedef unsigned int PEND_RING_IDX; -#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1)) -static PEND_RING_IDX pending_prod, pending_cons; -#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons) - -static unsigned long mmap_vstart; -#define MMAP_VADDR(_req) (mmap_vstart + ((_req) * PAGE_SIZE)) - -/* Freed TX mbufs get batched on this ring before return to pending_ring. */ -static uint16_t dealloc_ring[MAX_PENDING_REQS]; -static PEND_RING_IDX dealloc_prod, dealloc_cons; - -static multicall_entry_t rx_mcl[NET_RX_RING_SIZE+1]; -static mmu_update_t rx_mmu[NET_RX_RING_SIZE]; -static gnttab_transfer_t grant_rx_op[NET_RX_RING_SIZE]; - -static grant_handle_t grant_tx_handle[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]; - -static struct task net_tx_task, net_rx_task; -static struct callout rx_task_callout; - -static STAILQ_HEAD(netback_tx_sched_list, netback_info) tx_sched_list = - STAILQ_HEAD_INITIALIZER(tx_sched_list); -static STAILQ_HEAD(netback_rx_sched_list, netback_info) rx_sched_list = - STAILQ_HEAD_INITIALIZER(rx_sched_list); -static struct mtx tx_sched_list_lock; -static struct mtx rx_sched_list_lock; - -static int vif_unit_maker = 0; - -/* Protos */ -static void netback_start(struct ifnet *ifp); -static int netback_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); -static int vif_add_dev(struct xenbus_device *xdev); -static void disconnect_rings(netif_t *netif); - -#ifdef XEN_NETBACK_DEBUG_LOTS -/* Debug code to display the contents of an mbuf */ -static void -print_mbuf(struct mbuf *m, int max) -{ - int i, j=0; - printf("mbuf %08x len = %d", (unsigned int)m, m->m_pkthdr.len); - for (; m; m = m->m_next) { - unsigned char *d = m->m_data; - for (i=0; i < m->m_len; i++) { - if (max && j == max) - break; - if ((j++ % 16) == 0) - printf("\n%04x:", j); - printf(" %02x", d[i]); - } - } - printf("\n"); -} -#endif - - -#define MAX_MFN_ALLOC 64 -static unsigned long mfn_list[MAX_MFN_ALLOC]; -static unsigned int alloc_index = 0; - -static unsigned long -alloc_mfn(void) -{ - unsigned long mfn = 0; - struct xen_memory_reservation reservation = { - .extent_start = mfn_list, - .nr_extents = MAX_MFN_ALLOC, - .extent_order = 0, - .domid = DOMID_SELF - }; - if ( unlikely(alloc_index == 0) ) - alloc_index = HYPERVISOR_memory_op( - XENMEM_increase_reservation, &reservation); - if ( alloc_index != 0 ) - mfn = mfn_list[--alloc_index]; - return mfn; -} - -static unsigned long -alloc_empty_page_range(unsigned long nr_pages) -{ - void *pages; - int i = 0, j = 0; - multicall_entry_t mcl[17]; - unsigned long mfn_list[16]; - struct xen_memory_reservation reservation = { - .extent_start = mfn_list, - .nr_extents = 0, - .address_bits = 0, - .extent_order = 0, - .domid = DOMID_SELF - }; - - pages = malloc(nr_pages*PAGE_SIZE, M_DEVBUF, M_NOWAIT); - if (pages == NULL) - return 0; - - memset(mcl, 0, sizeof(mcl)); - - while (i < nr_pages) { - unsigned long va = (unsigned long)pages + (i++ * PAGE_SIZE); - - mcl[j].op = __HYPERVISOR_update_va_mapping; - mcl[j].args[0] = va; - - mfn_list[j++] = vtomach(va) >> PAGE_SHIFT; - - xen_phys_machine[(vtophys(va) >> PAGE_SHIFT)] = INVALID_P2M_ENTRY; - - if (j == 16 || i == nr_pages) { - mcl[j-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_LOCAL; - - reservation.nr_extents = j; - - mcl[j].op = __HYPERVISOR_memory_op; - mcl[j].args[0] = XENMEM_decrease_reservation; - mcl[j].args[1] = (unsigned long)&reservation; - - (void)HYPERVISOR_multicall(mcl, j+1); - - mcl[j-1].args[MULTI_UVMFLAGS_INDEX] = 0; - j = 0; - } - } - - return (unsigned long)pages; -} - -#ifdef XEN_NETBACK_FIXUP_CSUM -static void -fixup_checksum(struct mbuf *m) -{ - struct ether_header *eh = mtod(m, struct ether_header *); - struct ip *ip = (struct ip *)(eh + 1); - int iphlen = ip->ip_hl << 2; - int iplen = ntohs(ip->ip_len); - - if ((m->m_pkthdr.csum_flags & CSUM_TCP)) { - struct tcphdr *th = (struct tcphdr *)((caddr_t)ip + iphlen); - th->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, - htons(IPPROTO_TCP + (iplen - iphlen))); - th->th_sum = in_cksum_skip(m, iplen + sizeof(*eh), sizeof(*eh) + iphlen); - m->m_pkthdr.csum_flags &= ~CSUM_TCP; - } else { - u_short csum; - struct udphdr *uh = (struct udphdr *)((caddr_t)ip + iphlen); - uh->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, - htons(IPPROTO_UDP + (iplen - iphlen))); - if ((csum = in_cksum_skip(m, iplen + sizeof(*eh), sizeof(*eh) + iphlen)) == 0) - csum = 0xffff; - uh->uh_sum = csum; - m->m_pkthdr.csum_flags &= ~CSUM_UDP; - } -} -#endif - -/* Add the interface to the specified bridge */ -static int -add_to_bridge(struct ifnet *ifp, char *bridge) -{ - struct ifdrv ifd; - struct ifbreq ifb; - struct ifnet *ifp_bridge = ifunit(bridge); - - if (!ifp_bridge) - return ENOENT; - - bzero(&ifd, sizeof(ifd)); - bzero(&ifb, sizeof(ifb)); - - strcpy(ifb.ifbr_ifsname, ifp->if_xname); - strcpy(ifd.ifd_name, ifp->if_xname); - ifd.ifd_cmd = BRDGADD; - ifd.ifd_len = sizeof(ifb); - ifd.ifd_data = &ifb; - - return bridge_ioctl_kern(ifp_bridge, SIOCSDRVSPEC, &ifd); - -} - -static int -netif_create(int handle, struct xenbus_device *xdev, char *bridge) -{ - netif_t *netif; - struct ifnet *ifp; - - netif = (netif_t *)malloc(sizeof(*netif), M_DEVBUF, M_NOWAIT | M_ZERO); - if (!netif) - return ENOMEM; - - netif->ref_cnt = 1; - netif->handle = handle; - netif->domid = xdev->otherend_id; - netif->xdev = xdev; - netif->bridge = bridge; - xdev->data = netif; - - /* Set up ifnet structure */ - ifp = netif->ifp = if_alloc(IFT_ETHER); - if (!ifp) { - if (bridge) - free(bridge, M_DEVBUF); - free(netif, M_DEVBUF); - return ENOMEM; - } - - ifp->if_softc = netif; - if_initname(ifp, "vif", - atomic_fetchadd_int(&vif_unit_maker, 1) /* ifno */ ); - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; - ifp->if_output = ether_output; - ifp->if_start = netback_start; - ifp->if_ioctl = netback_ioctl; - ifp->if_mtu = ETHERMTU; - ifp->if_snd.ifq_maxlen = NET_TX_RING_SIZE - 1; - - DPRINTF("Created %s for domid=%d handle=%d\n", IFNAME(netif), netif->domid, netif->handle); - - return 0; -} - -static void -netif_get(netif_t *netif) -{ - atomic_add_int(&netif->ref_cnt, 1); -} - -static void -netif_put(netif_t *netif) -{ - if (atomic_fetchadd_int(&netif->ref_cnt, -1) == 1) { - DPRINTF("%s\n", IFNAME(netif)); - disconnect_rings(netif); - if (netif->ifp) { - if_free(netif->ifp); - netif->ifp = NULL; - } - if (netif->bridge) - free(netif->bridge, M_DEVBUF); - free(netif, M_DEVBUF); - } -} - -static int -netback_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) -{ - switch (cmd) { - case SIOCSIFFLAGS: - DDPRINTF("%s cmd=SIOCSIFFLAGS flags=%x\n", - IFNAME((struct netback_info *)ifp->if_softc), ((struct ifreq *)data)->ifr_flags); - return 0; - } - - DDPRINTF("%s cmd=%lx\n", IFNAME((struct netback_info *)ifp->if_softc), cmd); - - return ether_ioctl(ifp, cmd, data); -} - -static inline void -maybe_schedule_tx_action(void) -{ - smp_mb(); - if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) && !STAILQ_EMPTY(&tx_sched_list)) - taskqueue_enqueue(taskqueue_swi, &net_tx_task); -} - -/* Removes netif from front of list and does not call netif_put() (caller must) */ -static netif_t * -remove_from_tx_schedule_list(void) -{ - netif_t *netif; - - mtx_lock(&tx_sched_list_lock); - - if ((netif = STAILQ_FIRST(&tx_sched_list))) { - STAILQ_REMOVE(&tx_sched_list, netif, netback_info, next_tx); - STAILQ_NEXT(netif, next_tx) = NULL; - netif->on_tx_sched_list = 0; - } - - mtx_unlock(&tx_sched_list_lock); - - return netif; -} - -/* Adds netif to end of list and calls netif_get() */ -static void -add_to_tx_schedule_list_tail(netif_t *netif) -{ - if (netif->on_tx_sched_list) - return; - - mtx_lock(&tx_sched_list_lock); - if (!netif->on_tx_sched_list && (netif->ifp->if_drv_flags & IFF_DRV_RUNNING)) { - netif_get(netif); - STAILQ_INSERT_TAIL(&tx_sched_list, netif, next_tx); - netif->on_tx_sched_list = 1; - } - mtx_unlock(&tx_sched_list_lock); -} - -/* - * Note on CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER: - * If this driver is pipelining transmit requests then we can be very - * aggressive in avoiding new-packet notifications -- frontend only needs to - * send a notification if there are no outstanding unreceived responses. - * If we may be buffer transmit buffers for any reason then we must be rather - * more conservative and treat this as the final check for pending work. - */ -static void -netif_schedule_tx_work(netif_t *netif) -{ - int more_to_do; - -#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER - more_to_do = RING_HAS_UNCONSUMED_REQUESTS(&netif->tx); -#else - RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do); -#endif - - if (more_to_do) { - DDPRINTF("Adding %s to tx sched list\n", IFNAME(netif)); - add_to_tx_schedule_list_tail(netif); - maybe_schedule_tx_action(); - } -} - -static struct mtx dealloc_lock; -MTX_SYSINIT(netback_dealloc, &dealloc_lock, "DEALLOC LOCK", MTX_SPIN | MTX_NOWITNESS); - -static void -netif_idx_release(uint16_t pending_idx) -{ - mtx_lock_spin(&dealloc_lock); - dealloc_ring[MASK_PEND_IDX(dealloc_prod++)] = pending_idx; - mtx_unlock_spin(&dealloc_lock); - - taskqueue_enqueue(taskqueue_swi, &net_tx_task); -} - -static void -make_tx_response(netif_t *netif, - uint16_t id, - int8_t st) -{ - RING_IDX i = netif->tx.rsp_prod_pvt; - netif_tx_response_t *resp; - int notify; - - resp = RING_GET_RESPONSE(&netif->tx, i); - resp->id = id; - resp->status = st; - - netif->tx.rsp_prod_pvt = ++i; - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify); - if (notify) - notify_remote_via_irq(netif->irq); - -#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER - if (i == netif->tx.req_cons) { - int more_to_do; - RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do); - if (more_to_do) - add_to_tx_schedule_list_tail(netif); - } -#endif -} - -inline static void -net_tx_action_dealloc(void) -{ - gnttab_unmap_grant_ref_t *gop; - uint16_t pending_idx; - PEND_RING_IDX dc, dp; - netif_t *netif; - int ret; - - dc = dealloc_cons; - dp = dealloc_prod; - - /* - * Free up any grants we have finished using - */ - gop = tx_unmap_ops; - while (dc != dp) { - pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)]; - gop->host_addr = MMAP_VADDR(pending_idx); - gop->dev_bus_addr = 0; - gop->handle = grant_tx_handle[pending_idx]; - gop++; - } - ret = HYPERVISOR_grant_table_op( - GNTTABOP_unmap_grant_ref, tx_unmap_ops, gop - tx_unmap_ops); - BUG_ON(ret); - - while (dealloc_cons != dp) { - pending_idx = dealloc_ring[MASK_PEND_IDX(dealloc_cons++)]; - - netif = pending_tx_info[pending_idx].netif; - - make_tx_response(netif, pending_tx_info[pending_idx].req.id, - NETIF_RSP_OKAY); - - pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; - - netif_put(netif); - } -} - -static void -netif_page_release(void *buf, void *args) -{ - uint16_t pending_idx = (unsigned int)args; - - DDPRINTF("pending_idx=%u\n", pending_idx); - - KASSERT(pending_idx < MAX_PENDING_REQS, ("%s: bad index %u", __func__, pending_idx)); - - netif_idx_release(pending_idx); -} - -static void -net_tx_action(void *context, int pending) -{ - struct mbuf *m; - netif_t *netif; - netif_tx_request_t txreq; - uint16_t pending_idx; - RING_IDX i; - gnttab_map_grant_ref_t *mop; - int ret, work_to_do; - struct mbuf *txq = NULL, *txq_last = NULL; - - if (dealloc_cons != dealloc_prod) - net_tx_action_dealloc(); - - mop = tx_map_ops; - while ((NR_PENDING_REQS < MAX_PENDING_REQS) && !STAILQ_EMPTY(&tx_sched_list)) { - - /* Get a netif from the list with work to do. */ - netif = remove_from_tx_schedule_list(); - - DDPRINTF("Processing %s (prod=%u, cons=%u)\n", - IFNAME(netif), netif->tx.sring->req_prod, netif->tx.req_cons); - - RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do); - if (!work_to_do) { - netif_put(netif); - continue; - } - - i = netif->tx.req_cons; - rmb(); /* Ensure that we see the request before we copy it. */ - memcpy(&txreq, RING_GET_REQUEST(&netif->tx, i), sizeof(txreq)); - - /* If we want credit-based scheduling, coud add it here - WORK */ - - netif->tx.req_cons++; - - netif_schedule_tx_work(netif); - - if (unlikely(txreq.size < ETHER_HDR_LEN) || - unlikely(txreq.size > (ETHER_MAX_LEN-ETHER_CRC_LEN))) { - WPRINTF("Bad packet size: %d\n", txreq.size); - make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); - netif_put(netif); - continue; - } - - /* No crossing a page as the payload mustn't fragment. */ - if (unlikely((txreq.offset + txreq.size) >= PAGE_SIZE)) { - WPRINTF("txreq.offset: %x, size: %u, end: %u\n", - txreq.offset, txreq.size, - (txreq.offset & PAGE_MASK) + txreq.size); - make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); - netif_put(netif); - continue; - } - - pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)]; - - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (!m) { - WPRINTF("Failed to allocate mbuf\n"); - make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); - netif_put(netif); - break; - } - m->m_pkthdr.rcvif = netif->ifp; - - if ((m->m_pkthdr.len = txreq.size) > PKT_PROT_LEN) { - struct mbuf *n; - MGET(n, M_DONTWAIT, MT_DATA); - if (!(m->m_next = n)) { - m_freem(m); - WPRINTF("Failed to allocate second mbuf\n"); - make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); - netif_put(netif); - break; - } - n->m_len = txreq.size - PKT_PROT_LEN; - m->m_len = PKT_PROT_LEN; - } else - m->m_len = txreq.size; - - mop->host_addr = MMAP_VADDR(pending_idx); - mop->dom = netif->domid; - mop->ref = txreq.gref; - mop->flags = GNTMAP_host_map | GNTMAP_readonly; - mop++; - - memcpy(&pending_tx_info[pending_idx].req, - &txreq, sizeof(txreq)); - pending_tx_info[pending_idx].netif = netif; - *((uint16_t *)m->m_data) = pending_idx; - - if (txq_last) - txq_last->m_nextpkt = m; - else - txq = m; - txq_last = m; - - pending_cons++; - - if ((mop - tx_map_ops) >= ARRAY_SIZE(tx_map_ops)) - break; - } - - if (!txq) - return; - - ret = HYPERVISOR_grant_table_op( - GNTTABOP_map_grant_ref, tx_map_ops, mop - tx_map_ops); - BUG_ON(ret); - - mop = tx_map_ops; - while ((m = txq) != NULL) { - caddr_t data; - - txq = m->m_nextpkt; - m->m_nextpkt = NULL; - - pending_idx = *((uint16_t *)m->m_data); - netif = pending_tx_info[pending_idx].netif; - memcpy(&txreq, &pending_tx_info[pending_idx].req, sizeof(txreq)); - - /* Check the remap error code. */ - if (unlikely(mop->status)) { - WPRINTF("#### netback grant fails\n"); - make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); - netif_put(netif); - m_freem(m); - mop++; - pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; - continue; - } - -#if 0 - /* Can't do this in FreeBSD since vtophys() returns the pfn */ - /* of the remote domain who loaned us the machine page - DPT */ - xen_phys_machine[(vtophys(MMAP_VADDR(pending_idx)) >> PAGE_SHIFT)] = - mop->dev_bus_addr >> PAGE_SHIFT; -#endif - grant_tx_handle[pending_idx] = mop->handle; - - /* Setup data in mbuf (lengths are already set) */ - data = (caddr_t)(MMAP_VADDR(pending_idx)|txreq.offset); - bcopy(data, m->m_data, m->m_len); - if (m->m_next) { - struct mbuf *n = m->m_next; - MEXTADD(n, MMAP_VADDR(pending_idx), PAGE_SIZE, netif_page_release, - (void *)(unsigned int)pending_idx, M_RDONLY, EXT_NET_DRV); - n->m_data = &data[PKT_PROT_LEN]; - } else { - /* Schedule a response immediately. */ - netif_idx_release(pending_idx); - } - - if ((txreq.flags & NETTXF_data_validated)) { - /* Tell the stack the checksums are okay */ - m->m_pkthdr.csum_flags |= - (CSUM_IP_CHECKED | CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR); - m->m_pkthdr.csum_data = 0xffff; - } - - /* If necessary, inform stack to compute the checksums if it forwards the packet */ - if ((txreq.flags & NETTXF_csum_blank)) { - struct ether_header *eh = mtod(m, struct ether_header *); - if (ntohs(eh->ether_type) == ETHERTYPE_IP) { - struct ip *ip = (struct ip *)&m->m_data[14]; - if (ip->ip_p == IPPROTO_TCP) - m->m_pkthdr.csum_flags |= CSUM_TCP; - else if (ip->ip_p == IPPROTO_UDP) - m->m_pkthdr.csum_flags |= CSUM_UDP; - } - } - - netif->ifp->if_ibytes += m->m_pkthdr.len; - netif->ifp->if_ipackets++; - - DDPRINTF("RECV %d bytes from %s (cflags=%x)\n", - m->m_pkthdr.len, IFNAME(netif), m->m_pkthdr.csum_flags); - DPRINTF_MBUF_LEN(m, 128); - - (*netif->ifp->if_input)(netif->ifp, m); - - mop++; - } -} - -/* Handle interrupt from a frontend */ -static void -netback_intr(void *arg) -{ - netif_t *netif = arg; - DDPRINTF("%s\n", IFNAME(netif)); - add_to_tx_schedule_list_tail(netif); - maybe_schedule_tx_action(); -} - -/* Removes netif from front of list and does not call netif_put() (caller must) */ -static netif_t * -remove_from_rx_schedule_list(void) -{ - netif_t *netif; - - mtx_lock(&rx_sched_list_lock); - - if ((netif = STAILQ_FIRST(&rx_sched_list))) { - STAILQ_REMOVE(&rx_sched_list, netif, netback_info, next_rx); - STAILQ_NEXT(netif, next_rx) = NULL; - netif->on_rx_sched_list = 0; - } - - mtx_unlock(&rx_sched_list_lock); - - return netif; -} - -/* Adds netif to end of list and calls netif_get() */ -static void -add_to_rx_schedule_list_tail(netif_t *netif) -{ - if (netif->on_rx_sched_list) - return; - - mtx_lock(&rx_sched_list_lock); - if (!netif->on_rx_sched_list && (netif->ifp->if_drv_flags & IFF_DRV_RUNNING)) { - netif_get(netif); - STAILQ_INSERT_TAIL(&rx_sched_list, netif, next_rx); - netif->on_rx_sched_list = 1; - } - mtx_unlock(&rx_sched_list_lock); -} - -static int -make_rx_response(netif_t *netif, uint16_t id, int8_t st, - uint16_t offset, uint16_t size, uint16_t flags) -{ - RING_IDX i = netif->rx.rsp_prod_pvt; - netif_rx_response_t *resp; - int notify; - - resp = RING_GET_RESPONSE(&netif->rx, i); - resp->offset = offset; - resp->flags = flags; - resp->id = id; - resp->status = (int16_t)size; - if (st < 0) - resp->status = (int16_t)st; - - DDPRINTF("rx resp(%d): off=%x fl=%x id=%x stat=%d\n", - i, resp->offset, resp->flags, resp->id, resp->status); - - netif->rx.rsp_prod_pvt = ++i; - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, notify); - - return notify; -} - -static int -netif_rx(netif_t *netif) -{ - struct ifnet *ifp = netif->ifp; - struct mbuf *m; - multicall_entry_t *mcl; - mmu_update_t *mmu; - gnttab_transfer_t *gop; - unsigned long vdata, old_mfn, new_mfn; - struct mbuf *rxq = NULL, *rxq_last = NULL; - int ret, notify = 0, pkts_dequeued = 0; - - DDPRINTF("%s\n", IFNAME(netif)); - - mcl = rx_mcl; - mmu = rx_mmu; - gop = grant_rx_op; - - while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { - - /* Quit if the target domain has no receive buffers */ - if (netif->rx.req_cons == netif->rx.sring->req_prod) - break; - - IFQ_DRV_DEQUEUE(&ifp->if_snd, m); - if (m == NULL) - break; - - pkts_dequeued++; - - /* Check if we need to copy the data */ - if (((m->m_flags & (M_RDONLY|M_EXT)) != M_EXT) || - (*m->m_ext.ref_cnt > 1) || m->m_next != NULL) { - struct mbuf *n; - - DDPRINTF("copying mbuf (fl=%x ext=%x rc=%d n=%x)\n", - m->m_flags, - (m->m_flags & M_EXT) ? m->m_ext.ext_type : 0, - (m->m_flags & M_EXT) ? *m->m_ext.ref_cnt : 0, - (unsigned int)m->m_next); - - /* Make copy */ - MGETHDR(n, M_DONTWAIT, MT_DATA); - if (!n) - goto drop; - - MCLGET(n, M_DONTWAIT); - if (!(n->m_flags & M_EXT)) { - m_freem(n); - goto drop; - } - - /* Leave space at front and keep current alignment */ - n->m_data += 16 + ((unsigned int)m->m_data & 0x3); - - if (m->m_pkthdr.len > M_TRAILINGSPACE(n)) { - WPRINTF("pkt to big %d\n", m->m_pkthdr.len); - m_freem(n); - goto drop; - } - m_copydata(m, 0, m->m_pkthdr.len, n->m_data); - n->m_pkthdr.len = n->m_len = m->m_pkthdr.len; - n->m_pkthdr.csum_flags = (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA); - m_freem(m); - m = n; - } - - vdata = (unsigned long)m->m_data; - old_mfn = vtomach(vdata) >> PAGE_SHIFT; - - if ((new_mfn = alloc_mfn()) == 0) - goto drop; - -#ifdef XEN_NETBACK_FIXUP_CSUM - /* Check if we need to compute a checksum. This happens */ - /* when bridging from one domain to another. */ - if ((m->m_pkthdr.csum_flags & CSUM_DELAY_DATA)) - fixup_checksum(m); -#endif - - xen_phys_machine[(vtophys(vdata) >> PAGE_SHIFT)] = new_mfn; - - mcl->op = __HYPERVISOR_update_va_mapping; - mcl->args[0] = vdata; - mcl->args[1] = (new_mfn << PAGE_SHIFT) | PG_V | PG_RW | PG_M | PG_A; - mcl->args[2] = 0; - mcl->args[3] = 0; - mcl++; - - gop->mfn = old_mfn; - gop->domid = netif->domid; - gop->ref = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons)->gref; - netif->rx.req_cons++; - gop++; - - mmu->ptr = (new_mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE; - mmu->val = vtophys(vdata) >> PAGE_SHIFT; - mmu++; - - if (rxq_last) - rxq_last->m_nextpkt = m; - else - rxq = m; - rxq_last = m; - - DDPRINTF("XMIT %d bytes to %s\n", m->m_pkthdr.len, IFNAME(netif)); - DPRINTF_MBUF_LEN(m, 128); - - /* Filled the batch queue? */ - if ((gop - grant_rx_op) == ARRAY_SIZE(grant_rx_op)) - break; - - continue; - drop: - DDPRINTF("dropping pkt\n"); - ifp->if_oerrors++; - m_freem(m); - } - - if (mcl == rx_mcl) - return pkts_dequeued; - - mcl->op = __HYPERVISOR_mmu_update; - mcl->args[0] = (unsigned long)rx_mmu; - mcl->args[1] = mmu - rx_mmu; - mcl->args[2] = 0; - mcl->args[3] = DOMID_SELF; - mcl++; - - mcl[-2].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL; - ret = HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl); - BUG_ON(ret != 0); - - ret = HYPERVISOR_grant_table_op(GNTTABOP_transfer, grant_rx_op, gop - grant_rx_op); - BUG_ON(ret != 0); - - mcl = rx_mcl; - gop = grant_rx_op; - - while ((m = rxq) != NULL) { - int8_t status; - uint16_t id, flags = 0; - - rxq = m->m_nextpkt; - m->m_nextpkt = NULL; - - /* Rederive the machine addresses. */ - new_mfn = mcl->args[1] >> PAGE_SHIFT; - old_mfn = gop->mfn; - - ifp->if_obytes += m->m_pkthdr.len; - ifp->if_opackets++; - - /* The update_va_mapping() must not fail. */ - BUG_ON(mcl->result != 0); - - /* Setup flags */ - if ((m->m_pkthdr.csum_flags & CSUM_DELAY_DATA)) - flags |= NETRXF_csum_blank | NETRXF_data_validated; - else if ((m->m_pkthdr.csum_flags & CSUM_DATA_VALID)) - flags |= NETRXF_data_validated; - - /* Check the reassignment error code. */ - status = NETIF_RSP_OKAY; - if (gop->status != 0) { - DPRINTF("Bad status %d from grant transfer to DOM%u\n", - gop->status, netif->domid); - /* - * Page no longer belongs to us unless GNTST_bad_page, - * but that should be a fatal error anyway. - */ - BUG_ON(gop->status == GNTST_bad_page); - status = NETIF_RSP_ERROR; - } - id = RING_GET_REQUEST(&netif->rx, netif->rx.rsp_prod_pvt)->id; - notify |= make_rx_response(netif, id, status, - (unsigned long)m->m_data & PAGE_MASK, - m->m_pkthdr.len, flags); - - m_freem(m); - mcl++; - gop++; - } - - if (notify) - notify_remote_via_irq(netif->irq); - - return pkts_dequeued; -} - -static void -rx_task_timer(void *arg) -{ - DDPRINTF("\n"); - taskqueue_enqueue(taskqueue_swi, &net_rx_task); -} - -static void -net_rx_action(void *context, int pending) -{ - netif_t *netif, *last_zero_work = NULL; - - DDPRINTF("\n"); - - while ((netif = remove_from_rx_schedule_list())) { - struct ifnet *ifp = netif->ifp; - - if (netif == last_zero_work) { - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - add_to_rx_schedule_list_tail(netif); - netif_put(netif); - if (!STAILQ_EMPTY(&rx_sched_list)) - callout_reset(&rx_task_callout, 1, rx_task_timer, NULL); - break; - } - - if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { - if (netif_rx(netif)) - last_zero_work = NULL; - else if (!last_zero_work) - last_zero_work = netif; - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - add_to_rx_schedule_list_tail(netif); - } - - netif_put(netif); - } -} - -static void -netback_start(struct ifnet *ifp) -{ - netif_t *netif = (netif_t *)ifp->if_softc; - - DDPRINTF("%s\n", IFNAME(netif)); - - add_to_rx_schedule_list_tail(netif); - taskqueue_enqueue(taskqueue_swi, &net_rx_task); -} - -/* Map a grant ref to a ring */ -static int -map_ring(grant_ref_t ref, domid_t dom, struct ring_ref *ring) -{ - struct gnttab_map_grant_ref op; - - ring->va = kmem_alloc_nofault(kernel_map, PAGE_SIZE); - if (ring->va == 0) - return ENOMEM; - - op.host_addr = ring->va; - op.flags = GNTMAP_host_map; - op.ref = ref; - op.dom = dom; - HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); - if (op.status) { - WPRINTF("grant table op err=%d\n", op.status); - kmem_free(kernel_map, ring->va, PAGE_SIZE); - ring->va = 0; - return EACCES; - } - - ring->handle = op.handle; - ring->bus_addr = op.dev_bus_addr; - - return 0; -} - -/* Unmap grant ref for a ring */ -static void -unmap_ring(struct ring_ref *ring) -{ - struct gnttab_unmap_grant_ref op; - - op.host_addr = ring->va; - op.dev_bus_addr = ring->bus_addr; - op.handle = ring->handle; - HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1); - if (op.status) - WPRINTF("grant table op err=%d\n", op.status); - - kmem_free(kernel_map, ring->va, PAGE_SIZE); - ring->va = 0; -} - -static int -connect_rings(netif_t *netif) -{ - struct xenbus_device *xdev = netif->xdev; - netif_tx_sring_t *txs; - netif_rx_sring_t *rxs; - unsigned long tx_ring_ref, rx_ring_ref; - evtchn_port_t evtchn; - evtchn_op_t op = { .cmd = EVTCHNOP_bind_interdomain }; - int err; - - // Grab FE data and map his memory - err = xenbus_gather(NULL, xdev->otherend, - "tx-ring-ref", "%lu", &tx_ring_ref, - "rx-ring-ref", "%lu", &rx_ring_ref, - "event-channel", "%u", &evtchn, NULL); - if (err) { - xenbus_dev_fatal(xdev, err, - "reading %s/ring-ref and event-channel", - xdev->otherend); - return err; - } - - err = map_ring(tx_ring_ref, netif->domid, &netif->tx_ring_ref); - if (err) { - xenbus_dev_fatal(xdev, err, "mapping tx ring"); - return err; - } - txs = (netif_tx_sring_t *)netif->tx_ring_ref.va; - BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE); - - err = map_ring(rx_ring_ref, netif->domid, &netif->rx_ring_ref); - if (err) { - unmap_ring(&netif->tx_ring_ref); - xenbus_dev_fatal(xdev, err, "mapping rx ring"); - return err; - } - rxs = (netif_rx_sring_t *)netif->rx_ring_ref.va; - BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE); - - op.u.bind_interdomain.remote_dom = netif->domid; - op.u.bind_interdomain.remote_port = evtchn; - err = HYPERVISOR_event_channel_op(&op); - if (err) { - unmap_ring(&netif->tx_ring_ref); - unmap_ring(&netif->rx_ring_ref); - xenbus_dev_fatal(xdev, err, "binding event channel"); - return err; - } - netif->evtchn = op.u.bind_interdomain.local_port; - - /* bind evtchn to irq handler */ - netif->irq = - bind_evtchn_to_irqhandler(netif->evtchn, "netback", - netback_intr, netif, INTR_TYPE_NET|INTR_MPSAFE, &netif->irq_cookie); - - netif->rings_connected = 1; - - DPRINTF("%s connected! evtchn=%d irq=%d\n", - IFNAME(netif), netif->evtchn, netif->irq); - - return 0; -} - -static void -disconnect_rings(netif_t *netif) -{ - DPRINTF("\n"); - - if (netif->rings_connected) { - unbind_from_irqhandler(netif->irq, netif->irq_cookie); - netif->irq = 0; - unmap_ring(&netif->tx_ring_ref); - unmap_ring(&netif->rx_ring_ref); - netif->rings_connected = 0; - } -} - -static void -connect(netif_t *netif) -{ - if (!netif->xdev || - !netif->attached || - netif->frontend_state != XenbusStateConnected) { - return; - } - - if (!connect_rings(netif)) { - xenbus_switch_state(netif->xdev, NULL, XenbusStateConnected); - - /* Turn on interface */ - netif->ifp->if_drv_flags |= IFF_DRV_RUNNING; - netif->ifp->if_flags |= IFF_UP; - } -} - -static int -netback_remove(struct xenbus_device *xdev) -{ - netif_t *netif = xdev->data; - device_t ndev; - - DPRINTF("remove %s\n", xdev->nodename); - - if ((ndev = netif->ndev)) { - netif->ndev = NULL; - mtx_lock(&Giant); - device_detach(ndev); - mtx_unlock(&Giant); - } - - xdev->data = NULL; - netif->xdev = NULL; - netif_put(netif); - - return 0; -} - -/** - * Entry point to this code when a new device is created. Allocate the basic - * structures and the ring buffers for communication with the frontend. - * Switch to Connected state. - */ -static int -netback_probe(struct xenbus_device *xdev, const struct xenbus_device_id *id) -{ - int err; - long handle; - char *bridge; - - DPRINTF("node=%s\n", xdev->nodename); - - /* Grab the handle */ - err = xenbus_scanf(NULL, xdev->nodename, "handle", "%li", &handle); - if (err != 1) { - xenbus_dev_fatal(xdev, err, "reading handle"); - return err; - } - - /* Check for bridge */ - bridge = xenbus_read(NULL, xdev->nodename, "bridge", NULL); - if (IS_ERR(bridge)) - bridge = NULL; - - err = xenbus_switch_state(xdev, NULL, XenbusStateInitWait); - if (err) { - xenbus_dev_fatal(xdev, err, "writing switch state"); - return err; - } - - err = netif_create(handle, xdev, bridge); - if (err) { - xenbus_dev_fatal(xdev, err, "creating netif"); - return err; - } - - err = vif_add_dev(xdev); - if (err) { - netif_put((netif_t *)xdev->data); - xenbus_dev_fatal(xdev, err, "adding vif device"); - return err; - } - - return 0; -} - -/** - * We are reconnecting to the backend, due to a suspend/resume, or a backend - * driver restart. We tear down our netif structure and recreate it, but - * leave the device-layer structures intact so that this is transparent to the - * rest of the kernel. - */ -static int netback_resume(struct xenbus_device *xdev) -{ - DPRINTF("node=%s\n", xdev->nodename); - return 0; -} - - -/** - * Callback received when the frontend's state changes. - */ -static void frontend_changed(struct xenbus_device *xdev, - XenbusState frontend_state) -{ - netif_t *netif = xdev->data; - - DPRINTF("state=%d\n", frontend_state); - - netif->frontend_state = frontend_state; - - switch (frontend_state) { - case XenbusStateInitialising: - case XenbusStateInitialised: - break; - case XenbusStateConnected: - connect(netif); - break; - case XenbusStateClosing: - xenbus_switch_state(xdev, NULL, XenbusStateClosing); - break; - case XenbusStateClosed: - xenbus_remove_device(xdev); - break; - case XenbusStateUnknown: - case XenbusStateInitWait: - xenbus_dev_fatal(xdev, EINVAL, "saw state %d at frontend", - frontend_state); - break; - } -} - -/* ** Driver registration ** */ - -static struct xenbus_device_id netback_ids[] = { - { "vif" }, - { "" } -}; - -static struct xenbus_driver netback = { - .name = "netback", - .ids = netback_ids, - .probe = netback_probe, - .remove = netback_remove, - .resume= netback_resume, - .otherend_changed = frontend_changed, -}; - -static void -netback_init(void *unused) -{ - callout_init(&rx_task_callout, CALLOUT_MPSAFE); - - mmap_vstart = alloc_empty_page_range(MAX_PENDING_REQS); - BUG_ON(!mmap_vstart); - - pending_cons = 0; - for (pending_prod = 0; pending_prod < MAX_PENDING_REQS; pending_prod++) - pending_ring[pending_prod] = pending_prod; - - TASK_INIT(&net_tx_task, 0, net_tx_action, NULL); - TASK_INIT(&net_rx_task, 0, net_rx_action, NULL); - mtx_init(&tx_sched_list_lock, "nb_tx_sched_lock", "netback tx sched lock", MTX_DEF); - mtx_init(&rx_sched_list_lock, "nb_rx_sched_lock", "netback rx sched lock", MTX_DEF); - - DPRINTF("registering %s\n", netback.name); - - xenbus_register_backend(&netback); -} - -SYSINIT(xnbedev, SI_SUB_PSEUDO, SI_ORDER_ANY, netback_init, NULL) - -static int -vif_add_dev(struct xenbus_device *xdev) -{ - netif_t *netif = xdev->data; - device_t nexus, ndev; - devclass_t dc; - int err = 0; - - mtx_lock(&Giant); - - /* We will add a vif device as a child of nexus0 (for now) */ - if (!(dc = devclass_find("nexus")) || - !(nexus = devclass_get_device(dc, 0))) { - WPRINTF("could not find nexus0!\n"); - err = ENOENT; - goto done; - } - - - /* Create a newbus device representing the vif */ - ndev = BUS_ADD_CHILD(nexus, 0, "vif", netif->ifp->if_dunit); - if (!ndev) { - WPRINTF("could not create newbus device %s!\n", IFNAME(netif)); - err = EFAULT; - goto done; - } - - netif_get(netif); - device_set_ivars(ndev, netif); - netif->ndev = ndev; - - device_probe_and_attach(ndev); - - done: - - mtx_unlock(&Giant); - - return err; -} - -enum { - VIF_SYSCTL_DOMID, - VIF_SYSCTL_HANDLE, - VIF_SYSCTL_TXRING, - VIF_SYSCTL_RXRING, -}; - -static char * -vif_sysctl_ring_info(netif_t *netif, int cmd) -{ - char *buf = malloc(256, M_DEVBUF, M_WAITOK); - if (buf) { - if (!netif->rings_connected) - sprintf(buf, "rings not connected\n"); - else if (cmd == VIF_SYSCTL_TXRING) { - netif_tx_back_ring_t *tx = &netif->tx; - sprintf(buf, "nr_ents=%x req_cons=%x" - " req_prod=%x req_event=%x" - " rsp_prod=%x rsp_event=%x", - tx->nr_ents, tx->req_cons, - tx->sring->req_prod, tx->sring->req_event, - tx->sring->rsp_prod, tx->sring->rsp_event); - } else { - netif_rx_back_ring_t *rx = &netif->rx; - sprintf(buf, "nr_ents=%x req_cons=%x" - " req_prod=%x req_event=%x" - " rsp_prod=%x rsp_event=%x", - rx->nr_ents, rx->req_cons, - rx->sring->req_prod, rx->sring->req_event, - rx->sring->rsp_prod, rx->sring->rsp_event); - } - } - return buf; -} - -static int -vif_sysctl_handler(SYSCTL_HANDLER_ARGS) -{ - device_t dev = (device_t)arg1; - netif_t *netif = (netif_t *)device_get_ivars(dev); - const char *value; - char *buf = NULL; - int err; - - switch (arg2) { - case VIF_SYSCTL_DOMID: - return sysctl_handle_int(oidp, NULL, netif->domid, req); - case VIF_SYSCTL_HANDLE: - return sysctl_handle_int(oidp, NULL, netif->handle, req); - case VIF_SYSCTL_TXRING: - case VIF_SYSCTL_RXRING: - value = buf = vif_sysctl_ring_info(netif, arg2); - break; - default: - return (EINVAL); - } - - err = SYSCTL_OUT(req, value, strlen(value)); - if (buf != NULL) - free(buf, M_DEVBUF); - - return err; -} - -/* Newbus vif device driver probe */ -static int -vif_probe(device_t dev) -{ - DDPRINTF("vif%d\n", device_get_unit(dev)); - return 0; -} - -/* Newbus vif device driver attach */ -static int -vif_attach(device_t dev) -{ - netif_t *netif = (netif_t *)device_get_ivars(dev); - uint8_t mac[ETHER_ADDR_LEN]; - - DDPRINTF("%s\n", IFNAME(netif)); - - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "domid", CTLTYPE_INT|CTLFLAG_RD, - dev, VIF_SYSCTL_DOMID, vif_sysctl_handler, "I", - "domid of frontend"); - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "handle", CTLTYPE_INT|CTLFLAG_RD, - dev, VIF_SYSCTL_HANDLE, vif_sysctl_handler, "I", - "handle of frontend"); -#ifdef XEN_NETBACK_DEBUG - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "txring", CTLFLAG_RD, - dev, VIF_SYSCTL_TXRING, vif_sysctl_handler, "A", - "tx ring info"); - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "rxring", CTLFLAG_RD, - dev, VIF_SYSCTL_RXRING, vif_sysctl_handler, "A", - "rx ring info"); -#endif - - memset(mac, 0xff, sizeof(mac)); - mac[0] &= ~0x01; - - ether_ifattach(netif->ifp, mac); - netif->attached = 1; - - connect(netif); - - if (netif->bridge) { - DPRINTF("Adding %s to bridge %s\n", IFNAME(netif), netif->bridge); - int err = add_to_bridge(netif->ifp, netif->bridge); - if (err) { - WPRINTF("Error adding %s to %s; err=%d\n", - IFNAME(netif), netif->bridge, err); - } - } - - return bus_generic_attach(dev); -} - -/* Newbus vif device driver detach */ -static int -vif_detach(device_t dev) -{ - netif_t *netif = (netif_t *)device_get_ivars(dev); - struct ifnet *ifp = netif->ifp; - - DDPRINTF("%s\n", IFNAME(netif)); - - /* Tell the stack that the interface is no longer active */ - ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - - ether_ifdetach(ifp); - - bus_generic_detach(dev); - - netif->attached = 0; - - netif_put(netif); - - return 0; -} - -static device_method_t vif_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, vif_probe), - DEVMETHOD(device_attach, vif_attach), - DEVMETHOD(device_detach, vif_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - {0, 0} -}; - -static devclass_t vif_devclass; - -static driver_t vif_driver = { - "vif", - vif_methods, - 0, -}; - -DRIVER_MODULE(vif, nexus, vif_driver, vif_devclass, 0, 0); - - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: t - * End: - */ diff --git a/sys/dev/xen/netfront/mbufq.h b/sys/dev/xen/netfront/mbufq.h deleted file mode 100644 index 0d6c604..0000000 --- a/sys/dev/xen/netfront/mbufq.h +++ /dev/null @@ -1,123 +0,0 @@ -/************************************************************************** - -Copyright (c) 2007, Chelsio Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Neither the name of the Chelsio Corporation nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -$FreeBSD$ - -***************************************************************************/ - -#ifndef CXGB_MBUFQ_H_ -#define CXGB_MBUFQ_H_ - -struct mbuf_head { - struct mbuf *head; - struct mbuf *tail; - uint32_t qlen; - uint32_t qsize; - struct mtx lock; -}; - -static __inline void -mbufq_init(struct mbuf_head *l) -{ - l->head = l->tail = NULL; - l->qlen = l->qsize = 0; -} - -static __inline int -mbufq_empty(struct mbuf_head *l) -{ - return (l->head == NULL); -} - -static __inline int -mbufq_len(struct mbuf_head *l) -{ - return (l->qlen); -} - -static __inline int -mbufq_size(struct mbuf_head *l) -{ - return (l->qsize); -} - -static __inline int -mbufq_head_size(struct mbuf_head *l) -{ - return (l->head ? l->head->m_pkthdr.len : 0); -} - -static __inline void -mbufq_tail(struct mbuf_head *l, struct mbuf *m) -{ - l->qlen++; - if (l->head == NULL) - l->head = m; - else - l->tail->m_nextpkt = m; - l->tail = m; - l->qsize += m->m_pkthdr.len; -} - -static __inline struct mbuf * -mbufq_dequeue(struct mbuf_head *l) -{ - struct mbuf *m; - - m = l->head; - if (m) { - if (m == l->tail) - l->head = l->tail = NULL; - else - l->head = m->m_nextpkt; - m->m_nextpkt = NULL; - l->qlen--; - l->qsize -= m->m_pkthdr.len; - } - - return (m); -} - -static __inline struct mbuf * -mbufq_peek(struct mbuf_head *l) -{ - return (l->head); -} - -static __inline void -mbufq_append(struct mbuf_head *a, struct mbuf_head *b) -{ - if (a->tail) - a->tail->m_nextpkt = b->head; - if (b->tail) - a->tail = b->tail; - a->qlen += b->qlen; - a->qsize += b->qsize; - - -} -#endif /* CXGB_MBUFQ_H_ */ diff --git a/sys/dev/xen/netfront/netfront.c b/sys/dev/xen/netfront/netfront.c deleted file mode 100644 index 3a29ffb..0000000 --- a/sys/dev/xen/netfront/netfront.c +++ /dev/null @@ -1,1850 +0,0 @@ -/* - * - * Copyright (c) 2004-2006 Kip Macy - * All rights reserved. - * - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/socket.h> -#include <sys/queue.h> -#include <sys/lock.h> -#include <sys/sx.h> - -#include <net/if.h> -#include <net/if_arp.h> -#include <net/ethernet.h> -#include <net/if_dl.h> -#include <net/if_media.h> - -#include <net/bpf.h> - -#include <net/if_types.h> -#include <net/if.h> - -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/if_ether.h> - -#include <vm/vm.h> -#include <vm/pmap.h> - -#include <machine/clock.h> /* for DELAY */ -#include <machine/bus.h> -#include <machine/resource.h> -#include <machine/frame.h> -#include <machine/vmparam.h> - -#include <sys/bus.h> -#include <sys/rman.h> - -#include <machine/intr_machdep.h> - -#include <machine/xen/xen-os.h> -#include <machine/xen/hypervisor.h> -#include <machine/xen/xen_intr.h> -#include <machine/xen/evtchn.h> -#include <machine/xen/xenbus.h> -#include <xen/gnttab.h> -#include <xen/interface/memory.h> -#include <dev/xen/netfront/mbufq.h> -#include <machine/xen/features.h> -#include <xen/interface/io/netif.h> - - -#define GRANT_INVALID_REF 0 - -#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE) -#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE) - -#ifdef CONFIG_XEN -static int MODPARM_rx_copy = 0; -module_param_named(rx_copy, MODPARM_rx_copy, bool, 0); -MODULE_PARM_DESC(rx_copy, "Copy packets from network card (rather than flip)"); -static int MODPARM_rx_flip = 0; -module_param_named(rx_flip, MODPARM_rx_flip, bool, 0); -MODULE_PARM_DESC(rx_flip, "Flip packets from network card (rather than copy)"); -#else -static const int MODPARM_rx_copy = 1; -static const int MODPARM_rx_flip = 0; -#endif - -#define RX_COPY_THRESHOLD 256 - -#define net_ratelimit() 0 - -struct netfront_info; -struct netfront_rx_info; - -static void xn_txeof(struct netfront_info *); -static void xn_rxeof(struct netfront_info *); -static void network_alloc_rx_buffers(struct netfront_info *); - -static void xn_tick_locked(struct netfront_info *); -static void xn_tick(void *); - -static void xn_intr(void *); -static void xn_start_locked(struct ifnet *); -static void xn_start(struct ifnet *); -static int xn_ioctl(struct ifnet *, u_long, caddr_t); -static void xn_ifinit_locked(struct netfront_info *); -static void xn_ifinit(void *); -static void xn_stop(struct netfront_info *); -#ifdef notyet -static void xn_watchdog(struct ifnet *); -#endif - -static void show_device(struct netfront_info *sc); -#ifdef notyet -static void netfront_closing(struct xenbus_device *dev); -#endif -static void netif_free(struct netfront_info *info); -static int netfront_remove(struct xenbus_device *dev); - -static int talk_to_backend(struct xenbus_device *dev, struct netfront_info *info); -static int create_netdev(struct xenbus_device *dev, struct ifnet **ifp); -static void netif_disconnect_backend(struct netfront_info *info); -static int setup_device(struct xenbus_device *dev, struct netfront_info *info); -static void end_access(int ref, void *page); - -/* Xenolinux helper functions */ -static int network_connect(struct ifnet *ifp); - -static void xn_free_rx_ring(struct netfront_info *); - -static void xn_free_tx_ring(struct netfront_info *); - -static int xennet_get_responses(struct netfront_info *np, - struct netfront_rx_info *rinfo, RING_IDX rp, struct mbuf **list, - int *pages_flipped_p); - -#define virt_to_mfn(x) (vtomach(x) >> PAGE_SHIFT) - -#define INVALID_P2M_ENTRY (~0UL) - -/* - * Mbuf pointers. We need these to keep track of the virtual addresses - * of our mbuf chains since we can only convert from virtual to physical, - * not the other way around. The size must track the free index arrays. - */ -struct xn_chain_data { - struct mbuf *xn_tx_chain[NET_TX_RING_SIZE+1]; - struct mbuf *xn_rx_chain[NET_RX_RING_SIZE+1]; -}; - - -struct net_device_stats -{ - u_long rx_packets; /* total packets received */ - u_long tx_packets; /* total packets transmitted */ - u_long rx_bytes; /* total bytes received */ - u_long tx_bytes; /* total bytes transmitted */ - u_long rx_errors; /* bad packets received */ - u_long tx_errors; /* packet transmit problems */ - u_long rx_dropped; /* no space in linux buffers */ - u_long tx_dropped; /* no space available in linux */ - u_long multicast; /* multicast packets received */ - u_long collisions; - - /* detailed rx_errors: */ - u_long rx_length_errors; - u_long rx_over_errors; /* receiver ring buff overflow */ - u_long rx_crc_errors; /* recved pkt with crc error */ - u_long rx_frame_errors; /* recv'd frame alignment error */ - u_long rx_fifo_errors; /* recv'r fifo overrun */ - u_long rx_missed_errors; /* receiver missed packet */ - - /* detailed tx_errors */ - u_long tx_aborted_errors; - u_long tx_carrier_errors; - u_long tx_fifo_errors; - u_long tx_heartbeat_errors; - u_long tx_window_errors; - - /* for cslip etc */ - u_long rx_compressed; - u_long tx_compressed; -}; - -struct netfront_info { - - struct ifnet *xn_ifp; - - struct net_device_stats stats; - u_int tx_full; - - netif_tx_front_ring_t tx; - netif_rx_front_ring_t rx; - - struct mtx tx_lock; - struct mtx rx_lock; - struct sx sc_lock; - - u_int handle; - u_int irq; - u_int copying_receiver; - u_int carrier; - - /* Receive-ring batched refills. */ -#define RX_MIN_TARGET 32 -#define RX_MAX_TARGET NET_RX_RING_SIZE - int rx_min_target, rx_max_target, rx_target; - - /* - * {tx,rx}_skbs store outstanding skbuffs. The first entry in each - * array is an index into a chain of free entries. - */ - - grant_ref_t gref_tx_head; - grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1]; - grant_ref_t gref_rx_head; - grant_ref_t grant_rx_ref[NET_TX_RING_SIZE + 1]; - -#define TX_MAX_TARGET min(NET_RX_RING_SIZE, 256) - struct xenbus_device *xbdev; - int tx_ring_ref; - int rx_ring_ref; - uint8_t mac[ETHER_ADDR_LEN]; - struct xn_chain_data xn_cdata; /* mbufs */ - struct mbuf_head xn_rx_batch; /* head of the batch queue */ - - int xn_if_flags; - struct callout xn_stat_ch; - - u_long rx_pfn_array[NET_RX_RING_SIZE]; - multicall_entry_t rx_mcl[NET_RX_RING_SIZE+1]; - mmu_update_t rx_mmu[NET_RX_RING_SIZE]; -}; - -#define rx_mbufs xn_cdata.xn_rx_chain -#define tx_mbufs xn_cdata.xn_tx_chain - -#define XN_LOCK_INIT(_sc, _name) \ - mtx_init(&(_sc)->tx_lock, #_name"_tx", "network transmit lock", MTX_DEF); \ - mtx_init(&(_sc)->rx_lock, #_name"_rx", "network receive lock", MTX_DEF); \ - sx_init(&(_sc)->sc_lock, #_name"_rx") - -#define XN_RX_LOCK(_sc) mtx_lock(&(_sc)->rx_lock) -#define XN_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->rx_lock) - -#define XN_TX_LOCK(_sc) mtx_lock(&(_sc)->tx_lock) -#define XN_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->tx_lock) - -#define XN_LOCK(_sc) sx_xlock(&(_sc)->sc_lock); -#define XN_UNLOCK(_sc) sx_xunlock(&(_sc)->sc_lock); - -#define XN_LOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_lock, SX_LOCKED); -#define XN_RX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rx_lock, MA_OWNED); -#define XN_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->tx_lock, MA_OWNED); -#define XN_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rx_lock); \ - mtx_destroy(&(_sc)->tx_lock); \ - sx_destroy(&(_sc)->sc_lock); - -struct netfront_rx_info { - struct netif_rx_response rx; - struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; -}; - -#define netfront_carrier_on(netif) ((netif)->carrier = 1) -#define netfront_carrier_off(netif) ((netif)->carrier = 0) -#define netfront_carrier_ok(netif) ((netif)->carrier) - -/* Access macros for acquiring freeing slots in xn_free_{tx,rx}_idxs[]. */ - - - -/* - * Access macros for acquiring freeing slots in tx_skbs[]. - */ - -static inline void -add_id_to_freelist(struct mbuf **list, unsigned short id) -{ - list[id] = list[0]; - list[0] = (void *)(u_long)id; -} - -static inline unsigned short -get_id_from_freelist(struct mbuf **list) -{ - u_int id = (u_int)(u_long)list[0]; - list[0] = list[id]; - return (id); -} - -static inline int -xennet_rxidx(RING_IDX idx) -{ - return idx & (NET_RX_RING_SIZE - 1); -} - -static inline struct mbuf * -xennet_get_rx_mbuf(struct netfront_info *np, - RING_IDX ri) -{ - int i = xennet_rxidx(ri); - struct mbuf *m; - - m = np->rx_mbufs[i]; - np->rx_mbufs[i] = NULL; - return (m); -} - -static inline grant_ref_t -xennet_get_rx_ref(struct netfront_info *np, RING_IDX ri) -{ - int i = xennet_rxidx(ri); - grant_ref_t ref = np->grant_rx_ref[i]; - np->grant_rx_ref[i] = GRANT_INVALID_REF; - return ref; -} - -#ifdef DEBUG - -#endif -#define IPRINTK(fmt, args...) \ - printf("[XEN] " fmt, ##args) -#define WPRINTK(fmt, args...) \ - printf("[XEN] " fmt, ##args) -#define DPRINTK(fmt, args...) \ - printf("[XEN] " fmt, ##args) - - -static __inline struct mbuf* -makembuf (struct mbuf *buf) -{ - struct mbuf *m = NULL; - - MGETHDR (m, M_DONTWAIT, MT_DATA); - - if (! m) - return 0; - - M_MOVE_PKTHDR(m, buf); - - m_cljget(m, M_DONTWAIT, MJUMPAGESIZE); - m->m_pkthdr.len = buf->m_pkthdr.len; - m->m_len = buf->m_len; - m_copydata(buf, 0, buf->m_pkthdr.len, mtod(m,caddr_t) ); - - m->m_ext.ext_args = (caddr_t *)(uintptr_t)(vtophys(mtod(m,caddr_t)) >> PAGE_SHIFT); - - return m; -} - -/** - * Read the 'mac' node at the given device's node in the store, and parse that - * as colon-separated octets, placing result the given mac array. mac must be - * a preallocated array of length ETH_ALEN (as declared in linux/if_ether.h). - * Return 0 on success, or errno on error. - */ -static int -xen_net_read_mac(struct xenbus_device *dev, uint8_t mac[]) -{ - char *s; - int i; - char *e; - char *macstr = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL); - if (IS_ERR(macstr)) { - return PTR_ERR(macstr); - } - s = macstr; - for (i = 0; i < ETHER_ADDR_LEN; i++) { - mac[i] = strtoul(s, &e, 16); - if (s == e || (e[0] != ':' && e[0] != 0)) { - free(macstr, M_DEVBUF); - return ENOENT; - } - s = &e[1]; - } - free(macstr, M_DEVBUF); - return 0; -} - -/** - * Entry point to this code when a new device is created. Allocate the basic - * structures and the ring buffers for communication with the backend, and - * inform the backend of the appropriate details for those. Switch to - * Connected state. - */ -static int -netfront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) -{ - int err; - struct ifnet *ifp; - struct netfront_info *info; - - printf("netfront_probe() \n"); - - err = create_netdev(dev, &ifp); - if (err) { - xenbus_dev_fatal(dev, err, "creating netdev"); - return err; - } - - info = ifp->if_softc; - dev->dev_driver_data = info; - - return 0; -} - - -/** - * We are reconnecting to the backend, due to a suspend/resume, or a backend - * driver restart. We tear down our netif structure and recreate it, but - * leave the device-layer structures intact so that this is transparent to the - * rest of the kernel. - */ -static int -netfront_resume(struct xenbus_device *dev) -{ - struct netfront_info *info = dev->dev_driver_data; - - DPRINTK("%s\n", dev->nodename); - - netif_disconnect_backend(info); - return (0); -} - - -/* Common code used when first setting up, and when resuming. */ -static int -talk_to_backend(struct xenbus_device *dev, struct netfront_info *info) -{ - const char *message; - struct xenbus_transaction xbt; - int err; - - err = xen_net_read_mac(dev, info->mac); - if (err) { - xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename); - goto out; - } - - /* Create shared ring, alloc event channel. */ - err = setup_device(dev, info); - if (err) - goto out; - - again: - err = xenbus_transaction_start(&xbt); - if (err) { - xenbus_dev_fatal(dev, err, "starting transaction"); - goto destroy_ring; - } - err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref","%u", - info->tx_ring_ref); - if (err) { - message = "writing tx ring-ref"; - goto abort_transaction; - } - err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref","%u", - info->rx_ring_ref); - if (err) { - message = "writing rx ring-ref"; - goto abort_transaction; - } - err = xenbus_printf(xbt, dev->nodename, - "event-channel", "%u", irq_to_evtchn_port(info->irq)); - if (err) { - message = "writing event-channel"; - goto abort_transaction; - } - err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u", - info->copying_receiver); - if (err) { - message = "writing request-rx-copy"; - goto abort_transaction; - } - err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1); - if (err) { - message = "writing feature-rx-notify"; - goto abort_transaction; - } - err = xenbus_printf(xbt, dev->nodename, "feature-no-csum-offload", "%d", 1); - if (err) { - message = "writing feature-no-csum-offload"; - goto abort_transaction; - } - err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1); - if (err) { - message = "writing feature-sg"; - goto abort_transaction; - } -#ifdef HAVE_TSO - err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1); - if (err) { - message = "writing feature-gso-tcpv4"; - goto abort_transaction; - } -#endif - - err = xenbus_transaction_end(xbt, 0); - if (err) { - if (err == EAGAIN) - goto again; - xenbus_dev_fatal(dev, err, "completing transaction"); - goto destroy_ring; - } - - return 0; - - abort_transaction: - xenbus_transaction_end(xbt, 1); - xenbus_dev_fatal(dev, err, "%s", message); - destroy_ring: - netif_free(info); - out: - return err; -} - - -static int -setup_device(struct xenbus_device *dev, struct netfront_info *info) -{ - netif_tx_sring_t *txs; - netif_rx_sring_t *rxs; - int err; - struct ifnet *ifp; - - ifp = info->xn_ifp; - - info->tx_ring_ref = GRANT_INVALID_REF; - info->rx_ring_ref = GRANT_INVALID_REF; - info->rx.sring = NULL; - info->tx.sring = NULL; - info->irq = 0; - - txs = (netif_tx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); - if (!txs) { - err = ENOMEM; - xenbus_dev_fatal(dev, err, "allocating tx ring page"); - goto fail; - } - SHARED_RING_INIT(txs); - FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE); - err = xenbus_grant_ring(dev, virt_to_mfn(txs)); - if (err < 0) - goto fail; - info->tx_ring_ref = err; - - rxs = (netif_rx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); - if (!rxs) { - err = ENOMEM; - xenbus_dev_fatal(dev, err, "allocating rx ring page"); - goto fail; - } - SHARED_RING_INIT(rxs); - FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE); - - err = xenbus_grant_ring(dev, virt_to_mfn(rxs)); - if (err < 0) - goto fail; - info->rx_ring_ref = err; - -#if 0 - network_connect(ifp); -#endif - err = bind_listening_port_to_irqhandler(dev->otherend_id, - "xn", xn_intr, info, INTR_TYPE_NET | INTR_MPSAFE, NULL); - - if (err <= 0) { - xenbus_dev_fatal(dev, err, - "bind_evtchn_to_irqhandler failed"); - goto fail; - } - info->irq = err; - - show_device(info); - - return 0; - - fail: - netif_free(info); - return err; -} - -/** - * Callback received when the backend's state changes. - */ -static void -backend_changed(struct xenbus_device *dev, - XenbusState backend_state) -{ - struct netfront_info *sc = dev->dev_driver_data; - - DPRINTK("\n"); - - switch (backend_state) { - case XenbusStateInitialising: - case XenbusStateInitialised: - case XenbusStateConnected: - case XenbusStateUnknown: - case XenbusStateClosed: - case XenbusStateReconfigured: - case XenbusStateReconfiguring: - break; - case XenbusStateInitWait: - if (dev->state != XenbusStateInitialising) - break; - if (network_connect(sc->xn_ifp) != 0) - break; - xenbus_switch_state(dev, XenbusStateConnected); -#ifdef notyet - (void)send_fake_arp(netdev); -#endif - break; break; - case XenbusStateClosing: - xenbus_frontend_closed(dev); - break; - } -} - -static void -xn_free_rx_ring(struct netfront_info *sc) -{ -#if 0 - int i; - - for (i = 0; i < NET_RX_RING_SIZE; i++) { - if (sc->xn_cdata.xn_rx_chain[i] != NULL) { - m_freem(sc->xn_cdata.xn_rx_chain[i]); - sc->xn_cdata.xn_rx_chain[i] = NULL; - } - } - - sc->rx.rsp_cons = 0; - sc->xn_rx_if->req_prod = 0; - sc->xn_rx_if->event = sc->rx.rsp_cons ; -#endif -} - -static void -xn_free_tx_ring(struct netfront_info *sc) -{ -#if 0 - int i; - - for (i = 0; i < NET_TX_RING_SIZE; i++) { - if (sc->xn_cdata.xn_tx_chain[i] != NULL) { - m_freem(sc->xn_cdata.xn_tx_chain[i]); - sc->xn_cdata.xn_tx_chain[i] = NULL; - } - } - - return; -#endif -} - -static inline int -netfront_tx_slot_available(struct netfront_info *np) -{ - return ((np->tx.req_prod_pvt - np->tx.rsp_cons) < - (TX_MAX_TARGET - /* MAX_SKB_FRAGS */ 24 - 2)); -} -static void -netif_release_tx_bufs(struct netfront_info *np) -{ - struct mbuf *m; - int i; - - for (i = 1; i <= NET_TX_RING_SIZE; i++) { - m = np->xn_cdata.xn_tx_chain[i]; - - if (((u_long)m) < KERNBASE) - continue; - gnttab_grant_foreign_access_ref(np->grant_tx_ref[i], - np->xbdev->otherend_id, virt_to_mfn(mtod(m, vm_offset_t)), - GNTMAP_readonly); - gnttab_release_grant_reference(&np->gref_tx_head, - np->grant_tx_ref[i]); - np->grant_tx_ref[i] = GRANT_INVALID_REF; - add_id_to_freelist(np->tx_mbufs, i); - m_freem(m); - } -} - -static void -network_alloc_rx_buffers(struct netfront_info *sc) -{ - unsigned short id; - struct mbuf *m_new; - int i, batch_target, notify; - RING_IDX req_prod; - struct xen_memory_reservation reservation; - grant_ref_t ref; - int nr_flips; - netif_rx_request_t *req; - vm_offset_t vaddr; - u_long pfn; - - req_prod = sc->rx.req_prod_pvt; - - if (unlikely(sc->carrier == 0)) - return; - - /* - * Allocate skbuffs greedily, even though we batch updates to the - * receive ring. This creates a less bursty demand on the memory - * allocator, so should reduce the chance of failed allocation - * requests both for ourself and for other kernel subsystems. - */ - batch_target = sc->rx_target - (req_prod - sc->rx.rsp_cons); - for (i = mbufq_len(&sc->xn_rx_batch); i < batch_target; i++) { - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) - goto no_mbuf; - - m_cljget(m_new, M_DONTWAIT, MJUMPAGESIZE); - if ((m_new->m_flags & M_EXT) == 0) { - m_freem(m_new); - -no_mbuf: - if (i != 0) - goto refill; - /* - * XXX set timer - */ - break; - } - m_new->m_len = m_new->m_pkthdr.len = MJUMPAGESIZE; - - /* queue the mbufs allocated */ - mbufq_tail(&sc->xn_rx_batch, m_new); - } - - /* Is the batch large enough to be worthwhile? */ - if (i < (sc->rx_target/2)) { - if (req_prod >sc->rx.sring->req_prod) - goto push; - return; - } - /* Adjust floating fill target if we risked running out of buffers. */ - if ( ((req_prod - sc->rx.sring->rsp_prod) < (sc->rx_target / 4)) && - ((sc->rx_target *= 2) > sc->rx_max_target) ) - sc->rx_target = sc->rx_max_target; - -refill: - for (nr_flips = i = 0; ; i++) { - if ((m_new = mbufq_dequeue(&sc->xn_rx_batch)) == NULL) - break; - - m_new->m_ext.ext_args = (vm_paddr_t *)(uintptr_t)( - vtophys(m_new->m_ext.ext_buf) >> PAGE_SHIFT); - - id = xennet_rxidx(req_prod + i); - - KASSERT(sc->xn_cdata.xn_rx_chain[id] == NULL, - ("non-NULL xm_rx_chain")); - sc->xn_cdata.xn_rx_chain[id] = m_new; - - ref = gnttab_claim_grant_reference(&sc->gref_rx_head); - KASSERT((short)ref >= 0, ("negative ref")); - sc->grant_rx_ref[id] = ref; - - vaddr = mtod(m_new, vm_offset_t); - pfn = vtophys(vaddr) >> PAGE_SHIFT; - req = RING_GET_REQUEST(&sc->rx, req_prod + i); - - if (sc->copying_receiver == 0) { - gnttab_grant_foreign_transfer_ref(ref, - sc->xbdev->otherend_id, pfn); - sc->rx_pfn_array[nr_flips] = PFNTOMFN(pfn); - if (!xen_feature(XENFEAT_auto_translated_physmap)) { - /* Remove this page before passing - * back to Xen. - */ - set_phys_to_machine(pfn, INVALID_P2M_ENTRY); - MULTI_update_va_mapping(&sc->rx_mcl[i], - vaddr, 0, 0); - } - nr_flips++; - } else { - gnttab_grant_foreign_access_ref(ref, - sc->xbdev->otherend_id, - PFNTOMFN(pfn), 0); - } - req->id = id; - req->gref = ref; - - sc->rx_pfn_array[i] = - vtomach(mtod(m_new,vm_offset_t)) >> PAGE_SHIFT; - } - - KASSERT(i, ("no mbufs processed")); /* should have returned earlier */ - KASSERT(mbufq_len(&sc->xn_rx_batch) == 0, ("not all mbufs processed")); - /* - * We may have allocated buffers which have entries outstanding - * in the page * update queue -- make sure we flush those first! - */ - PT_UPDATES_FLUSH(); - if (nr_flips != 0) { -#ifdef notyet - /* Tell the ballon driver what is going on. */ - balloon_update_driver_allowance(i); -#endif - set_xen_guest_handle(reservation.extent_start, sc->rx_pfn_array); - reservation.nr_extents = i; - reservation.extent_order = 0; - reservation.address_bits = 0; - reservation.domid = DOMID_SELF; - - if (!xen_feature(XENFEAT_auto_translated_physmap)) { - - /* After all PTEs have been zapped, flush the TLB. */ - sc->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] = - UVMF_TLB_FLUSH|UVMF_ALL; - - /* Give away a batch of pages. */ - sc->rx_mcl[i].op = __HYPERVISOR_memory_op; - sc->rx_mcl[i].args[0] = XENMEM_decrease_reservation; - sc->rx_mcl[i].args[1] = (u_long)&reservation; - /* Zap PTEs and give away pages in one big multicall. */ - (void)HYPERVISOR_multicall(sc->rx_mcl, i+1); - - /* Check return status of HYPERVISOR_dom_mem_op(). */ - if (unlikely(sc->rx_mcl[i].result != i)) - panic("Unable to reduce memory reservation\n"); - } else { - if (HYPERVISOR_memory_op( - XENMEM_decrease_reservation, &reservation) - != i) - panic("Unable to reduce memory " - "reservation\n"); - } - } else { - wmb(); - } - - /* Above is a suitable barrier to ensure backend will see requests. */ - sc->rx.req_prod_pvt = req_prod + i; -push: - RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->rx, notify); - if (notify) - notify_remote_via_irq(sc->irq); -} - -static void -xn_rxeof(struct netfront_info *np) -{ - struct ifnet *ifp; - struct netfront_rx_info rinfo; - struct netif_rx_response *rx = &rinfo.rx; - struct netif_extra_info *extras = rinfo.extras; - RING_IDX i, rp; - multicall_entry_t *mcl; - struct mbuf *m; - struct mbuf_head rxq, errq; - int err, pages_flipped = 0; - - XN_RX_LOCK_ASSERT(np); - if (!netfront_carrier_ok(np)) - return; - - mbufq_init(&errq); - mbufq_init(&rxq); - - ifp = np->xn_ifp; - - rp = np->rx.sring->rsp_prod; - rmb(); /* Ensure we see queued responses up to 'rp'. */ - - i = np->rx.rsp_cons; - while ((i != rp)) { - memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx)); - memset(extras, 0, sizeof(rinfo.extras)); - - m = NULL; - err = xennet_get_responses(np, &rinfo, rp, &m, - &pages_flipped); - - if (unlikely(err)) { - if (m) - mbufq_tail(&errq, m); - np->stats.rx_errors++; - i = np->rx.rsp_cons; - continue; - } - - m->m_pkthdr.rcvif = ifp; - if ( rx->flags & NETRXF_data_validated ) { - /* Tell the stack the checksums are okay */ - /* - * XXX this isn't necessarily the case - need to add - * check - */ - - m->m_pkthdr.csum_flags |= - (CSUM_IP_CHECKED | CSUM_IP_VALID | CSUM_DATA_VALID - | CSUM_PSEUDO_HDR); - m->m_pkthdr.csum_data = 0xffff; - } - - np->stats.rx_packets++; - np->stats.rx_bytes += m->m_pkthdr.len; - - mbufq_tail(&rxq, m); - np->rx.rsp_cons = ++i; - } - - if (pages_flipped) { - /* Some pages are no longer absent... */ -#ifdef notyet - balloon_update_driver_allowance(-pages_flipped); -#endif - /* Do all the remapping work, and M->P updates, in one big - * hypercall. - */ - if (!!xen_feature(XENFEAT_auto_translated_physmap)) { - mcl = np->rx_mcl + pages_flipped; - mcl->op = __HYPERVISOR_mmu_update; - mcl->args[0] = (u_long)np->rx_mmu; - mcl->args[1] = pages_flipped; - mcl->args[2] = 0; - mcl->args[3] = DOMID_SELF; - (void)HYPERVISOR_multicall(np->rx_mcl, - pages_flipped + 1); - } - } - - while ((m = mbufq_dequeue(&errq))) - m_freem(m); - - /* - * Process all the mbufs after the remapping is complete. - * Break the mbuf chain first though. - */ - while ((m = mbufq_dequeue(&rxq)) != NULL) { - ifp->if_ipackets++; - - /* - * Do we really need to drop the rx lock? - */ - XN_RX_UNLOCK(np); - /* Pass it up. */ - (*ifp->if_input)(ifp, m); - XN_RX_LOCK(np); - } - - np->rx.rsp_cons = i; - -#if 0 - /* If we get a callback with very few responses, reduce fill target. */ - /* NB. Note exponential increase, linear decrease. */ - if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) > - ((3*np->rx_target) / 4)) && (--np->rx_target < np->rx_min_target)) - np->rx_target = np->rx_min_target; -#endif - - network_alloc_rx_buffers(np); - - np->rx.sring->rsp_event = i + 1; -} - -static void -xn_txeof(struct netfront_info *np) -{ - RING_IDX i, prod; - unsigned short id; - struct ifnet *ifp; - struct mbuf *m; - - XN_TX_LOCK_ASSERT(np); - - if (!netfront_carrier_ok(np)) - return; - - ifp = np->xn_ifp; - ifp->if_timer = 0; - - do { - prod = np->tx.sring->rsp_prod; - rmb(); /* Ensure we see responses up to 'rp'. */ - - for (i = np->tx.rsp_cons; i != prod; i++) { - id = RING_GET_RESPONSE(&np->tx, i)->id; - m = np->xn_cdata.xn_tx_chain[id]; - - ifp->if_opackets++; - KASSERT(m != NULL, ("mbuf not found in xn_tx_chain")); - M_ASSERTVALID(m); - if (unlikely(gnttab_query_foreign_access( - np->grant_tx_ref[id]) != 0)) { - printf("network_tx_buf_gc: warning " - "-- grant still in use by backend " - "domain.\n"); - goto out; - } - gnttab_end_foreign_access_ref( - np->grant_tx_ref[id]); - gnttab_release_grant_reference( - &np->gref_tx_head, np->grant_tx_ref[id]); - np->grant_tx_ref[id] = GRANT_INVALID_REF; - - np->xn_cdata.xn_tx_chain[id] = NULL; - add_id_to_freelist(np->xn_cdata.xn_tx_chain, id); - m_freem(m); - } - np->tx.rsp_cons = prod; - - /* - * Set a new event, then check for race with update of - * tx_cons. Note that it is essential to schedule a - * callback, no matter how few buffers are pending. Even if - * there is space in the transmit ring, higher layers may - * be blocked because too much data is outstanding: in such - * cases notification from Xen is likely to be the only kick - * that we'll get. - */ - np->tx.sring->rsp_event = - prod + ((np->tx.sring->req_prod - prod) >> 1) + 1; - - mb(); - - } while (prod != np->tx.sring->rsp_prod); - - out: - if (np->tx_full && - ((np->tx.sring->req_prod - prod) < NET_TX_RING_SIZE)) { - np->tx_full = 0; -#if 0 - if (np->user_state == UST_OPEN) - netif_wake_queue(dev); -#endif - } - -} - -static void -xn_intr(void *xsc) -{ - struct netfront_info *np = xsc; - struct ifnet *ifp = np->xn_ifp; - -#if 0 - if (!(np->rx.rsp_cons != np->rx.sring->rsp_prod && - likely(netfront_carrier_ok(np)) && - ifp->if_drv_flags & IFF_DRV_RUNNING)) - return; -#endif - if (np->tx.rsp_cons != np->tx.sring->rsp_prod) { - XN_TX_LOCK(np); - xn_txeof(np); - XN_TX_UNLOCK(np); - } - - XN_RX_LOCK(np); - xn_rxeof(np); - XN_RX_UNLOCK(np); - - if (ifp->if_drv_flags & IFF_DRV_RUNNING && - !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - xn_start(ifp); -} - - -static void -xennet_move_rx_slot(struct netfront_info *np, struct mbuf *m, - grant_ref_t ref) -{ - int new = xennet_rxidx(np->rx.req_prod_pvt); - - KASSERT(np->rx_mbufs[new] == NULL, ("rx_mbufs != NULL")); - np->rx_mbufs[new] = m; - np->grant_rx_ref[new] = ref; - RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new; - RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref; - np->rx.req_prod_pvt++; -} - -static int -xennet_get_extras(struct netfront_info *np, - struct netif_extra_info *extras, RING_IDX rp) -{ - struct netif_extra_info *extra; - RING_IDX cons = np->rx.rsp_cons; - - int err = 0; - - do { - struct mbuf *m; - grant_ref_t ref; - - if (unlikely(cons + 1 == rp)) { -#if 0 - if (net_ratelimit()) - WPRINTK("Missing extra info\n"); -#endif - err = -EINVAL; - break; - } - - extra = (struct netif_extra_info *) - RING_GET_RESPONSE(&np->rx, ++cons); - - if (unlikely(!extra->type || - extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { -#if 0 - if (net_ratelimit()) - WPRINTK("Invalid extra type: %d\n", - extra->type); -#endif - err = -EINVAL; - } else { - memcpy(&extras[extra->type - 1], extra, sizeof(*extra)); - } - - m = xennet_get_rx_mbuf(np, cons); - ref = xennet_get_rx_ref(np, cons); - xennet_move_rx_slot(np, m, ref); - } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); - - np->rx.rsp_cons = cons; - return err; -} - -static int -xennet_get_responses(struct netfront_info *np, - struct netfront_rx_info *rinfo, RING_IDX rp, - struct mbuf **list, - int *pages_flipped_p) -{ - int pages_flipped = *pages_flipped_p; - struct mmu_update *mmu; - struct multicall_entry *mcl; - struct netif_rx_response *rx = &rinfo->rx; - struct netif_extra_info *extras = rinfo->extras; - RING_IDX cons = np->rx.rsp_cons; - struct mbuf *m, *m0, *m_prev; - grant_ref_t ref = xennet_get_rx_ref(np, cons); - int max = 5 /* MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD) */; - int frags = 1; - int err = 0; - u_long ret; - - m0 = m = m_prev = xennet_get_rx_mbuf(np, cons); - - - if (rx->flags & NETRXF_extra_info) { - err = xennet_get_extras(np, extras, rp); - cons = np->rx.rsp_cons; - } - - - if (m0 != NULL) { - m0->m_pkthdr.len = 0; - m0->m_next = NULL; - } - - for (;;) { - u_long mfn; - -#if 0 - printf("rx->status=%hd rx->offset=%hu frags=%u\n", - rx->status, rx->offset, frags); -#endif - if (unlikely(rx->status < 0 || - rx->offset + rx->status > PAGE_SIZE)) { -#if 0 - if (net_ratelimit()) - WPRINTK("rx->offset: %x, size: %u\n", - rx->offset, rx->status); -#endif - xennet_move_rx_slot(np, m, ref); - err = -EINVAL; - goto next; - } - - /* - * This definitely indicates a bug, either in this driver or in - * the backend driver. In future this should flag the bad - * situation to the system controller to reboot the backed. - */ - if (ref == GRANT_INVALID_REF) { -#if 0 - if (net_ratelimit()) - WPRINTK("Bad rx response id %d.\n", rx->id); -#endif - err = -EINVAL; - goto next; - } - - if (!np->copying_receiver) { - /* Memory pressure, insufficient buffer - * headroom, ... - */ - if (!(mfn = gnttab_end_foreign_transfer_ref(ref))) { - if (net_ratelimit()) - WPRINTK("Unfulfilled rx req " - "(id=%d, st=%d).\n", - rx->id, rx->status); - xennet_move_rx_slot(np, m, ref); - err = -ENOMEM; - goto next; - } - - if (!xen_feature( XENFEAT_auto_translated_physmap)) { - /* Remap the page. */ - void *vaddr = mtod(m, void *); - uint32_t pfn; - - mcl = np->rx_mcl + pages_flipped; - mmu = np->rx_mmu + pages_flipped; - - MULTI_update_va_mapping(mcl, (u_long)vaddr, - (((vm_paddr_t)mfn) << PAGE_SHIFT) | PG_RW | - PG_V | PG_M | PG_A, 0); - pfn = (uint32_t)m->m_ext.ext_args; - mmu->ptr = ((vm_paddr_t)mfn << PAGE_SHIFT) | - MMU_MACHPHYS_UPDATE; - mmu->val = pfn; - - set_phys_to_machine(pfn, mfn); - } - pages_flipped++; - } else { - ret = gnttab_end_foreign_access_ref(ref); - KASSERT(ret, ("ret != 0")); - } - - gnttab_release_grant_reference(&np->gref_rx_head, ref); - -next: - if (m != NULL) { - m->m_len = rx->status; - m->m_data += rx->offset; - m0->m_pkthdr.len += rx->status; - } - - if (!(rx->flags & NETRXF_more_data)) - break; - - if (cons + frags == rp) { - if (net_ratelimit()) - WPRINTK("Need more frags\n"); - err = -ENOENT; - break; - } - m_prev = m; - - rx = RING_GET_RESPONSE(&np->rx, cons + frags); - m = xennet_get_rx_mbuf(np, cons + frags); - - m_prev->m_next = m; - m->m_next = NULL; - ref = xennet_get_rx_ref(np, cons + frags); - frags++; - } - *list = m0; - - if (unlikely(frags > max)) { - if (net_ratelimit()) - WPRINTK("Too many frags\n"); - err = -E2BIG; - } - - if (unlikely(err)) - np->rx.rsp_cons = cons + frags; - - *pages_flipped_p = pages_flipped; - - return err; -} - -static void -xn_tick_locked(struct netfront_info *sc) -{ - XN_RX_LOCK_ASSERT(sc); - callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); - - /* XXX placeholder for printing debug information */ - -} - - -static void -xn_tick(void *xsc) -{ - struct netfront_info *sc; - - sc = xsc; - XN_RX_LOCK(sc); - xn_tick_locked(sc); - XN_RX_UNLOCK(sc); - -} -static void -xn_start_locked(struct ifnet *ifp) -{ - unsigned short id; - struct mbuf *m_head, *new_m; - struct netfront_info *sc; - netif_tx_request_t *tx; - RING_IDX i; - grant_ref_t ref; - u_long mfn, tx_bytes; - int notify; - - sc = ifp->if_softc; - tx_bytes = 0; - - if (!netfront_carrier_ok(sc)) - return; - - for (i = sc->tx.req_prod_pvt; TRUE; i++) { - IF_DEQUEUE(&ifp->if_snd, m_head); - if (m_head == NULL) - break; - - if (!netfront_tx_slot_available(sc)) { - IF_PREPEND(&ifp->if_snd, m_head); - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - break; - } - - id = get_id_from_freelist(sc->xn_cdata.xn_tx_chain); - - /* - * Start packing the mbufs in this chain into - * the fragment pointers. Stop when we run out - * of fragments or hit the end of the mbuf chain. - */ - new_m = makembuf(m_head); - tx = RING_GET_REQUEST(&sc->tx, i); - tx->id = id; - ref = gnttab_claim_grant_reference(&sc->gref_tx_head); - KASSERT((short)ref >= 0, ("Negative ref")); - mfn = virt_to_mfn(mtod(new_m, vm_offset_t)); - gnttab_grant_foreign_access_ref(ref, sc->xbdev->otherend_id, - mfn, GNTMAP_readonly); - tx->gref = sc->grant_tx_ref[id] = ref; - tx->size = new_m->m_pkthdr.len; -#if 0 - tx->flags = (skb->ip_summed == CHECKSUM_HW) ? NETTXF_csum_blank : 0; -#endif - tx->flags = 0; - new_m->m_next = NULL; - new_m->m_nextpkt = NULL; - - m_freem(m_head); - - sc->xn_cdata.xn_tx_chain[id] = new_m; - BPF_MTAP(ifp, new_m); - - sc->stats.tx_bytes += new_m->m_pkthdr.len; - sc->stats.tx_packets++; - } - - sc->tx.req_prod_pvt = i; - RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->tx, notify); - if (notify) - notify_remote_via_irq(sc->irq); - - xn_txeof(sc); - - if (RING_FULL(&sc->tx)) { - sc->tx_full = 1; -#if 0 - netif_stop_queue(dev); -#endif - } - - return; -} - -static void -xn_start(struct ifnet *ifp) -{ - struct netfront_info *sc; - sc = ifp->if_softc; - XN_TX_LOCK(sc); - xn_start_locked(ifp); - XN_TX_UNLOCK(sc); -} - -/* equivalent of network_open() in Linux */ -static void -xn_ifinit_locked(struct netfront_info *sc) -{ - struct ifnet *ifp; - - XN_LOCK_ASSERT(sc); - - ifp = sc->xn_ifp; - - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - return; - - xn_stop(sc); - - network_alloc_rx_buffers(sc); - sc->rx.sring->rsp_event = sc->rx.rsp_cons + 1; - - ifp->if_drv_flags |= IFF_DRV_RUNNING; - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - - callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); - -} - - -static void -xn_ifinit(void *xsc) -{ - struct netfront_info *sc = xsc; - - XN_LOCK(sc); - xn_ifinit_locked(sc); - XN_UNLOCK(sc); - -} - - -static int -xn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) -{ - struct netfront_info *sc = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *) data; - struct ifaddr *ifa = (struct ifaddr *)data; - - int mask, error = 0; - switch(cmd) { - case SIOCSIFADDR: - case SIOCGIFADDR: - XN_LOCK(sc); - if (ifa->ifa_addr->sa_family == AF_INET) { - ifp->if_flags |= IFF_UP; - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) - xn_ifinit_locked(sc); - arp_ifinit(ifp, ifa); - } else - error = ether_ioctl(ifp, cmd, data); - XN_UNLOCK(sc); - break; - case SIOCSIFMTU: - /* XXX can we alter the MTU on a VN ?*/ -#ifdef notyet - if (ifr->ifr_mtu > XN_JUMBO_MTU) - error = EINVAL; - else -#endif - { - ifp->if_mtu = ifr->ifr_mtu; - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - xn_ifinit(sc); - } - break; - case SIOCSIFFLAGS: - XN_LOCK(sc); - if (ifp->if_flags & IFF_UP) { - /* - * If only the state of the PROMISC flag changed, - * then just use the 'set promisc mode' command - * instead of reinitializing the entire NIC. Doing - * a full re-init means reloading the firmware and - * waiting for it to start up, which may take a - * second or two. - */ -#ifdef notyet - /* No promiscuous mode with Xen */ - if (ifp->if_drv_flags & IFF_DRV_RUNNING && - ifp->if_flags & IFF_PROMISC && - !(sc->xn_if_flags & IFF_PROMISC)) { - XN_SETBIT(sc, XN_RX_MODE, - XN_RXMODE_RX_PROMISC); - } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && - !(ifp->if_flags & IFF_PROMISC) && - sc->xn_if_flags & IFF_PROMISC) { - XN_CLRBIT(sc, XN_RX_MODE, - XN_RXMODE_RX_PROMISC); - } else -#endif - xn_ifinit_locked(sc); - } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - xn_stop(sc); - } - } - sc->xn_if_flags = ifp->if_flags; - XN_UNLOCK(sc); - error = 0; - break; - case SIOCSIFCAP: - mask = ifr->ifr_reqcap ^ ifp->if_capenable; - if (mask & IFCAP_HWCSUM) { - if (IFCAP_HWCSUM & ifp->if_capenable) - ifp->if_capenable &= ~IFCAP_HWCSUM; - else - ifp->if_capenable |= IFCAP_HWCSUM; - } - error = 0; - break; - case SIOCADDMULTI: - case SIOCDELMULTI: -#ifdef notyet - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - XN_LOCK(sc); - xn_setmulti(sc); - XN_UNLOCK(sc); - error = 0; - } -#endif - /* FALLTHROUGH */ - case SIOCSIFMEDIA: - case SIOCGIFMEDIA: - error = EINVAL; - break; - default: - error = ether_ioctl(ifp, cmd, data); - } - - return (error); -} - -static void -xn_stop(struct netfront_info *sc) -{ - struct ifnet *ifp; - - XN_LOCK_ASSERT(sc); - - ifp = sc->xn_ifp; - - callout_stop(&sc->xn_stat_ch); - - xn_free_rx_ring(sc); - xn_free_tx_ring(sc); - - ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); -} - -/* START of Xenolinux helper functions adapted to FreeBSD */ -static int -network_connect(struct ifnet *ifp) -{ - struct netfront_info *np; - int i, requeue_idx, err; - grant_ref_t ref; - netif_rx_request_t *req; - u_int feature_rx_copy, feature_rx_flip; - - printf("network_connect\n"); - - np = ifp->if_softc; - err = xenbus_scanf(XBT_NIL, np->xbdev->otherend, - "feature-rx-copy", "%u", &feature_rx_copy); - if (err != 1) - feature_rx_copy = 0; - err = xenbus_scanf(XBT_NIL, np->xbdev->otherend, - "feature-rx-flip", "%u", &feature_rx_flip); - if (err != 1) - feature_rx_flip = 1; - - /* - * Copy packets on receive path if: - * (a) This was requested by user, and the backend supports it; or - * (b) Flipping was requested, but this is unsupported by the backend. - */ - np->copying_receiver = ((MODPARM_rx_copy && feature_rx_copy) || - (MODPARM_rx_flip && !feature_rx_flip)); - - XN_LOCK(np); - /* Recovery procedure: */ - err = talk_to_backend(np->xbdev, np); - if (err) - return (err); - - /* Step 1: Reinitialise variables. */ - netif_release_tx_bufs(np); - - /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */ - for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { - struct mbuf *m; - - if (np->rx_mbufs[i] == NULL) - continue; - - m = np->rx_mbufs[requeue_idx] = xennet_get_rx_mbuf(np, i); - ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i); - req = RING_GET_REQUEST(&np->rx, requeue_idx); - - if (!np->copying_receiver) { - gnttab_grant_foreign_transfer_ref(ref, - np->xbdev->otherend_id, - vtophys(mtod(m, vm_offset_t))); - } else { - gnttab_grant_foreign_access_ref(ref, - np->xbdev->otherend_id, - vtophys(mtod(m, vm_offset_t)), 0); - } - req->gref = ref; - req->id = requeue_idx; - - requeue_idx++; - } - - np->rx.req_prod_pvt = requeue_idx; - - /* Step 3: All public and private state should now be sane. Get - * ready to start sending and receiving packets and give the driver - * domain a kick because we've probably just requeued some - * packets. - */ - netfront_carrier_on(np); - notify_remote_via_irq(np->irq); - XN_TX_LOCK(np); - xn_txeof(np); - XN_TX_UNLOCK(np); - network_alloc_rx_buffers(np); - XN_UNLOCK(np); - - return (0); -} - - -static void -show_device(struct netfront_info *sc) -{ -#ifdef DEBUG - if (sc) { - IPRINTK("<vif handle=%u %s(%s) evtchn=%u irq=%u tx=%p rx=%p>\n", - sc->xn_ifno, - be_state_name[sc->xn_backend_state], - sc->xn_user_state ? "open" : "closed", - sc->xn_evtchn, - sc->xn_irq, - sc->xn_tx_if, - sc->xn_rx_if); - } else { - IPRINTK("<vif NULL>\n"); - } -#endif -} - -static int ifno = 0; - -/** Create a network device. - * @param handle device handle - */ -static int -create_netdev(struct xenbus_device *dev, struct ifnet **ifpp) -{ - int i; - struct netfront_info *np; - int err; - struct ifnet *ifp; - - np = (struct netfront_info *)malloc(sizeof(struct netfront_info), - M_DEVBUF, M_NOWAIT); - if (np == NULL) - return (ENOMEM); - - memset(np, 0, sizeof(struct netfront_info)); - - np->xbdev = dev; - - XN_LOCK_INIT(np, xennetif); - np->rx_target = RX_MIN_TARGET; - np->rx_min_target = RX_MIN_TARGET; - np->rx_max_target = RX_MAX_TARGET; - - /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */ - for (i = 0; i <= NET_TX_RING_SIZE; i++) { - np->tx_mbufs[i] = (void *) ((u_long) i+1); - np->grant_tx_ref[i] = GRANT_INVALID_REF; - } - for (i = 0; i <= NET_RX_RING_SIZE; i++) { - np->rx_mbufs[i] = NULL; - np->grant_rx_ref[i] = GRANT_INVALID_REF; - } - /* A grant for every tx ring slot */ - if (gnttab_alloc_grant_references(TX_MAX_TARGET, - &np->gref_tx_head) < 0) { - printf("#### netfront can't alloc tx grant refs\n"); - err = ENOMEM; - goto exit; - } - /* A grant for every rx ring slot */ - if (gnttab_alloc_grant_references(RX_MAX_TARGET, - &np->gref_rx_head) < 0) { - printf("#### netfront can't alloc rx grant refs\n"); - gnttab_free_grant_references(np->gref_tx_head); - err = ENOMEM; - goto exit; - } - - err = xen_net_read_mac(dev, np->mac); - if (err) { - xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename); - goto out; - } - - /* Set up ifnet structure */ - *ifpp = ifp = np->xn_ifp = if_alloc(IFT_ETHER); - ifp->if_softc = np; - if_initname(ifp, "xn", ifno++/* ifno */); - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; - ifp->if_ioctl = xn_ioctl; - ifp->if_output = ether_output; - ifp->if_start = xn_start; -#ifdef notyet - ifp->if_watchdog = xn_watchdog; -#endif - ifp->if_init = xn_ifinit; - ifp->if_mtu = ETHERMTU; - ifp->if_snd.ifq_maxlen = NET_TX_RING_SIZE - 1; - -#ifdef notyet - ifp->if_hwassist = XN_CSUM_FEATURES; - ifp->if_capabilities = IFCAP_HWCSUM; - ifp->if_capenable = ifp->if_capabilities; -#endif - - ether_ifattach(ifp, np->mac); - callout_init(&np->xn_stat_ch, CALLOUT_MPSAFE); - netfront_carrier_off(np); - - return (0); - -exit: - gnttab_free_grant_references(np->gref_tx_head); -out: - panic("do something smart"); - -} - -/** - * Handle the change of state of the backend to Closing. We must delete our - * device-layer structures now, to ensure that writes are flushed through to - * the backend. Once is this done, we can switch to Closed in - * acknowledgement. - */ -#if 0 -static void netfront_closing(struct xenbus_device *dev) -{ -#if 0 - struct netfront_info *info = dev->dev_driver_data; - - DPRINTK("netfront_closing: %s removed\n", dev->nodename); - - close_netdev(info); -#endif - xenbus_switch_state(dev, XenbusStateClosed); -} -#endif - -static int netfront_remove(struct xenbus_device *dev) -{ - struct netfront_info *info = dev->dev_driver_data; - - DPRINTK("%s\n", dev->nodename); - - netif_free(info); - free(info, M_DEVBUF); - - return 0; -} - - -static void netif_free(struct netfront_info *info) -{ - netif_disconnect_backend(info); -#if 0 - close_netdev(info); -#endif -} - - - -static void netif_disconnect_backend(struct netfront_info *info) -{ - xn_stop(info); - end_access(info->tx_ring_ref, info->tx.sring); - end_access(info->rx_ring_ref, info->rx.sring); - info->tx_ring_ref = GRANT_INVALID_REF; - info->rx_ring_ref = GRANT_INVALID_REF; - info->tx.sring = NULL; - info->rx.sring = NULL; - -#if 0 - if (info->irq) - unbind_from_irqhandler(info->irq, info->netdev); -#else - panic("FIX ME"); -#endif - info->irq = 0; -} - - -static void end_access(int ref, void *page) -{ - if (ref != GRANT_INVALID_REF) - gnttab_end_foreign_access(ref, page); -} - - -/* ** Driver registration ** */ - - -static struct xenbus_device_id netfront_ids[] = { - { "vif" }, - { "" } -}; - - -static struct xenbus_driver netfront = { - .name = "vif", - .ids = netfront_ids, - .probe = netfront_probe, - .remove = netfront_remove, - .resume = netfront_resume, - .otherend_changed = backend_changed, -}; - -static void -netif_init(void *unused) -{ - if (!is_running_on_xen()) - return; - - if (is_initial_xendomain()) - return; - - IPRINTK("Initialising virtual ethernet driver.\n"); - - xenbus_register_frontend(&netfront); -} - -SYSINIT(xennetif, SI_SUB_PSEUDO, SI_ORDER_SECOND, netif_init, NULL); - - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 8 - * tab-width: 4 - * indent-tabs-mode: t - * End: - */ diff --git a/sys/dev/xen/pcifront/pcifront.c b/sys/dev/xen/pcifront/pcifront.c deleted file mode 100644 index e6c498b..0000000 --- a/sys/dev/xen/pcifront/pcifront.c +++ /dev/null @@ -1,688 +0,0 @@ -/* - * Copyright (c) 2006, Cisco Systems, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Cisco Systems, Inc. nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/module.h> -#include <sys/systm.h> -#include <sys/mbuf.h> -#include <sys/malloc.h> -#include <sys/kernel.h> -#include <sys/socket.h> -#include <sys/queue.h> - -#include <machine/vmparam.h> -#include <vm/vm.h> -#include <vm/pmap.h> - -#include <machine/bus.h> -#include <machine/resource.h> -#include <machine/frame.h> - -#include <sys/bus.h> -#include <sys/rman.h> - -#include <machine/intr_machdep.h> - -#include <machine/xen-os.h> -#include <machine/hypervisor.h> -#include <machine/hypervisor-ifs.h> -#include <machine/xen_intr.h> -#include <machine/evtchn.h> -#include <machine/xenbus.h> -#include <machine/gnttab.h> -#include <machine/xen-public/memory.h> -#include <machine/xen-public/io/pciif.h> - -#include <sys/pciio.h> -#include <dev/pci/pcivar.h> -#include "pcib_if.h" - -#ifdef XEN_PCIDEV_FE_DEBUG -#define DPRINTF(fmt, args...) \ - printf("pcifront (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) -#else -#define DPRINTF(fmt, args...) ((void)0) -#endif -#define WPRINTF(fmt, args...) \ - printf("pcifront (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) - -#define INVALID_GRANT_REF (0) -#define INVALID_EVTCHN (-1) -#define virt_to_mfn(x) (vtomach(x) >> PAGE_SHIFT) - -struct pcifront_device { - STAILQ_ENTRY(pcifront_device) next; - - struct xenbus_device *xdev; - - int unit; - int evtchn; - int gnt_ref; - - /* Lock this when doing any operations in sh_info */ - struct mtx sh_info_lock; - struct xen_pci_sharedinfo *sh_info; - - device_t ndev; - - int ref_cnt; -}; - -static STAILQ_HEAD(pcifront_dlist, pcifront_device) pdev_list = STAILQ_HEAD_INITIALIZER(pdev_list); - -struct xpcib_softc { - int domain; - int bus; - struct pcifront_device *pdev; -}; - -/* Allocate a PCI device structure */ -static struct pcifront_device * -alloc_pdev(struct xenbus_device *xdev) -{ - struct pcifront_device *pdev = NULL; - int err, unit; - - err = sscanf(xdev->nodename, "device/pci/%d", &unit); - if (err != 1) { - if (err == 0) - err = -EINVAL; - xenbus_dev_fatal(pdev->xdev, err, "Error scanning pci device instance number"); - goto out; - } - - pdev = (struct pcifront_device *)malloc(sizeof(struct pcifront_device), M_DEVBUF, M_NOWAIT); - if (pdev == NULL) { - err = -ENOMEM; - xenbus_dev_fatal(xdev, err, "Error allocating pcifront_device struct"); - goto out; - } - pdev->unit = unit; - pdev->xdev = xdev; - pdev->ref_cnt = 1; - - pdev->sh_info = (struct xen_pci_sharedinfo *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); - if (pdev->sh_info == NULL) { - free(pdev, M_DEVBUF); - pdev = NULL; - err = -ENOMEM; - xenbus_dev_fatal(xdev, err, "Error allocating sh_info struct"); - goto out; - } - pdev->sh_info->flags = 0; - - xdev->data = pdev; - - mtx_init(&pdev->sh_info_lock, "info_lock", "pci shared dev info lock", MTX_DEF); - - pdev->evtchn = INVALID_EVTCHN; - pdev->gnt_ref = INVALID_GRANT_REF; - - STAILQ_INSERT_TAIL(&pdev_list, pdev, next); - - DPRINTF("Allocated pdev @ 0x%p (unit=%d)\n", pdev, unit); - - out: - return pdev; -} - -/* Hold a reference to a pcifront device */ -static void -get_pdev(struct pcifront_device *pdev) -{ - pdev->ref_cnt++; -} - -/* Release a reference to a pcifront device */ -static void -put_pdev(struct pcifront_device *pdev) -{ - if (--pdev->ref_cnt > 0) - return; - - DPRINTF("freeing pdev @ 0x%p (ref_cnt=%d)\n", pdev, pdev->ref_cnt); - - if (pdev->evtchn != INVALID_EVTCHN) - xenbus_free_evtchn(pdev->xdev, pdev->evtchn); - - if (pdev->gnt_ref != INVALID_GRANT_REF) - gnttab_end_foreign_access(pdev->gnt_ref, 0, (void *)pdev->sh_info); - - pdev->xdev->data = NULL; - - free(pdev, M_DEVBUF); -} - - -/* Write to the xenbus info needed by backend */ -static int -pcifront_publish_info(struct pcifront_device *pdev) -{ - int err = 0; - struct xenbus_transaction *trans; - - err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info)); - if (err < 0) { - WPRINTF("error granting access to ring page\n"); - goto out; - } - - pdev->gnt_ref = err; - - err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn); - if (err) - goto out; - - do_publish: - trans = xenbus_transaction_start(); - if (IS_ERR(trans)) { - xenbus_dev_fatal(pdev->xdev, err, - "Error writing configuration for backend " - "(start transaction)"); - goto out; - } - - err = xenbus_printf(trans, pdev->xdev->nodename, - "pci-op-ref", "%u", pdev->gnt_ref); - if (!err) - err = xenbus_printf(trans, pdev->xdev->nodename, - "event-channel", "%u", pdev->evtchn); - if (!err) - err = xenbus_printf(trans, pdev->xdev->nodename, - "magic", XEN_PCI_MAGIC); - if (!err) - err = xenbus_switch_state(pdev->xdev, trans, - XenbusStateInitialised); - - if (err) { - xenbus_transaction_end(trans, 1); - xenbus_dev_fatal(pdev->xdev, err, - "Error writing configuration for backend"); - goto out; - } else { - err = xenbus_transaction_end(trans, 0); - if (err == -EAGAIN) - goto do_publish; - else if (err) { - xenbus_dev_fatal(pdev->xdev, err, - "Error completing transaction for backend"); - goto out; - } - } - - out: - return err; -} - -/* The backend is now connected so complete the connection process on our side */ -static int -pcifront_connect(struct pcifront_device *pdev) -{ - device_t nexus; - devclass_t nexus_devclass; - - /* We will add our device as a child of the nexus0 device */ - if (!(nexus_devclass = devclass_find("nexus")) || - !(nexus = devclass_get_device(nexus_devclass, 0))) { - WPRINTF("could not find nexus0!\n"); - return -1; - } - - /* Create a newbus device representing this frontend instance */ - pdev->ndev = BUS_ADD_CHILD(nexus, 0, "xpcife", pdev->unit); - if (!pdev->ndev) { - WPRINTF("could not create xpcife%d!\n", pdev->unit); - return -EFAULT; - } - get_pdev(pdev); - device_set_ivars(pdev->ndev, pdev); - - /* Good to go connected now */ - xenbus_switch_state(pdev->xdev, NULL, XenbusStateConnected); - - printf("pcifront: connected to %s\n", pdev->xdev->nodename); - - mtx_lock(&Giant); - device_probe_and_attach(pdev->ndev); - mtx_unlock(&Giant); - - return 0; -} - -/* The backend is closing so process a disconnect */ -static int -pcifront_disconnect(struct pcifront_device *pdev) -{ - int err = 0; - XenbusState prev_state; - - prev_state = xenbus_read_driver_state(pdev->xdev->nodename); - - if (prev_state < XenbusStateClosing) { - err = xenbus_switch_state(pdev->xdev, NULL, XenbusStateClosing); - if (!err && prev_state == XenbusStateConnected) { - /* TODO - need to detach the newbus devices */ - } - } - - return err; -} - -/* Process a probe from the xenbus */ -static int -pcifront_probe(struct xenbus_device *xdev, - const struct xenbus_device_id *id) -{ - int err = 0; - struct pcifront_device *pdev; - - DPRINTF("xenbus probing\n"); - - if ((pdev = alloc_pdev(xdev)) == NULL) - goto out; - - err = pcifront_publish_info(pdev); - - out: - if (err) - put_pdev(pdev); - return err; -} - -/* Remove the xenbus PCI device */ -static int -pcifront_remove(struct xenbus_device *xdev) -{ - DPRINTF("removing xenbus device node (%s)\n", xdev->nodename); - if (xdev->data) - put_pdev(xdev->data); - return 0; -} - -/* Called by xenbus when our backend node changes state */ -static void -pcifront_backend_changed(struct xenbus_device *xdev, - XenbusState be_state) -{ - struct pcifront_device *pdev = xdev->data; - - switch (be_state) { - case XenbusStateClosing: - DPRINTF("backend closing (%s)\n", xdev->nodename); - pcifront_disconnect(pdev); - break; - - case XenbusStateClosed: - DPRINTF("backend closed (%s)\n", xdev->nodename); - pcifront_disconnect(pdev); - break; - - case XenbusStateConnected: - DPRINTF("backend connected (%s)\n", xdev->nodename); - pcifront_connect(pdev); - break; - - default: - break; - } -} - -/* Process PCI operation */ -static int -do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op) -{ - int err = 0; - struct xen_pci_op *active_op = &pdev->sh_info->op; - evtchn_port_t port = pdev->evtchn; - time_t timeout; - - mtx_lock(&pdev->sh_info_lock); - - memcpy(active_op, op, sizeof(struct xen_pci_op)); - - /* Go */ - wmb(); - set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags); - notify_remote_via_evtchn(port); - - timeout = time_uptime + 2; - - clear_evtchn(port); - - /* Spin while waiting for the answer */ - while (test_bit - (_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) { - int err = HYPERVISOR_poll(&port, 1, 3 * hz); - if (err) - panic("Failed HYPERVISOR_poll: err=%d", err); - clear_evtchn(port); - if (time_uptime > timeout) { - WPRINTF("pciback not responding!!!\n"); - clear_bit(_XEN_PCIF_active, - (unsigned long *)&pdev->sh_info->flags); - err = XEN_PCI_ERR_dev_not_found; - goto out; - } - } - - memcpy(op, active_op, sizeof(struct xen_pci_op)); - - err = op->err; - out: - mtx_unlock(&pdev->sh_info_lock); - return err; -} - -/* ** XenBus Driver registration ** */ - -static struct xenbus_device_id pcifront_ids[] = { - { "pci" }, - { "" } -}; - -static struct xenbus_driver pcifront = { - .name = "pcifront", - .ids = pcifront_ids, - .probe = pcifront_probe, - .remove = pcifront_remove, - .otherend_changed = pcifront_backend_changed, -}; - -/* Register the driver with xenbus during sys init */ -static void -pcifront_init(void *unused) -{ - if ((xen_start_info->flags & SIF_INITDOMAIN)) - return; - - DPRINTF("xenbus registering\n"); - - xenbus_register_frontend(&pcifront); -} - -SYSINIT(pciif, SI_SUB_PSEUDO, SI_ORDER_ANY, pcifront_init, NULL) - - -/* Newbus xpcife device driver probe */ -static int -xpcife_probe(device_t dev) -{ -#ifdef XEN_PCIDEV_FE_DEBUG - struct pcifront_device *pdev = (struct pcifront_device *)device_get_ivars(dev); - DPRINTF("xpcife probe (unit=%d)\n", pdev->unit); -#endif - return 0; -} - -/* Newbus xpcife device driver attach */ -static int -xpcife_attach(device_t dev) -{ - struct pcifront_device *pdev = (struct pcifront_device *)device_get_ivars(dev); - int i, num_roots, len, err; - char str[64]; - unsigned int domain, bus; - - DPRINTF("xpcife attach (unit=%d)\n", pdev->unit); - - err = xenbus_scanf(NULL, pdev->xdev->otherend, - "root_num", "%d", &num_roots); - if (err != 1) { - if (err == 0) - err = -EINVAL; - xenbus_dev_fatal(pdev->xdev, err, - "Error reading number of PCI roots"); - goto out; - } - - /* Add a pcib device for each root */ - for (i = 0; i < num_roots; i++) { - device_t child; - - len = snprintf(str, sizeof(str), "root-%d", i); - if (unlikely(len >= (sizeof(str) - 1))) { - err = -ENOMEM; - goto out; - } - - err = xenbus_scanf(NULL, pdev->xdev->otherend, str, - "%x:%x", &domain, &bus); - if (err != 2) { - if (err >= 0) - err = -EINVAL; - xenbus_dev_fatal(pdev->xdev, err, - "Error reading PCI root %d", i); - goto out; - } - err = 0; - if (domain != pdev->xdev->otherend_id) { - err = -EINVAL; - xenbus_dev_fatal(pdev->xdev, err, - "Domain mismatch %d != %d", domain, pdev->xdev->otherend_id); - goto out; - } - - child = device_add_child(dev, "pcib", bus); - if (!child) { - err = -ENOMEM; - xenbus_dev_fatal(pdev->xdev, err, - "Unable to create pcib%d", bus); - goto out; - } - } - - out: - return bus_generic_attach(dev); -} - -static devclass_t xpcife_devclass; - -static device_method_t xpcife_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, xpcife_probe), - DEVMETHOD(device_attach, xpcife_attach), - DEVMETHOD(device_detach, bus_generic_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), - DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - {0, 0} -}; - -static driver_t xpcife_driver = { - "xpcife", - xpcife_methods, - 0, -}; - -DRIVER_MODULE(xpcife, nexus, xpcife_driver, xpcife_devclass, 0, 0); - - -/* Newbus xen pcib device driver probe */ -static int -xpcib_probe(device_t dev) -{ - struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev); - struct pcifront_device *pdev = (struct pcifront_device *)device_get_ivars(device_get_parent(dev)); - - DPRINTF("xpcib probe (bus=%d)\n", device_get_unit(dev)); - - sc->domain = pdev->xdev->otherend_id; - sc->bus = device_get_unit(dev); - sc->pdev = pdev; - - return 0; -} - -/* Newbus xen pcib device driver attach */ -static int -xpcib_attach(device_t dev) -{ - struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev); - - DPRINTF("xpcib attach (bus=%d)\n", sc->bus); - - device_add_child(dev, "pci", sc->bus); - return bus_generic_attach(dev); -} - -static int -xpcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) -{ - struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev); - switch (which) { - case PCIB_IVAR_BUS: - *result = sc->bus; - return 0; - } - return ENOENT; -} - -/* Return the number of slots supported */ -static int -xpcib_maxslots(device_t dev) -{ - return 31; -} - -#define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) - -/* Read configuration space register */ -static u_int32_t -xpcib_read_config(device_t dev, int bus, int slot, int func, - int reg, int bytes) -{ - struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev); - struct xen_pci_op op = { - .cmd = XEN_PCI_OP_conf_read, - .domain = sc->domain, - .bus = sc->bus, - .devfn = PCI_DEVFN(slot, func), - .offset = reg, - .size = bytes, - }; - int err; - - err = do_pci_op(sc->pdev, &op); - - DPRINTF("read config (b=%d, s=%d, f=%d, reg=%d, len=%d, val=%x, err=%d)\n", - bus, slot, func, reg, bytes, op.value, err); - - if (err) - op.value = ~0; - - return op.value; -} - -/* Write configuration space register */ -static void -xpcib_write_config(device_t dev, int bus, int slot, int func, - int reg, u_int32_t data, int bytes) -{ - struct xpcib_softc *sc = (struct xpcib_softc *)device_get_softc(dev); - struct xen_pci_op op = { - .cmd = XEN_PCI_OP_conf_write, - .domain = sc->domain, - .bus = sc->bus, - .devfn = PCI_DEVFN(slot, func), - .offset = reg, - .size = bytes, - .value = data, - }; - int err; - - err = do_pci_op(sc->pdev, &op); - - DPRINTF("write config (b=%d, s=%d, f=%d, reg=%d, len=%d, val=%x, err=%d)\n", - bus, slot, func, reg, bytes, data, err); -} - -static int -xpcib_route_interrupt(device_t pcib, device_t dev, int pin) -{ - struct pci_devinfo *dinfo = device_get_ivars(dev); - pcicfgregs *cfg = &dinfo->cfg; - - DPRINTF("route intr (pin=%d, line=%d)\n", pin, cfg->intline); - - return cfg->intline; -} - -static device_method_t xpcib_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, xpcib_probe), - DEVMETHOD(device_attach, xpcib_attach), - DEVMETHOD(device_detach, bus_generic_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_read_ivar, xpcib_read_ivar), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - - /* pcib interface */ - DEVMETHOD(pcib_maxslots, xpcib_maxslots), - DEVMETHOD(pcib_read_config, xpcib_read_config), - DEVMETHOD(pcib_write_config, xpcib_write_config), - DEVMETHOD(pcib_route_interrupt, xpcib_route_interrupt), - { 0, 0 } -}; - -static devclass_t xpcib_devclass; - -DEFINE_CLASS_0(pcib, xpcib_driver, xpcib_methods, sizeof(struct xpcib_softc)); -DRIVER_MODULE(pcib, xpcife, xpcib_driver, xpcib_devclass, 0, 0); - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: t - * End: - */ |