int gnttab_resume(void) { unsigned int max_nr_gframes; gnttab_request_version(); max_nr_gframes = gnttab_max_grant_frames(); if (max_nr_gframes < nr_grant_frames) return -ENOSYS; if (xen_pv_domain()) return gnttab_map(0, nr_grant_frames - 1); if (gnttab_shared.addr == NULL) { gnttab_shared.addr = ioremap(xen_hvm_resume_frames, PAGE_SIZE * max_nr_gframes); if (gnttab_shared.addr == NULL) { printk(KERN_WARNING "Failed to ioremap gnttab share frames!"); return -ENOMEM; } } gnttab_map(0, nr_grant_frames - 1); return 0; }
int gnttab_init(void) { int i; unsigned long max_nr_grant_frames; unsigned int max_nr_glist_frames, nr_glist_frames; unsigned int nr_init_grefs; int ret; gnttab_request_version(); max_nr_grant_frames = gnttab_max_grant_frames(); nr_grant_frames = 1; /* Determine the maximum number of frames required for the * grant reference free list on the current hypervisor. */ BUG_ON(grefs_per_grant_frame == 0); max_nr_glist_frames = (max_nr_grant_frames * grefs_per_grant_frame / RPP); gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *), GFP_KERNEL); if (gnttab_list == NULL) return -ENOMEM; nr_glist_frames = (nr_grant_frames * grefs_per_grant_frame + RPP - 1) / RPP; for (i = 0; i < nr_glist_frames; i++) { gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL); if (gnttab_list[i] == NULL) { ret = -ENOMEM; goto ini_nomem; } } ret = arch_gnttab_init(max_nr_grant_frames); if (ret < 0) goto ini_nomem; if (gnttab_setup() < 0) { ret = -ENODEV; goto ini_nomem; } nr_init_grefs = nr_grant_frames * grefs_per_grant_frame; for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++) gnttab_entry(i) = i + 1; gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END; gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES; gnttab_free_head = NR_RESERVED_ENTRIES; printk("Grant table initialized\n"); return 0; ini_nomem: for (i--; i >= 0; i--) free_page((unsigned long)gnttab_list[i]); kfree(gnttab_list); return ret; }
int gnttab_resume(void) { unsigned int max_nr_gframes; max_nr_gframes = gnttab_max_grant_frames(); if (max_nr_gframes < nr_grant_frames) return -ENOSYS; if (xen_pv_domain()) return gnttab_map(0, nr_grant_frames - 1); if (!shared) { shared = ioremap(xen_hvm_resume_frames, PAGE_SIZE * max_nr_gframes); if (shared == NULL) { #ifdef CONFIG_DEBUG_PRINTK printk(KERN_WARNING "Failed to ioremap gnttab share frames!"); #else ; #endif return -ENOMEM; } } gnttab_map(0, nr_grant_frames - 1); return 0; }
static int gnttab_setup(void) { int rc; unsigned int max_nr_gframes; max_nr_gframes = gnttab_max_grant_frames(); if (max_nr_gframes < nr_grant_frames) return -ENOSYS; if (xen_pv_domain() && xen_feature(XENFEAT_auto_translated_physmap) && !gnttab_shared.addr) { rc = xlated_setup_gnttab_pages((unsigned long)max_nr_gframes, &gnttab_shared.addr); if (rc != 0) return rc; } if (xen_pv_domain()) return gnttab_map(0, nr_grant_frames - 1); if (gnttab_shared.addr == NULL) { gnttab_shared.addr = xen_remap(xen_hvm_resume_frames, PAGE_SIZE * max_nr_gframes); if (gnttab_shared.addr == NULL) { printk(KERN_WARNING "Failed to ioremap gnttab share frames!"); return -ENOMEM; } } gnttab_map(0, nr_grant_frames - 1); return 0; }
static int gnttab_map(unsigned int start_idx, unsigned int end_idx) { struct gnttab_setup_table setup; unsigned long *frames; unsigned int nr_gframes = end_idx + 1; int rc; if (xen_hvm_domain()) { struct xen_add_to_physmap xatp; unsigned int i = end_idx; rc = 0; /* * Loop backwards, so that the first hypercall has the largest * index, ensuring that the table will grow only once. */ do { xatp.domid = DOMID_SELF; xatp.idx = i; xatp.space = XENMAPSPACE_grant_table; xatp.gpfn = (xen_hvm_resume_frames >> PAGE_SHIFT) + i; rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp); if (rc != 0) { #ifdef CONFIG_DEBUG_PRINTK printk(KERN_WARNING "grant table add_to_physmap failed, err=%d\n", rc); #else ; #endif break; } } while (i-- > start_idx); return rc; } frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC); if (!frames) return -ENOMEM; setup.dom = DOMID_SELF; setup.nr_frames = nr_gframes; set_xen_guest_handle(setup.frame_list, frames); rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); if (rc == -ENOSYS) { kfree(frames); return -ENOSYS; } BUG_ON(rc || setup.status); rc = arch_gnttab_map_shared(frames, nr_gframes, gnttab_max_grant_frames(), &shared); BUG_ON(rc); kfree(frames); return 0; }
static int gnttab_map_frames_v2(xen_pfn_t *frames, unsigned int nr_gframes) { uint64_t *sframes; unsigned int nr_sframes; struct gnttab_get_status_frames getframes; int rc; nr_sframes = nr_status_frames(nr_gframes); /* No need for kzalloc as it is initialized in following hypercall * GNTTABOP_get_status_frames. */ sframes = kmalloc(nr_sframes * sizeof(uint64_t), GFP_ATOMIC); if (!sframes) return -ENOMEM; getframes.dom = DOMID_SELF; getframes.nr_frames = nr_sframes; set_xen_guest_handle(getframes.frame_list, sframes); rc = HYPERVISOR_grant_table_op(GNTTABOP_get_status_frames, &getframes, 1); if (rc == -ENOSYS) { kfree(sframes); return -ENOSYS; } BUG_ON(rc || getframes.status); rc = arch_gnttab_map_status(sframes, nr_sframes, nr_status_frames(gnttab_max_grant_frames()), &grstatus); BUG_ON(rc); kfree(sframes); rc = arch_gnttab_map_shared(frames, nr_gframes, gnttab_max_grant_frames(), &gnttab_shared.addr); BUG_ON(rc); return 0; }
static int gnttab_map_frames_v1(xen_pfn_t *frames, unsigned int nr_gframes) { int rc; rc = arch_gnttab_map_shared(frames, nr_gframes, gnttab_max_grant_frames(), &gnttab_shared.addr); BUG_ON(rc); return 0; }
static int __init xen_pvh_gnttab_setup(void) { if (!xen_pvh_domain()) return -ENODEV; xen_auto_xlat_grant_frames.count = gnttab_max_grant_frames(); return xen_xlate_map_ballooned_pages(&xen_auto_xlat_grant_frames.pfn, &xen_auto_xlat_grant_frames.vaddr, xen_auto_xlat_grant_frames.count); }
static int __init xlated_setup_gnttab_pages(void) { struct page **pages; xen_pfn_t *pfns; int rc; unsigned int i; unsigned long nr_grant_frames = gnttab_max_grant_frames(); BUG_ON(nr_grant_frames == 0); pages = kcalloc(nr_grant_frames, sizeof(pages[0]), GFP_KERNEL); if (!pages) return -ENOMEM; pfns = kcalloc(nr_grant_frames, sizeof(pfns[0]), GFP_KERNEL); if (!pfns) { kfree(pages); return -ENOMEM; } rc = alloc_xenballooned_pages(nr_grant_frames, pages, 0 /* lowmem */); if (rc) { pr_warn("%s Couldn't balloon alloc %ld pfns rc:%d\n", __func__, nr_grant_frames, rc); kfree(pages); kfree(pfns); return rc; } for (i = 0; i < nr_grant_frames; i++) pfns[i] = page_to_pfn(pages[i]); rc = arch_gnttab_map_shared(pfns, nr_grant_frames, nr_grant_frames, &xen_auto_xlat_grant_frames.vaddr); if (rc) { pr_warn("%s Couldn't map %ld pfns rc:%d\n", __func__, nr_grant_frames, rc); free_xenballooned_pages(nr_grant_frames, pages); kfree(pages); kfree(pfns); return rc; } kfree(pages); xen_auto_xlat_grant_frames.pfn = pfns; xen_auto_xlat_grant_frames.count = nr_grant_frames; return 0; }
static int gnttab_expand(unsigned int req_entries) { int rc; unsigned int cur, extra; cur = nr_grant_frames; extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) / GREFS_PER_GRANT_FRAME); if (cur + extra > gnttab_max_grant_frames()) return -ENOSPC; rc = gnttab_map(cur, cur + extra - 1); if (rc == 0) rc = grow_gnttab_list(extra); return rc; }
static int gnttab_setup(void) { unsigned int max_nr_gframes; max_nr_gframes = gnttab_max_grant_frames(); if (max_nr_gframes < nr_grant_frames) return -ENOSYS; if (xen_feature(XENFEAT_auto_translated_physmap) && gnttab_shared.addr == NULL) { gnttab_shared.addr = xen_auto_xlat_grant_frames.vaddr; if (gnttab_shared.addr == NULL) { pr_warn("gnttab share frames (addr=0x%08lx) is not mapped!\n", (unsigned long)xen_auto_xlat_grant_frames.vaddr); return -ENOMEM; } } return gnttab_map(0, nr_grant_frames - 1); }
static int gnttab_expand(unsigned int req_entries) { int rc; unsigned int cur, extra; BUG_ON(grefs_per_grant_frame == 0); cur = nr_grant_frames; extra = ((req_entries + (grefs_per_grant_frame-1)) / grefs_per_grant_frame); if (cur + extra > gnttab_max_grant_frames()) return -ENOSPC; rc = gnttab_map(cur, cur + extra - 1); if (rc == 0) rc = grow_gnttab_list(extra); return rc; }
static int __devinit platform_pci_init(struct pci_dev *pdev, const struct pci_device_id *ent) { int i, ret; long ioaddr; long mmio_addr, mmio_len; unsigned int max_nr_gframes; i = pci_enable_device(pdev); if (i) return i; ioaddr = pci_resource_start(pdev, 0); mmio_addr = pci_resource_start(pdev, 1); mmio_len = pci_resource_len(pdev, 1); if (mmio_addr == 0 || ioaddr == 0) { dev_err(&pdev->dev, "no resources found\n"); ret = -ENOENT; goto pci_out; } ret = pci_request_region(pdev, 1, DRV_NAME); if (ret < 0) goto pci_out; ret = pci_request_region(pdev, 0, DRV_NAME); if (ret < 0) goto mem_out; platform_mmio = mmio_addr; platform_mmiolen = mmio_len; if (!xen_have_vector_callback) { ret = xen_allocate_irq(pdev); if (ret) { dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret); goto out; } callback_via = get_callback_via(pdev); ret = xen_set_callback_via(callback_via); if (ret) { dev_warn(&pdev->dev, "Unable to set the evtchn callback " "err=%d\n", ret); goto out; } } max_nr_gframes = gnttab_max_grant_frames(); xen_hvm_resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes); ret = gnttab_init(); if (ret) goto out; xenbus_probe(NULL); return 0; out: pci_release_region(pdev, 0); mem_out: pci_release_region(pdev, 1); pci_out: pci_disable_device(pdev); return ret; }