10767e98aSRoger Pau Monné /****************************************************************************** 20767e98aSRoger Pau Monné * gnttab.c 30767e98aSRoger Pau Monné * 40767e98aSRoger Pau Monné * Two sets of functionality: 50767e98aSRoger Pau Monné * 1. Granting foreign access to our memory reservation. 60767e98aSRoger Pau Monné * 2. Accessing others' memory reservations via grant references. 70767e98aSRoger Pau Monné * (i.e., mechanisms for both sender and recipient of grant references) 80767e98aSRoger Pau Monné * 90767e98aSRoger Pau Monné * Copyright (c) 2005, Christopher Clark 100767e98aSRoger Pau Monné * Copyright (c) 2004, K A Fraser 110767e98aSRoger Pau Monné */ 120767e98aSRoger Pau Monné 130767e98aSRoger Pau Monné #include <sys/cdefs.h> 140767e98aSRoger Pau Monné __FBSDID("$FreeBSD$"); 150767e98aSRoger Pau Monné 160767e98aSRoger Pau Monné #include "opt_pmap.h" 170767e98aSRoger Pau Monné 180767e98aSRoger Pau Monné #include <sys/param.h> 190767e98aSRoger Pau Monné #include <sys/systm.h> 200767e98aSRoger Pau Monné #include <sys/bus.h> 210767e98aSRoger Pau Monné #include <sys/conf.h> 220767e98aSRoger Pau Monné #include <sys/module.h> 230767e98aSRoger Pau Monné #include <sys/kernel.h> 240767e98aSRoger Pau Monné #include <sys/lock.h> 250767e98aSRoger Pau Monné #include <sys/malloc.h> 260767e98aSRoger Pau Monné #include <sys/mman.h> 270767e98aSRoger Pau Monné #include <sys/limits.h> 280767e98aSRoger Pau Monné #include <sys/rman.h> 290767e98aSRoger Pau Monné #include <machine/resource.h> 300767e98aSRoger Pau Monné 310767e98aSRoger Pau Monné #include <xen/xen-os.h> 320767e98aSRoger Pau Monné #include <xen/hypervisor.h> 330767e98aSRoger Pau Monné #include <machine/xen/synch_bitops.h> 340767e98aSRoger Pau Monné 350767e98aSRoger Pau Monné #include <xen/hypervisor.h> 360767e98aSRoger Pau Monné #include <xen/gnttab.h> 370767e98aSRoger Pau Monné 380767e98aSRoger Pau Monné #include <vm/vm.h> 390767e98aSRoger Pau Monné #include <vm/vm_kern.h> 400767e98aSRoger Pau Monné #include <vm/vm_extern.h> 410767e98aSRoger Pau Monné #include <vm/pmap.h> 420767e98aSRoger Pau Monné 430767e98aSRoger Pau Monné #define cmpxchg(a, b, c) atomic_cmpset_int((volatile u_int *)(a),(b),(c)) 440767e98aSRoger Pau Monné 450767e98aSRoger Pau Monné /* External tools reserve first few grant table entries. */ 460767e98aSRoger Pau Monné #define NR_RESERVED_ENTRIES 8 470767e98aSRoger Pau Monné #define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(grant_entry_t)) 480767e98aSRoger Pau Monné 490767e98aSRoger Pau Monné static grant_ref_t **gnttab_list; 500767e98aSRoger Pau Monné static unsigned int nr_grant_frames; 510767e98aSRoger Pau Monné static unsigned int boot_max_nr_grant_frames; 520767e98aSRoger Pau Monné static int gnttab_free_count; 530767e98aSRoger Pau Monné static grant_ref_t gnttab_free_head; 540767e98aSRoger Pau Monné static struct mtx gnttab_list_lock; 550767e98aSRoger Pau Monné 560767e98aSRoger Pau Monné #ifdef XENHVM 570767e98aSRoger Pau Monné /* 580767e98aSRoger Pau Monné * Resource representing allocated physical address space 590767e98aSRoger Pau Monné * for the grant table metainfo 600767e98aSRoger Pau Monné */ 610767e98aSRoger Pau Monné static struct resource *gnttab_pseudo_phys_res; 620767e98aSRoger Pau Monné 630767e98aSRoger Pau Monné /* Resource id for allocated physical address space. */ 640767e98aSRoger Pau Monné static int gnttab_pseudo_phys_res_id; 650767e98aSRoger Pau Monné #endif 660767e98aSRoger Pau Monné 670767e98aSRoger Pau Monné static grant_entry_t *shared; 680767e98aSRoger Pau Monné 690767e98aSRoger Pau Monné static struct gnttab_free_callback *gnttab_free_callback_list = NULL; 700767e98aSRoger Pau Monné 710767e98aSRoger Pau Monné static int gnttab_expand(unsigned int req_entries); 720767e98aSRoger Pau Monné 730767e98aSRoger Pau Monné #define RPP (PAGE_SIZE / sizeof(grant_ref_t)) 740767e98aSRoger Pau Monné #define gnttab_entry(entry) (gnttab_list[(entry) / RPP][(entry) % RPP]) 750767e98aSRoger Pau Monné 760767e98aSRoger Pau Monné static int 770767e98aSRoger Pau Monné get_free_entries(int count, int *entries) 780767e98aSRoger Pau Monné { 790767e98aSRoger Pau Monné int ref, error; 800767e98aSRoger Pau Monné grant_ref_t head; 810767e98aSRoger Pau Monné 820767e98aSRoger Pau Monné mtx_lock(&gnttab_list_lock); 830767e98aSRoger Pau Monné if ((gnttab_free_count < count) && 840767e98aSRoger Pau Monné ((error = gnttab_expand(count - gnttab_free_count)) != 0)) { 850767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 860767e98aSRoger Pau Monné return (error); 870767e98aSRoger Pau Monné } 880767e98aSRoger Pau Monné ref = head = gnttab_free_head; 890767e98aSRoger Pau Monné gnttab_free_count -= count; 900767e98aSRoger Pau Monné while (count-- > 1) 910767e98aSRoger Pau Monné head = gnttab_entry(head); 920767e98aSRoger Pau Monné gnttab_free_head = gnttab_entry(head); 930767e98aSRoger Pau Monné gnttab_entry(head) = GNTTAB_LIST_END; 940767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 950767e98aSRoger Pau Monné 960767e98aSRoger Pau Monné *entries = ref; 970767e98aSRoger Pau Monné return (0); 980767e98aSRoger Pau Monné } 990767e98aSRoger Pau Monné 1000767e98aSRoger Pau Monné static void 1010767e98aSRoger Pau Monné do_free_callbacks(void) 1020767e98aSRoger Pau Monné { 1030767e98aSRoger Pau Monné struct gnttab_free_callback *callback, *next; 1040767e98aSRoger Pau Monné 1050767e98aSRoger Pau Monné callback = gnttab_free_callback_list; 1060767e98aSRoger Pau Monné gnttab_free_callback_list = NULL; 1070767e98aSRoger Pau Monné 1080767e98aSRoger Pau Monné while (callback != NULL) { 1090767e98aSRoger Pau Monné next = callback->next; 1100767e98aSRoger Pau Monné if (gnttab_free_count >= callback->count) { 1110767e98aSRoger Pau Monné callback->next = NULL; 1120767e98aSRoger Pau Monné callback->fn(callback->arg); 1130767e98aSRoger Pau Monné } else { 1140767e98aSRoger Pau Monné callback->next = gnttab_free_callback_list; 1150767e98aSRoger Pau Monné gnttab_free_callback_list = callback; 1160767e98aSRoger Pau Monné } 1170767e98aSRoger Pau Monné callback = next; 1180767e98aSRoger Pau Monné } 1190767e98aSRoger Pau Monné } 1200767e98aSRoger Pau Monné 1210767e98aSRoger Pau Monné static inline void 1220767e98aSRoger Pau Monné check_free_callbacks(void) 1230767e98aSRoger Pau Monné { 1240767e98aSRoger Pau Monné if (__predict_false(gnttab_free_callback_list != NULL)) 1250767e98aSRoger Pau Monné do_free_callbacks(); 1260767e98aSRoger Pau Monné } 1270767e98aSRoger Pau Monné 1280767e98aSRoger Pau Monné static void 1290767e98aSRoger Pau Monné put_free_entry(grant_ref_t ref) 1300767e98aSRoger Pau Monné { 1310767e98aSRoger Pau Monné 1320767e98aSRoger Pau Monné mtx_lock(&gnttab_list_lock); 1330767e98aSRoger Pau Monné gnttab_entry(ref) = gnttab_free_head; 1340767e98aSRoger Pau Monné gnttab_free_head = ref; 1350767e98aSRoger Pau Monné gnttab_free_count++; 1360767e98aSRoger Pau Monné check_free_callbacks(); 1370767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 1380767e98aSRoger Pau Monné } 1390767e98aSRoger Pau Monné 1400767e98aSRoger Pau Monné /* 1410767e98aSRoger Pau Monné * Public grant-issuing interface functions 1420767e98aSRoger Pau Monné */ 1430767e98aSRoger Pau Monné 1440767e98aSRoger Pau Monné int 1450767e98aSRoger Pau Monné gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly, 1460767e98aSRoger Pau Monné grant_ref_t *result) 1470767e98aSRoger Pau Monné { 1480767e98aSRoger Pau Monné int error, ref; 1490767e98aSRoger Pau Monné 1500767e98aSRoger Pau Monné error = get_free_entries(1, &ref); 1510767e98aSRoger Pau Monné 1520767e98aSRoger Pau Monné if (__predict_false(error)) 1530767e98aSRoger Pau Monné return (error); 1540767e98aSRoger Pau Monné 1550767e98aSRoger Pau Monné shared[ref].frame = frame; 1560767e98aSRoger Pau Monné shared[ref].domid = domid; 1570767e98aSRoger Pau Monné wmb(); 1580767e98aSRoger Pau Monné shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); 1590767e98aSRoger Pau Monné 1600767e98aSRoger Pau Monné if (result) 1610767e98aSRoger Pau Monné *result = ref; 1620767e98aSRoger Pau Monné 1630767e98aSRoger Pau Monné return (0); 1640767e98aSRoger Pau Monné } 1650767e98aSRoger Pau Monné 1660767e98aSRoger Pau Monné void 1670767e98aSRoger Pau Monné gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, 1680767e98aSRoger Pau Monné unsigned long frame, int readonly) 1690767e98aSRoger Pau Monné { 1700767e98aSRoger Pau Monné 1710767e98aSRoger Pau Monné shared[ref].frame = frame; 1720767e98aSRoger Pau Monné shared[ref].domid = domid; 1730767e98aSRoger Pau Monné wmb(); 1740767e98aSRoger Pau Monné shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); 1750767e98aSRoger Pau Monné } 1760767e98aSRoger Pau Monné 1770767e98aSRoger Pau Monné int 1780767e98aSRoger Pau Monné gnttab_query_foreign_access(grant_ref_t ref) 1790767e98aSRoger Pau Monné { 1800767e98aSRoger Pau Monné uint16_t nflags; 1810767e98aSRoger Pau Monné 1820767e98aSRoger Pau Monné nflags = shared[ref].flags; 1830767e98aSRoger Pau Monné 1840767e98aSRoger Pau Monné return (nflags & (GTF_reading|GTF_writing)); 1850767e98aSRoger Pau Monné } 1860767e98aSRoger Pau Monné 1870767e98aSRoger Pau Monné int 1880767e98aSRoger Pau Monné gnttab_end_foreign_access_ref(grant_ref_t ref) 1890767e98aSRoger Pau Monné { 1900767e98aSRoger Pau Monné uint16_t flags, nflags; 1910767e98aSRoger Pau Monné 1920767e98aSRoger Pau Monné nflags = shared[ref].flags; 1930767e98aSRoger Pau Monné do { 1940767e98aSRoger Pau Monné if ( (flags = nflags) & (GTF_reading|GTF_writing) ) { 1950767e98aSRoger Pau Monné printf("%s: WARNING: g.e. still in use!\n", __func__); 1960767e98aSRoger Pau Monné return (0); 1970767e98aSRoger Pau Monné } 1980767e98aSRoger Pau Monné } while ((nflags = synch_cmpxchg(&shared[ref].flags, flags, 0)) != 1990767e98aSRoger Pau Monné flags); 2000767e98aSRoger Pau Monné 2010767e98aSRoger Pau Monné return (1); 2020767e98aSRoger Pau Monné } 2030767e98aSRoger Pau Monné 2040767e98aSRoger Pau Monné void 2050767e98aSRoger Pau Monné gnttab_end_foreign_access(grant_ref_t ref, void *page) 2060767e98aSRoger Pau Monné { 2070767e98aSRoger Pau Monné if (gnttab_end_foreign_access_ref(ref)) { 2080767e98aSRoger Pau Monné put_free_entry(ref); 2090767e98aSRoger Pau Monné if (page != NULL) { 2100767e98aSRoger Pau Monné free(page, M_DEVBUF); 2110767e98aSRoger Pau Monné } 2120767e98aSRoger Pau Monné } 2130767e98aSRoger Pau Monné else { 2140767e98aSRoger Pau Monné /* XXX This needs to be fixed so that the ref and page are 2150767e98aSRoger Pau Monné placed on a list to be freed up later. */ 2160767e98aSRoger Pau Monné printf("%s: WARNING: leaking g.e. and page still in use!\n", 2170767e98aSRoger Pau Monné __func__); 2180767e98aSRoger Pau Monné } 2190767e98aSRoger Pau Monné } 2200767e98aSRoger Pau Monné 2210767e98aSRoger Pau Monné void 2220767e98aSRoger Pau Monné gnttab_end_foreign_access_references(u_int count, grant_ref_t *refs) 2230767e98aSRoger Pau Monné { 2240767e98aSRoger Pau Monné grant_ref_t *last_ref; 2250767e98aSRoger Pau Monné grant_ref_t head; 2260767e98aSRoger Pau Monné grant_ref_t tail; 2270767e98aSRoger Pau Monné 2280767e98aSRoger Pau Monné head = GNTTAB_LIST_END; 2290767e98aSRoger Pau Monné tail = *refs; 2300767e98aSRoger Pau Monné last_ref = refs + count; 2310767e98aSRoger Pau Monné while (refs != last_ref) { 2320767e98aSRoger Pau Monné 2330767e98aSRoger Pau Monné if (gnttab_end_foreign_access_ref(*refs)) { 2340767e98aSRoger Pau Monné gnttab_entry(*refs) = head; 2350767e98aSRoger Pau Monné head = *refs; 2360767e98aSRoger Pau Monné } else { 2370767e98aSRoger Pau Monné /* 2380767e98aSRoger Pau Monné * XXX This needs to be fixed so that the ref 2390767e98aSRoger Pau Monné * is placed on a list to be freed up later. 2400767e98aSRoger Pau Monné */ 2410767e98aSRoger Pau Monné printf("%s: WARNING: leaking g.e. still in use!\n", 2420767e98aSRoger Pau Monné __func__); 2430767e98aSRoger Pau Monné count--; 2440767e98aSRoger Pau Monné } 2450767e98aSRoger Pau Monné refs++; 2460767e98aSRoger Pau Monné } 2470767e98aSRoger Pau Monné 2480767e98aSRoger Pau Monné if (count != 0) { 2490767e98aSRoger Pau Monné mtx_lock(&gnttab_list_lock); 2500767e98aSRoger Pau Monné gnttab_free_count += count; 2510767e98aSRoger Pau Monné gnttab_entry(tail) = gnttab_free_head; 2520767e98aSRoger Pau Monné gnttab_free_head = head; 2530767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 2540767e98aSRoger Pau Monné } 2550767e98aSRoger Pau Monné } 2560767e98aSRoger Pau Monné 2570767e98aSRoger Pau Monné int 2580767e98aSRoger Pau Monné gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn, 2590767e98aSRoger Pau Monné grant_ref_t *result) 2600767e98aSRoger Pau Monné { 2610767e98aSRoger Pau Monné int error, ref; 2620767e98aSRoger Pau Monné 2630767e98aSRoger Pau Monné error = get_free_entries(1, &ref); 2640767e98aSRoger Pau Monné if (__predict_false(error)) 2650767e98aSRoger Pau Monné return (error); 2660767e98aSRoger Pau Monné 2670767e98aSRoger Pau Monné gnttab_grant_foreign_transfer_ref(ref, domid, pfn); 2680767e98aSRoger Pau Monné 2690767e98aSRoger Pau Monné *result = ref; 2700767e98aSRoger Pau Monné return (0); 2710767e98aSRoger Pau Monné } 2720767e98aSRoger Pau Monné 2730767e98aSRoger Pau Monné void 2740767e98aSRoger Pau Monné gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, 2750767e98aSRoger Pau Monné unsigned long pfn) 2760767e98aSRoger Pau Monné { 2770767e98aSRoger Pau Monné shared[ref].frame = pfn; 2780767e98aSRoger Pau Monné shared[ref].domid = domid; 2790767e98aSRoger Pau Monné wmb(); 2800767e98aSRoger Pau Monné shared[ref].flags = GTF_accept_transfer; 2810767e98aSRoger Pau Monné } 2820767e98aSRoger Pau Monné 2830767e98aSRoger Pau Monné unsigned long 2840767e98aSRoger Pau Monné gnttab_end_foreign_transfer_ref(grant_ref_t ref) 2850767e98aSRoger Pau Monné { 2860767e98aSRoger Pau Monné unsigned long frame; 2870767e98aSRoger Pau Monné uint16_t flags; 2880767e98aSRoger Pau Monné 2890767e98aSRoger Pau Monné /* 2900767e98aSRoger Pau Monné * If a transfer is not even yet started, try to reclaim the grant 2910767e98aSRoger Pau Monné * reference and return failure (== 0). 2920767e98aSRoger Pau Monné */ 2930767e98aSRoger Pau Monné while (!((flags = shared[ref].flags) & GTF_transfer_committed)) { 2940767e98aSRoger Pau Monné if ( synch_cmpxchg(&shared[ref].flags, flags, 0) == flags ) 2950767e98aSRoger Pau Monné return (0); 2960767e98aSRoger Pau Monné cpu_relax(); 2970767e98aSRoger Pau Monné } 2980767e98aSRoger Pau Monné 2990767e98aSRoger Pau Monné /* If a transfer is in progress then wait until it is completed. */ 3000767e98aSRoger Pau Monné while (!(flags & GTF_transfer_completed)) { 3010767e98aSRoger Pau Monné flags = shared[ref].flags; 3020767e98aSRoger Pau Monné cpu_relax(); 3030767e98aSRoger Pau Monné } 3040767e98aSRoger Pau Monné 3050767e98aSRoger Pau Monné /* Read the frame number /after/ reading completion status. */ 3060767e98aSRoger Pau Monné rmb(); 3070767e98aSRoger Pau Monné frame = shared[ref].frame; 3080767e98aSRoger Pau Monné KASSERT(frame != 0, ("grant table inconsistent")); 3090767e98aSRoger Pau Monné 3100767e98aSRoger Pau Monné return (frame); 3110767e98aSRoger Pau Monné } 3120767e98aSRoger Pau Monné 3130767e98aSRoger Pau Monné unsigned long 3140767e98aSRoger Pau Monné gnttab_end_foreign_transfer(grant_ref_t ref) 3150767e98aSRoger Pau Monné { 3160767e98aSRoger Pau Monné unsigned long frame = gnttab_end_foreign_transfer_ref(ref); 3170767e98aSRoger Pau Monné 3180767e98aSRoger Pau Monné put_free_entry(ref); 3190767e98aSRoger Pau Monné return (frame); 3200767e98aSRoger Pau Monné } 3210767e98aSRoger Pau Monné 3220767e98aSRoger Pau Monné void 3230767e98aSRoger Pau Monné gnttab_free_grant_reference(grant_ref_t ref) 3240767e98aSRoger Pau Monné { 3250767e98aSRoger Pau Monné 3260767e98aSRoger Pau Monné put_free_entry(ref); 3270767e98aSRoger Pau Monné } 3280767e98aSRoger Pau Monné 3290767e98aSRoger Pau Monné void 3300767e98aSRoger Pau Monné gnttab_free_grant_references(grant_ref_t head) 3310767e98aSRoger Pau Monné { 3320767e98aSRoger Pau Monné grant_ref_t ref; 3330767e98aSRoger Pau Monné int count = 1; 3340767e98aSRoger Pau Monné 3350767e98aSRoger Pau Monné if (head == GNTTAB_LIST_END) 3360767e98aSRoger Pau Monné return; 3370767e98aSRoger Pau Monné 3380767e98aSRoger Pau Monné ref = head; 3390767e98aSRoger Pau Monné while (gnttab_entry(ref) != GNTTAB_LIST_END) { 3400767e98aSRoger Pau Monné ref = gnttab_entry(ref); 3410767e98aSRoger Pau Monné count++; 3420767e98aSRoger Pau Monné } 3430767e98aSRoger Pau Monné mtx_lock(&gnttab_list_lock); 3440767e98aSRoger Pau Monné gnttab_entry(ref) = gnttab_free_head; 3450767e98aSRoger Pau Monné gnttab_free_head = head; 3460767e98aSRoger Pau Monné gnttab_free_count += count; 3470767e98aSRoger Pau Monné check_free_callbacks(); 3480767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 3490767e98aSRoger Pau Monné } 3500767e98aSRoger Pau Monné 3510767e98aSRoger Pau Monné int 3520767e98aSRoger Pau Monné gnttab_alloc_grant_references(uint16_t count, grant_ref_t *head) 3530767e98aSRoger Pau Monné { 3540767e98aSRoger Pau Monné int ref, error; 3550767e98aSRoger Pau Monné 3560767e98aSRoger Pau Monné error = get_free_entries(count, &ref); 3570767e98aSRoger Pau Monné if (__predict_false(error)) 3580767e98aSRoger Pau Monné return (error); 3590767e98aSRoger Pau Monné 3600767e98aSRoger Pau Monné *head = ref; 3610767e98aSRoger Pau Monné return (0); 3620767e98aSRoger Pau Monné } 3630767e98aSRoger Pau Monné 3640767e98aSRoger Pau Monné int 3650767e98aSRoger Pau Monné gnttab_empty_grant_references(const grant_ref_t *private_head) 3660767e98aSRoger Pau Monné { 3670767e98aSRoger Pau Monné 3680767e98aSRoger Pau Monné return (*private_head == GNTTAB_LIST_END); 3690767e98aSRoger Pau Monné } 3700767e98aSRoger Pau Monné 3710767e98aSRoger Pau Monné int 3720767e98aSRoger Pau Monné gnttab_claim_grant_reference(grant_ref_t *private_head) 3730767e98aSRoger Pau Monné { 3740767e98aSRoger Pau Monné grant_ref_t g = *private_head; 3750767e98aSRoger Pau Monné 3760767e98aSRoger Pau Monné if (__predict_false(g == GNTTAB_LIST_END)) 3770767e98aSRoger Pau Monné return (g); 3780767e98aSRoger Pau Monné *private_head = gnttab_entry(g); 3790767e98aSRoger Pau Monné return (g); 3800767e98aSRoger Pau Monné } 3810767e98aSRoger Pau Monné 3820767e98aSRoger Pau Monné void 3830767e98aSRoger Pau Monné gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release) 3840767e98aSRoger Pau Monné { 3850767e98aSRoger Pau Monné 3860767e98aSRoger Pau Monné gnttab_entry(release) = *private_head; 3870767e98aSRoger Pau Monné *private_head = release; 3880767e98aSRoger Pau Monné } 3890767e98aSRoger Pau Monné 3900767e98aSRoger Pau Monné void 3910767e98aSRoger Pau Monné gnttab_request_free_callback(struct gnttab_free_callback *callback, 3920767e98aSRoger Pau Monné void (*fn)(void *), void *arg, uint16_t count) 3930767e98aSRoger Pau Monné { 3940767e98aSRoger Pau Monné 3950767e98aSRoger Pau Monné mtx_lock(&gnttab_list_lock); 3960767e98aSRoger Pau Monné if (callback->next) 3970767e98aSRoger Pau Monné goto out; 3980767e98aSRoger Pau Monné callback->fn = fn; 3990767e98aSRoger Pau Monné callback->arg = arg; 4000767e98aSRoger Pau Monné callback->count = count; 4010767e98aSRoger Pau Monné callback->next = gnttab_free_callback_list; 4020767e98aSRoger Pau Monné gnttab_free_callback_list = callback; 4030767e98aSRoger Pau Monné check_free_callbacks(); 4040767e98aSRoger Pau Monné out: 4050767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 4060767e98aSRoger Pau Monné 4070767e98aSRoger Pau Monné } 4080767e98aSRoger Pau Monné 4090767e98aSRoger Pau Monné void 4100767e98aSRoger Pau Monné gnttab_cancel_free_callback(struct gnttab_free_callback *callback) 4110767e98aSRoger Pau Monné { 4120767e98aSRoger Pau Monné struct gnttab_free_callback **pcb; 4130767e98aSRoger Pau Monné 4140767e98aSRoger Pau Monné mtx_lock(&gnttab_list_lock); 4150767e98aSRoger Pau Monné for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) { 4160767e98aSRoger Pau Monné if (*pcb == callback) { 4170767e98aSRoger Pau Monné *pcb = callback->next; 4180767e98aSRoger Pau Monné break; 4190767e98aSRoger Pau Monné } 4200767e98aSRoger Pau Monné } 4210767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 4220767e98aSRoger Pau Monné } 4230767e98aSRoger Pau Monné 4240767e98aSRoger Pau Monné 4250767e98aSRoger Pau Monné static int 4260767e98aSRoger Pau Monné grow_gnttab_list(unsigned int more_frames) 4270767e98aSRoger Pau Monné { 4280767e98aSRoger Pau Monné unsigned int new_nr_grant_frames, extra_entries, i; 4290767e98aSRoger Pau Monné 4300767e98aSRoger Pau Monné new_nr_grant_frames = nr_grant_frames + more_frames; 4310767e98aSRoger Pau Monné extra_entries = more_frames * GREFS_PER_GRANT_FRAME; 4320767e98aSRoger Pau Monné 4330767e98aSRoger Pau Monné for (i = nr_grant_frames; i < new_nr_grant_frames; i++) 4340767e98aSRoger Pau Monné { 4350767e98aSRoger Pau Monné gnttab_list[i] = (grant_ref_t *) 4360767e98aSRoger Pau Monné malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); 4370767e98aSRoger Pau Monné 4380767e98aSRoger Pau Monné if (!gnttab_list[i]) 4390767e98aSRoger Pau Monné goto grow_nomem; 4400767e98aSRoger Pau Monné } 4410767e98aSRoger Pau Monné 4420767e98aSRoger Pau Monné for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames; 4430767e98aSRoger Pau Monné i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++) 4440767e98aSRoger Pau Monné gnttab_entry(i) = i + 1; 4450767e98aSRoger Pau Monné 4460767e98aSRoger Pau Monné gnttab_entry(i) = gnttab_free_head; 4470767e98aSRoger Pau Monné gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames; 4480767e98aSRoger Pau Monné gnttab_free_count += extra_entries; 4490767e98aSRoger Pau Monné 4500767e98aSRoger Pau Monné nr_grant_frames = new_nr_grant_frames; 4510767e98aSRoger Pau Monné 4520767e98aSRoger Pau Monné check_free_callbacks(); 4530767e98aSRoger Pau Monné 4540767e98aSRoger Pau Monné return (0); 4550767e98aSRoger Pau Monné 4560767e98aSRoger Pau Monné grow_nomem: 4570767e98aSRoger Pau Monné for ( ; i >= nr_grant_frames; i--) 4580767e98aSRoger Pau Monné free(gnttab_list[i], M_DEVBUF); 4590767e98aSRoger Pau Monné return (ENOMEM); 4600767e98aSRoger Pau Monné } 4610767e98aSRoger Pau Monné 4620767e98aSRoger Pau Monné static unsigned int 4630767e98aSRoger Pau Monné __max_nr_grant_frames(void) 4640767e98aSRoger Pau Monné { 4650767e98aSRoger Pau Monné struct gnttab_query_size query; 4660767e98aSRoger Pau Monné int rc; 4670767e98aSRoger Pau Monné 4680767e98aSRoger Pau Monné query.dom = DOMID_SELF; 4690767e98aSRoger Pau Monné 4700767e98aSRoger Pau Monné rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1); 4710767e98aSRoger Pau Monné if ((rc < 0) || (query.status != GNTST_okay)) 4720767e98aSRoger Pau Monné return (4); /* Legacy max supported number of frames */ 4730767e98aSRoger Pau Monné 4740767e98aSRoger Pau Monné return (query.max_nr_frames); 4750767e98aSRoger Pau Monné } 4760767e98aSRoger Pau Monné 4770767e98aSRoger Pau Monné static inline 4780767e98aSRoger Pau Monné unsigned int max_nr_grant_frames(void) 4790767e98aSRoger Pau Monné { 4800767e98aSRoger Pau Monné unsigned int xen_max = __max_nr_grant_frames(); 4810767e98aSRoger Pau Monné 4820767e98aSRoger Pau Monné if (xen_max > boot_max_nr_grant_frames) 4830767e98aSRoger Pau Monné return (boot_max_nr_grant_frames); 4840767e98aSRoger Pau Monné return (xen_max); 4850767e98aSRoger Pau Monné } 4860767e98aSRoger Pau Monné 4870767e98aSRoger Pau Monné #ifdef notyet 4880767e98aSRoger Pau Monné /* 4890767e98aSRoger Pau Monné * XXX needed for backend support 4900767e98aSRoger Pau Monné * 4910767e98aSRoger Pau Monné */ 4920767e98aSRoger Pau Monné static int 4930767e98aSRoger Pau Monné map_pte_fn(pte_t *pte, struct page *pmd_page, 4940767e98aSRoger Pau Monné unsigned long addr, void *data) 4950767e98aSRoger Pau Monné { 4960767e98aSRoger Pau Monné unsigned long **frames = (unsigned long **)data; 4970767e98aSRoger Pau Monné 4980767e98aSRoger Pau Monné set_pte_at(&init_mm, addr, pte, pfn_pte_ma((*frames)[0], PAGE_KERNEL)); 4990767e98aSRoger Pau Monné (*frames)++; 5000767e98aSRoger Pau Monné return 0; 5010767e98aSRoger Pau Monné } 5020767e98aSRoger Pau Monné 5030767e98aSRoger Pau Monné static int 5040767e98aSRoger Pau Monné unmap_pte_fn(pte_t *pte, struct page *pmd_page, 5050767e98aSRoger Pau Monné unsigned long addr, void *data) 5060767e98aSRoger Pau Monné { 5070767e98aSRoger Pau Monné 5080767e98aSRoger Pau Monné set_pte_at(&init_mm, addr, pte, __pte(0)); 5090767e98aSRoger Pau Monné return 0; 5100767e98aSRoger Pau Monné } 5110767e98aSRoger Pau Monné #endif 5120767e98aSRoger Pau Monné 5130767e98aSRoger Pau Monné #ifndef XENHVM 5140767e98aSRoger Pau Monné 5150767e98aSRoger Pau Monné static int 5160767e98aSRoger Pau Monné gnttab_map(unsigned int start_idx, unsigned int end_idx) 5170767e98aSRoger Pau Monné { 5180767e98aSRoger Pau Monné struct gnttab_setup_table setup; 5190767e98aSRoger Pau Monné u_long *frames; 5200767e98aSRoger Pau Monné 5210767e98aSRoger Pau Monné unsigned int nr_gframes = end_idx + 1; 5220767e98aSRoger Pau Monné int i, rc; 5230767e98aSRoger Pau Monné 5240767e98aSRoger Pau Monné frames = malloc(nr_gframes * sizeof(unsigned long), M_DEVBUF, M_NOWAIT); 5250767e98aSRoger Pau Monné if (!frames) 5260767e98aSRoger Pau Monné return (ENOMEM); 5270767e98aSRoger Pau Monné 5280767e98aSRoger Pau Monné setup.dom = DOMID_SELF; 5290767e98aSRoger Pau Monné setup.nr_frames = nr_gframes; 5300767e98aSRoger Pau Monné set_xen_guest_handle(setup.frame_list, frames); 5310767e98aSRoger Pau Monné 5320767e98aSRoger Pau Monné rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); 5330767e98aSRoger Pau Monné if (rc == -ENOSYS) { 5340767e98aSRoger Pau Monné free(frames, M_DEVBUF); 5350767e98aSRoger Pau Monné return (ENOSYS); 5360767e98aSRoger Pau Monné } 5370767e98aSRoger Pau Monné KASSERT(!(rc || setup.status), 5380767e98aSRoger Pau Monné ("unexpected result from grant_table_op")); 5390767e98aSRoger Pau Monné 5400767e98aSRoger Pau Monné if (shared == NULL) { 5410767e98aSRoger Pau Monné vm_offset_t area; 5420767e98aSRoger Pau Monné 5430767e98aSRoger Pau Monné area = kva_alloc(PAGE_SIZE * max_nr_grant_frames()); 5440767e98aSRoger Pau Monné KASSERT(area, ("can't allocate VM space for grant table")); 5450767e98aSRoger Pau Monné shared = (grant_entry_t *)area; 5460767e98aSRoger Pau Monné } 5470767e98aSRoger Pau Monné 5480767e98aSRoger Pau Monné for (i = 0; i < nr_gframes; i++) 5490767e98aSRoger Pau Monné PT_SET_MA(((caddr_t)shared) + i*PAGE_SIZE, 5500767e98aSRoger Pau Monné ((vm_paddr_t)frames[i]) << PAGE_SHIFT | PG_RW | PG_V); 5510767e98aSRoger Pau Monné 5520767e98aSRoger Pau Monné free(frames, M_DEVBUF); 5530767e98aSRoger Pau Monné 5540767e98aSRoger Pau Monné return (0); 5550767e98aSRoger Pau Monné } 5560767e98aSRoger Pau Monné 5570767e98aSRoger Pau Monné int 5580767e98aSRoger Pau Monné gnttab_resume(device_t dev) 5590767e98aSRoger Pau Monné { 5600767e98aSRoger Pau Monné 5610767e98aSRoger Pau Monné if (max_nr_grant_frames() < nr_grant_frames) 5620767e98aSRoger Pau Monné return (ENOSYS); 5630767e98aSRoger Pau Monné return (gnttab_map(0, nr_grant_frames - 1)); 5640767e98aSRoger Pau Monné } 5650767e98aSRoger Pau Monné 5660767e98aSRoger Pau Monné int 5670767e98aSRoger Pau Monné gnttab_suspend(void) 5680767e98aSRoger Pau Monné { 5690767e98aSRoger Pau Monné int i; 5700767e98aSRoger Pau Monné 5710767e98aSRoger Pau Monné for (i = 0; i < nr_grant_frames; i++) 5720767e98aSRoger Pau Monné pmap_kremove((vm_offset_t) shared + i * PAGE_SIZE); 5730767e98aSRoger Pau Monné 5740767e98aSRoger Pau Monné return (0); 5750767e98aSRoger Pau Monné } 5760767e98aSRoger Pau Monné 5770767e98aSRoger Pau Monné #else /* XENHVM */ 5780767e98aSRoger Pau Monné 5790767e98aSRoger Pau Monné static vm_paddr_t resume_frames; 5800767e98aSRoger Pau Monné 5810767e98aSRoger Pau Monné static int 5820767e98aSRoger Pau Monné gnttab_map(unsigned int start_idx, unsigned int end_idx) 5830767e98aSRoger Pau Monné { 5840767e98aSRoger Pau Monné struct xen_add_to_physmap xatp; 5850767e98aSRoger Pau Monné unsigned int i = end_idx; 5860767e98aSRoger Pau Monné 5870767e98aSRoger Pau Monné /* 5880767e98aSRoger Pau Monné * Loop backwards, so that the first hypercall has the largest index, 5890767e98aSRoger Pau Monné * ensuring that the table will grow only once. 5900767e98aSRoger Pau Monné */ 5910767e98aSRoger Pau Monné do { 5920767e98aSRoger Pau Monné xatp.domid = DOMID_SELF; 5930767e98aSRoger Pau Monné xatp.idx = i; 5940767e98aSRoger Pau Monné xatp.space = XENMAPSPACE_grant_table; 5950767e98aSRoger Pau Monné xatp.gpfn = (resume_frames >> PAGE_SHIFT) + i; 5960767e98aSRoger Pau Monné if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) 5970767e98aSRoger Pau Monné panic("HYPERVISOR_memory_op failed to map gnttab"); 5980767e98aSRoger Pau Monné } while (i-- > start_idx); 5990767e98aSRoger Pau Monné 6000767e98aSRoger Pau Monné if (shared == NULL) { 6010767e98aSRoger Pau Monné vm_offset_t area; 6020767e98aSRoger Pau Monné 6030767e98aSRoger Pau Monné area = kva_alloc(PAGE_SIZE * max_nr_grant_frames()); 6040767e98aSRoger Pau Monné KASSERT(area, ("can't allocate VM space for grant table")); 6050767e98aSRoger Pau Monné shared = (grant_entry_t *)area; 6060767e98aSRoger Pau Monné } 6070767e98aSRoger Pau Monné 6080767e98aSRoger Pau Monné for (i = start_idx; i <= end_idx; i++) { 6090767e98aSRoger Pau Monné pmap_kenter((vm_offset_t) shared + i * PAGE_SIZE, 6100767e98aSRoger Pau Monné resume_frames + i * PAGE_SIZE); 6110767e98aSRoger Pau Monné } 6120767e98aSRoger Pau Monné 6130767e98aSRoger Pau Monné return (0); 6140767e98aSRoger Pau Monné } 6150767e98aSRoger Pau Monné 6160767e98aSRoger Pau Monné int 6170767e98aSRoger Pau Monné gnttab_resume(device_t dev) 6180767e98aSRoger Pau Monné { 6190767e98aSRoger Pau Monné unsigned int max_nr_gframes, nr_gframes; 6200767e98aSRoger Pau Monné 6210767e98aSRoger Pau Monné nr_gframes = nr_grant_frames; 6220767e98aSRoger Pau Monné max_nr_gframes = max_nr_grant_frames(); 6230767e98aSRoger Pau Monné if (max_nr_gframes < nr_gframes) 6240767e98aSRoger Pau Monné return (ENOSYS); 6250767e98aSRoger Pau Monné 6260767e98aSRoger Pau Monné if (!resume_frames) { 6270767e98aSRoger Pau Monné KASSERT(dev != NULL, 6280767e98aSRoger Pau Monné ("No resume frames and no device provided")); 6290767e98aSRoger Pau Monné 6300767e98aSRoger Pau Monné gnttab_pseudo_phys_res = bus_alloc_resource(dev, 6310767e98aSRoger Pau Monné SYS_RES_MEMORY, &gnttab_pseudo_phys_res_id, 0, ~0, 6320767e98aSRoger Pau Monné PAGE_SIZE * max_nr_gframes, RF_ACTIVE); 6330767e98aSRoger Pau Monné if (gnttab_pseudo_phys_res == NULL) 6340767e98aSRoger Pau Monné panic("Unable to reserve physical memory for gnttab"); 6350767e98aSRoger Pau Monné resume_frames = rman_get_start(gnttab_pseudo_phys_res); 6360767e98aSRoger Pau Monné } 6370767e98aSRoger Pau Monné 6380767e98aSRoger Pau Monné return (gnttab_map(0, nr_gframes - 1)); 6390767e98aSRoger Pau Monné } 6400767e98aSRoger Pau Monné 6410767e98aSRoger Pau Monné #endif 6420767e98aSRoger Pau Monné 6430767e98aSRoger Pau Monné static int 6440767e98aSRoger Pau Monné gnttab_expand(unsigned int req_entries) 6450767e98aSRoger Pau Monné { 6460767e98aSRoger Pau Monné int error; 6470767e98aSRoger Pau Monné unsigned int cur, extra; 6480767e98aSRoger Pau Monné 6490767e98aSRoger Pau Monné cur = nr_grant_frames; 6500767e98aSRoger Pau Monné extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) / 6510767e98aSRoger Pau Monné GREFS_PER_GRANT_FRAME); 6520767e98aSRoger Pau Monné if (cur + extra > max_nr_grant_frames()) 6530767e98aSRoger Pau Monné return (ENOSPC); 6540767e98aSRoger Pau Monné 6550767e98aSRoger Pau Monné error = gnttab_map(cur, cur + extra - 1); 6560767e98aSRoger Pau Monné if (!error) 6570767e98aSRoger Pau Monné error = grow_gnttab_list(extra); 6580767e98aSRoger Pau Monné 6590767e98aSRoger Pau Monné return (error); 6600767e98aSRoger Pau Monné } 6610767e98aSRoger Pau Monné 662*1093cd82SRoger Pau Monné MTX_SYSINIT(gnttab, &gnttab_list_lock, "GNTTAB LOCK", MTX_DEF); 663*1093cd82SRoger Pau Monné 664*1093cd82SRoger Pau Monné /*------------------ Private Device Attachment Functions --------------------*/ 665*1093cd82SRoger Pau Monné /** 666*1093cd82SRoger Pau Monné * \brief Identify instances of this device type in the system. 667*1093cd82SRoger Pau Monné * 668*1093cd82SRoger Pau Monné * \param driver The driver performing this identify action. 669*1093cd82SRoger Pau Monné * \param parent The NewBus parent device for any devices this method adds. 670*1093cd82SRoger Pau Monné */ 671*1093cd82SRoger Pau Monné static void 672*1093cd82SRoger Pau Monné granttable_identify(driver_t *driver __unused, device_t parent) 673*1093cd82SRoger Pau Monné { 674*1093cd82SRoger Pau Monné 675*1093cd82SRoger Pau Monné KASSERT(xen_domain(), 676*1093cd82SRoger Pau Monné ("Trying to attach grant-table device on non Xen domain")); 677*1093cd82SRoger Pau Monné /* 678*1093cd82SRoger Pau Monné * A single device instance for our driver is always present 679*1093cd82SRoger Pau Monné * in a system operating under Xen. 680*1093cd82SRoger Pau Monné */ 681*1093cd82SRoger Pau Monné if (BUS_ADD_CHILD(parent, 0, driver->name, 0) == NULL) 682*1093cd82SRoger Pau Monné panic("unable to attach Xen Grant-table device"); 683*1093cd82SRoger Pau Monné } 684*1093cd82SRoger Pau Monné 685*1093cd82SRoger Pau Monné /** 686*1093cd82SRoger Pau Monné * \brief Probe for the existence of the Xen Grant-table device 687*1093cd82SRoger Pau Monné * 688*1093cd82SRoger Pau Monné * \param dev NewBus device_t for this instance. 689*1093cd82SRoger Pau Monné * 690*1093cd82SRoger Pau Monné * \return Always returns 0 indicating success. 691*1093cd82SRoger Pau Monné */ 692*1093cd82SRoger Pau Monné static int 693*1093cd82SRoger Pau Monné granttable_probe(device_t dev) 694*1093cd82SRoger Pau Monné { 695*1093cd82SRoger Pau Monné 696*1093cd82SRoger Pau Monné device_set_desc(dev, "Xen Grant-table Device"); 697*1093cd82SRoger Pau Monné return (BUS_PROBE_NOWILDCARD); 698*1093cd82SRoger Pau Monné } 699*1093cd82SRoger Pau Monné 700*1093cd82SRoger Pau Monné /** 701*1093cd82SRoger Pau Monné * \brief Attach the Xen Grant-table device. 702*1093cd82SRoger Pau Monné * 703*1093cd82SRoger Pau Monné * \param dev NewBus device_t for this instance. 704*1093cd82SRoger Pau Monné * 705*1093cd82SRoger Pau Monné * \return On success, 0. Otherwise an errno value indicating the 706*1093cd82SRoger Pau Monné * type of failure. 707*1093cd82SRoger Pau Monné */ 708*1093cd82SRoger Pau Monné static int 709*1093cd82SRoger Pau Monné granttable_attach(device_t dev) 7100767e98aSRoger Pau Monné { 7110767e98aSRoger Pau Monné int i; 7120767e98aSRoger Pau Monné unsigned int max_nr_glist_frames; 7130767e98aSRoger Pau Monné unsigned int nr_init_grefs; 7140767e98aSRoger Pau Monné 7150767e98aSRoger Pau Monné nr_grant_frames = 1; 7160767e98aSRoger Pau Monné boot_max_nr_grant_frames = __max_nr_grant_frames(); 7170767e98aSRoger Pau Monné 7180767e98aSRoger Pau Monné /* Determine the maximum number of frames required for the 7190767e98aSRoger Pau Monné * grant reference free list on the current hypervisor. 7200767e98aSRoger Pau Monné */ 7210767e98aSRoger Pau Monné max_nr_glist_frames = (boot_max_nr_grant_frames * 7220767e98aSRoger Pau Monné GREFS_PER_GRANT_FRAME / 7230767e98aSRoger Pau Monné (PAGE_SIZE / sizeof(grant_ref_t))); 7240767e98aSRoger Pau Monné 7250767e98aSRoger Pau Monné gnttab_list = malloc(max_nr_glist_frames * sizeof(grant_ref_t *), 7260767e98aSRoger Pau Monné M_DEVBUF, M_NOWAIT); 7270767e98aSRoger Pau Monné 7280767e98aSRoger Pau Monné if (gnttab_list == NULL) 7290767e98aSRoger Pau Monné return (ENOMEM); 7300767e98aSRoger Pau Monné 7310767e98aSRoger Pau Monné for (i = 0; i < nr_grant_frames; i++) { 7320767e98aSRoger Pau Monné gnttab_list[i] = (grant_ref_t *) 7330767e98aSRoger Pau Monné malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); 7340767e98aSRoger Pau Monné if (gnttab_list[i] == NULL) 7350767e98aSRoger Pau Monné goto ini_nomem; 7360767e98aSRoger Pau Monné } 7370767e98aSRoger Pau Monné 7380767e98aSRoger Pau Monné if (gnttab_resume(dev)) 7390767e98aSRoger Pau Monné return (ENODEV); 7400767e98aSRoger Pau Monné 7410767e98aSRoger Pau Monné nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME; 7420767e98aSRoger Pau Monné 7430767e98aSRoger Pau Monné for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++) 7440767e98aSRoger Pau Monné gnttab_entry(i) = i + 1; 7450767e98aSRoger Pau Monné 7460767e98aSRoger Pau Monné gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END; 7470767e98aSRoger Pau Monné gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES; 7480767e98aSRoger Pau Monné gnttab_free_head = NR_RESERVED_ENTRIES; 7490767e98aSRoger Pau Monné 7500767e98aSRoger Pau Monné if (bootverbose) 7510767e98aSRoger Pau Monné printf("Grant table initialized\n"); 7520767e98aSRoger Pau Monné 7530767e98aSRoger Pau Monné return (0); 7540767e98aSRoger Pau Monné 7550767e98aSRoger Pau Monné ini_nomem: 7560767e98aSRoger Pau Monné for (i--; i >= 0; i--) 7570767e98aSRoger Pau Monné free(gnttab_list[i], M_DEVBUF); 7580767e98aSRoger Pau Monné free(gnttab_list, M_DEVBUF); 7590767e98aSRoger Pau Monné return (ENOMEM); 7600767e98aSRoger Pau Monné } 7610767e98aSRoger Pau Monné 762*1093cd82SRoger Pau Monné /*-------------------- Private Device Attachment Data -----------------------*/ 763*1093cd82SRoger Pau Monné static device_method_t granttable_methods[] = { 764*1093cd82SRoger Pau Monné /* Device interface */ 765*1093cd82SRoger Pau Monné DEVMETHOD(device_identify, granttable_identify), 766*1093cd82SRoger Pau Monné DEVMETHOD(device_probe, granttable_probe), 767*1093cd82SRoger Pau Monné DEVMETHOD(device_attach, granttable_attach), 768*1093cd82SRoger Pau Monné 769*1093cd82SRoger Pau Monné DEVMETHOD_END 770*1093cd82SRoger Pau Monné }; 771*1093cd82SRoger Pau Monné 772*1093cd82SRoger Pau Monné DEFINE_CLASS_0(granttable, granttable_driver, granttable_methods, 0); 773*1093cd82SRoger Pau Monné devclass_t granttable_devclass; 774*1093cd82SRoger Pau Monné 775*1093cd82SRoger Pau Monné DRIVER_MODULE_ORDERED(granttable, xenpv, granttable_driver, granttable_devclass, 776*1093cd82SRoger Pau Monné NULL, NULL, SI_ORDER_FIRST); 777