543bf5741875f5b215b30344cf537e3e8279b86d
[dpdk.git] / lib / librte_eal / linuxapp / xen_dom0 / dom0_mm_misc.c
1 /*-
2  * This file is provided under a dual BSD/GPLv2 license.  When using or
3  *   redistributing this file, you may do so under either license.
4  *
5  *   GPL LICENSE SUMMARY
6  *
7  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
8  *
9  *   This program is free software; you can redistribute it and/or modify
10  *   it under the terms of version 2 of the GNU General Public License as
11  *   published by the Free Software Foundation.
12  *
13  *   This program is distributed in the hope that it will be useful, but
14  *   WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *   General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with this program; if not, write to the Free Software
20  *   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21  *   The full GNU General Public License is included in this distribution
22  *   in the file called LICENSE.GPL.
23  *
24  *   Contact Information:
25  *   Intel Corporation
26  *
27  *   BSD LICENSE
28  *
29  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
30  *   All rights reserved.
31  *
32  *   Redistribution and use in source and binary forms, with or without
33  *   modification, are permitted provided that the following conditions
34  *   are met:
35  *
36  *     * Redistributions of source code must retain the above copyright
37  *       notice, this list of conditions and the following disclaimer.
38  *     * Redistributions in binary form must reproduce the above copyright
39  *       notice, this list of conditions and the following disclaimer in
40  *       the documentation and/or other materials provided with the
41  *       distribution.
42  *     * Neither the name of Intel Corporation nor the names of its
43  *       contributors may be used to endorse or promote products derived
44  *       from this software without specific prior written permission.
45  *
46  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
47  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
48  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
49  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
50  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
51  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
52  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
56  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57  *
58  */
59
60 #include <linux/module.h>
61 #include <linux/miscdevice.h>
62 #include <linux/fs.h>
63 #include <linux/device.h>
64 #include <linux/errno.h>
65 #include <linux/vmalloc.h>
66 #include <linux/mm.h>
67 #include <linux/version.h>
68
69 #include <xen/xen.h>
70 #include <xen/page.h>
71 #include <xen/xen-ops.h>
72 #include <xen/interface/memory.h>
73
74 #include <rte_config.h>
75 #include <exec-env/rte_dom0_common.h>
76
77 #include "compat.h"
78 #include "dom0_mm_dev.h"
79
80 MODULE_LICENSE("Dual BSD/GPL");
81 MODULE_AUTHOR("Intel Corporation");
82 MODULE_DESCRIPTION("Kernel Module for supporting DPDK running on Xen Dom0");
83
84 static struct dom0_mm_dev dom0_dev;
85 static struct kobject *dom0_kobj = NULL;
86
87 static struct memblock_info *rsv_mm_info;
88
89 /* Default configuration for reserved memory size(2048 MB). */
90 static uint32_t rsv_memsize = 2048;
91
92 static int dom0_open(struct inode *inode, struct file *file);
93 static int dom0_release(struct inode *inode, struct file *file);
94 static int dom0_ioctl(struct file *file, unsigned int ioctl_num,
95                 unsigned long ioctl_param);
96 static int dom0_mmap(struct file *file, struct vm_area_struct *vma);
97 static int dom0_memory_free(uint32_t size);
98 static int dom0_memory_release(struct dom0_mm_data *mm_data);
99
100 static const struct file_operations data_fops = {
101         .owner = THIS_MODULE,
102         .open = dom0_open,
103         .release = dom0_release,
104         .mmap = dom0_mmap,
105         .unlocked_ioctl = (void *)dom0_ioctl,
106 };
107
108 static ssize_t
109 show_memsize_rsvd(struct device *dev, struct device_attribute *attr, char *buf)
110 {
111         return snprintf(buf, 10, "%u\n", dom0_dev.used_memsize);
112 }
113
114 static ssize_t
115 show_memsize(struct device *dev, struct device_attribute *attr, char *buf)
116 {
117         return snprintf(buf, 10, "%u\n", dom0_dev.config_memsize);
118 }
119
120 static ssize_t
121 store_memsize(struct device *dev, struct device_attribute *attr,
122             const char *buf, size_t count)
123 {
124         int err = 0;
125         unsigned long mem_size;
126
127         if (0 != kstrtoul(buf, 0, &mem_size))
128                 return  -EINVAL;
129
130         mutex_lock(&dom0_dev.data_lock);
131         if (0 == mem_size) {
132                 err = -EINVAL;
133                 goto fail;
134         } else if (mem_size > (rsv_memsize - dom0_dev.used_memsize)) {
135                 XEN_ERR("configure memory size fail\n");
136                 err = -EINVAL;
137                 goto fail;
138         } else
139                 dom0_dev.config_memsize = mem_size;
140
141 fail:
142         mutex_unlock(&dom0_dev.data_lock);
143         return err ? err : count;
144 }
145
146 static DEVICE_ATTR(memsize, S_IRUGO | S_IWUSR, show_memsize, store_memsize);
147 static DEVICE_ATTR(memsize_rsvd, S_IRUGO, show_memsize_rsvd, NULL);
148
149 static struct attribute *dev_attrs[] = {
150         &dev_attr_memsize.attr,
151         &dev_attr_memsize_rsvd.attr,
152         NULL,
153 };
154
155 /* the memory size unit is MB */
156 static const struct attribute_group dev_attr_grp = {
157         .name = "memsize-mB",
158         .attrs = dev_attrs,
159 };
160
161
162 static void
163 sort_viraddr(struct memblock_info *mb, int cnt)
164 {
165         int i,j;
166         uint64_t tmp_pfn;
167         uint64_t tmp_viraddr;
168
169         /*sort virtual address and pfn */
170         for(i = 0; i < cnt; i ++) {
171                 for(j = cnt - 1; j > i; j--) {
172                         if(mb[j].pfn < mb[j - 1].pfn) {
173                                 tmp_pfn = mb[j - 1].pfn;
174                                 mb[j - 1].pfn = mb[j].pfn;
175                                 mb[j].pfn = tmp_pfn;
176
177                                 tmp_viraddr = mb[j - 1].vir_addr;
178                                 mb[j - 1].vir_addr = mb[j].vir_addr;
179                                 mb[j].vir_addr = tmp_viraddr;
180                         }
181                 }
182         }
183 }
184
185 static int
186 dom0_find_memdata(const char * mem_name)
187 {
188         unsigned i;
189         int idx = -1;
190         for(i = 0; i< NUM_MEM_CTX; i++) {
191                 if(dom0_dev.mm_data[i] == NULL)
192                         continue;
193                 if (!strncmp(dom0_dev.mm_data[i]->name, mem_name,
194                         sizeof(char) * DOM0_NAME_MAX)) {
195                         idx = i;
196                         break;
197                 }
198         }
199
200         return idx;
201 }
202
203 static int
204 dom0_find_mempos(void)
205 {
206         unsigned i;
207         int idx = -1;
208
209         for(i = 0; i< NUM_MEM_CTX; i++) {
210                 if(dom0_dev.mm_data[i] == NULL){
211                         idx = i;
212                         break;
213                 }
214         }
215
216         return idx;
217 }
218
219 static int
220 dom0_memory_release(struct dom0_mm_data *mm_data)
221 {
222         int idx;
223         uint32_t  num_block, block_id;
224
225         /* each memory block is 2M */
226         num_block = mm_data->mem_size / SIZE_PER_BLOCK;
227         if (num_block == 0)
228                 return -EINVAL;
229
230         /* reset global memory data */
231         idx = dom0_find_memdata(mm_data->name);
232         if (idx >= 0) {
233                 dom0_dev.used_memsize -= mm_data->mem_size;
234                 dom0_dev.mm_data[idx] = NULL;
235                 dom0_dev.num_mem_ctx--;
236         }
237
238         /* reset these memory blocks status as free */
239         for (idx = 0; idx < num_block; idx++) {
240                 block_id = mm_data->block_num[idx];
241                 rsv_mm_info[block_id].used = 0;
242         }
243
244         memset(mm_data, 0, sizeof(struct dom0_mm_data));
245         vfree(mm_data);
246         return 0;
247 }
248
249 static int
250 dom0_memory_free(uint32_t rsv_size)
251 {
252         uint64_t vstart, vaddr;
253         uint32_t i, num_block, size;
254
255         if (!xen_pv_domain())
256                 return -1;
257
258         /* each memory block is 2M */
259         num_block = rsv_size / SIZE_PER_BLOCK;
260         if (num_block == 0)
261                 return -EINVAL;
262
263         /* free all memory blocks of size of 4M and destroy contiguous region */
264         for (i = 0; i < dom0_dev.num_bigblock * 2; i += 2) {
265                 vstart = rsv_mm_info[i].vir_addr;
266                 if (vstart) {
267                 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
268                         if (rsv_mm_info[i].exchange_flag)
269                                 xen_destroy_contiguous_region(vstart,
270                                                 DOM0_CONTIG_NUM_ORDER);
271                         if (rsv_mm_info[i + 1].exchange_flag)
272                                 xen_destroy_contiguous_region(vstart +
273                                                 DOM0_MEMBLOCK_SIZE,
274                                                 DOM0_CONTIG_NUM_ORDER);
275                 #else
276                         if (rsv_mm_info[i].exchange_flag)
277                                 xen_destroy_contiguous_region(rsv_mm_info[i].pfn
278                                         * PAGE_SIZE,
279                                         DOM0_CONTIG_NUM_ORDER);
280                         if (rsv_mm_info[i + 1].exchange_flag)
281                                 xen_destroy_contiguous_region(rsv_mm_info[i].pfn
282                                         * PAGE_SIZE + DOM0_MEMBLOCK_SIZE,
283                                         DOM0_CONTIG_NUM_ORDER);
284                 #endif
285
286                         size = DOM0_MEMBLOCK_SIZE * 2;
287                         vaddr = vstart;
288                         while (size > 0) {
289                                 ClearPageReserved(virt_to_page(vaddr));
290                                 vaddr += PAGE_SIZE;
291                                 size -= PAGE_SIZE;
292                         }
293                         free_pages(vstart, MAX_NUM_ORDER);
294                 }
295         }
296
297         /* free all memory blocks size of 2M and destroy contiguous region */
298         for (; i < num_block; i++) {
299                 vstart = rsv_mm_info[i].vir_addr;
300                 if (vstart) {
301                         if (rsv_mm_info[i].exchange_flag)
302                                 xen_destroy_contiguous_region(vstart,
303                                         DOM0_CONTIG_NUM_ORDER);
304
305                         size = DOM0_MEMBLOCK_SIZE;
306                         vaddr = vstart;
307                         while (size > 0) {
308                                 ClearPageReserved(virt_to_page(vaddr));
309                                 vaddr += PAGE_SIZE;
310                                 size -= PAGE_SIZE;
311                         }
312                         free_pages(vstart, DOM0_CONTIG_NUM_ORDER);
313                 }
314         }
315
316         memset(rsv_mm_info, 0, sizeof(struct memblock_info) * num_block);
317         vfree(rsv_mm_info);
318         rsv_mm_info = NULL;
319
320         return 0;
321 }
322
323 static void
324 find_free_memory(uint32_t count, struct dom0_mm_data *mm_data)
325 {
326         uint32_t i = 0;
327         uint32_t j = 0;
328
329         while ((i < count) && (j < rsv_memsize / SIZE_PER_BLOCK)) {
330                 if (rsv_mm_info[j].used == 0) {
331                         mm_data->block_info[i].pfn = rsv_mm_info[j].pfn;
332                         mm_data->block_info[i].vir_addr =
333                                 rsv_mm_info[j].vir_addr;
334                         mm_data->block_info[i].mfn = rsv_mm_info[j].mfn;
335                         mm_data->block_info[i].exchange_flag =
336                                 rsv_mm_info[j].exchange_flag;
337                         mm_data->block_num[i] = j;
338                         rsv_mm_info[j].used = 1;
339                         i++;
340                 }
341                 j++;
342         }
343 }
344
345 /**
346  * Find all memory segments in which physical addresses are contiguous.
347  */
348 static void
349 find_memseg(int count, struct dom0_mm_data * mm_data)
350 {
351         int i = 0;
352         int j, k, idx = 0;
353         uint64_t zone_len, pfn, num_block;
354
355         while(i < count) {
356                 if (mm_data->block_info[i].exchange_flag == 0) {
357                         i++;
358                         continue;
359                 }
360                 k = 0;
361                 pfn = mm_data->block_info[i].pfn;
362                 mm_data->seg_info[idx].pfn = pfn;
363                 mm_data->seg_info[idx].mfn[k] = mm_data->block_info[i].mfn;
364
365                 for (j = i + 1; j < count; j++) {
366
367                         /* ignore exchange fail memory block */
368                         if (mm_data->block_info[j].exchange_flag == 0)
369                                 break;
370
371                         if (mm_data->block_info[j].pfn !=
372                                 (mm_data->block_info[j - 1].pfn +
373                                          DOM0_MEMBLOCK_SIZE / PAGE_SIZE))
374                             break;
375                         ++k;
376                         mm_data->seg_info[idx].mfn[k] = mm_data->block_info[j].mfn;
377                 }
378
379                 num_block = j - i;
380                 zone_len = num_block * DOM0_MEMBLOCK_SIZE;
381                 mm_data->seg_info[idx].size = zone_len;
382
383                 XEN_PRINT("memseg id=%d, size=0x%llx\n", idx, zone_len);
384                 i = i+ num_block;
385                 idx++;
386                 if (idx == DOM0_NUM_MEMSEG)
387                         break;
388         }
389         mm_data->num_memseg = idx;
390 }
391
392 static int
393 dom0_memory_reserve(uint32_t rsv_size)
394 {
395         uint64_t pfn, vstart, vaddr;
396         uint32_t i, num_block, size, allocated_size = 0;
397
398 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
399         dma_addr_t dma_handle;
400 #endif
401
402         /* 2M as memory block */
403         num_block = rsv_size / SIZE_PER_BLOCK;
404
405         rsv_mm_info = vmalloc(sizeof(struct memblock_info) * num_block);
406         if (!rsv_mm_info) {
407                 XEN_ERR("Unable to allocate device memory information\n");
408                 return -ENOMEM;
409         }
410         memset(rsv_mm_info, 0, sizeof(struct memblock_info) * num_block);
411
412         /* try alloc size of 4M once */
413         for (i = 0; i < num_block; i += 2) {
414                 vstart = (unsigned long)
415                         __get_free_pages(GFP_ATOMIC, MAX_NUM_ORDER);
416                 if (vstart == 0)
417                         break;
418
419                 dom0_dev.num_bigblock = i / 2 + 1;
420                 allocated_size =  SIZE_PER_BLOCK * (i + 2);
421
422                 /* size of 4M */
423                 size = DOM0_MEMBLOCK_SIZE * 2;
424
425                 vaddr = vstart;
426                 while (size > 0) {
427                         SetPageReserved(virt_to_page(vaddr));
428                         vaddr += PAGE_SIZE;
429                         size -= PAGE_SIZE;
430                 }
431
432                 pfn = virt_to_pfn(vstart);
433                 rsv_mm_info[i].pfn = pfn;
434                 rsv_mm_info[i].vir_addr = vstart;
435                 rsv_mm_info[i + 1].pfn =
436                                 pfn + DOM0_MEMBLOCK_SIZE / PAGE_SIZE;
437                 rsv_mm_info[i + 1].vir_addr =
438                                 vstart + DOM0_MEMBLOCK_SIZE;
439         }
440
441         /*if it failed to alloc 4M, and continue to alloc 2M once */
442         for (; i < num_block; i++) {
443                 vstart = (unsigned long)
444                         __get_free_pages(GFP_ATOMIC, DOM0_CONTIG_NUM_ORDER);
445                 if (vstart == 0) {
446                         XEN_ERR("allocate memory fail.\n");
447                         dom0_memory_free(allocated_size);
448                         return -ENOMEM;
449                 }
450
451                 allocated_size += SIZE_PER_BLOCK;
452
453                 size = DOM0_MEMBLOCK_SIZE;
454                 vaddr = vstart;
455                 while (size > 0) {
456                         SetPageReserved(virt_to_page(vaddr));
457                         vaddr += PAGE_SIZE;
458                         size -= PAGE_SIZE;
459                 }
460                 pfn = virt_to_pfn(vstart);
461                 rsv_mm_info[i].pfn = pfn;
462                 rsv_mm_info[i].vir_addr = vstart;
463         }
464
465         sort_viraddr(rsv_mm_info, num_block);
466         
467         for (i = 0; i< num_block; i++) {
468
469                 /*
470                  * This API is used to exchage MFN for getting a block of
471                  * contiguous physical addresses, its maximum size is 2M.
472                  */
473         #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
474                 if (xen_create_contiguous_region(rsv_mm_info[i].vir_addr,
475                                 DOM0_CONTIG_NUM_ORDER, 0) == 0) {
476         #else
477                 if (xen_create_contiguous_region(rsv_mm_info[i].pfn * PAGE_SIZE,
478                                 DOM0_CONTIG_NUM_ORDER, 0, &dma_handle) == 0) {
479         #endif
480                         rsv_mm_info[i].exchange_flag = 1;
481                         rsv_mm_info[i].mfn =
482                                 pfn_to_mfn(rsv_mm_info[i].pfn);
483                         rsv_mm_info[i].used = 0;
484                 } else {
485                         XEN_ERR("exchange memeory fail\n");
486                         rsv_mm_info[i].exchange_flag = 0;
487                         dom0_dev.fail_times++;
488                         if (dom0_dev.fail_times > MAX_EXCHANGE_FAIL_TIME) {
489                                 dom0_memory_free(rsv_size);
490                                 return  -EFAULT;
491                         }
492                 }
493         }
494
495         return 0;
496 }
497
498 static int
499 dom0_prepare_memsegs(struct memory_info *meminfo, struct dom0_mm_data *mm_data)
500 {
501         uint32_t num_block;
502         int idx;
503
504         /* check if there is a free name buffer */
505         memcpy(mm_data->name, meminfo->name, DOM0_NAME_MAX);
506         mm_data->name[DOM0_NAME_MAX - 1] = '\0';
507         idx = dom0_find_mempos();
508         if (idx < 0)
509                 return -1;
510
511         num_block = meminfo->size / SIZE_PER_BLOCK;
512         /* find free memory and new memory segments*/
513         find_free_memory(num_block, mm_data);
514         find_memseg(num_block, mm_data);
515
516         /* update private memory data */
517         mm_data->refcnt++;
518         mm_data->mem_size = meminfo->size;
519
520         /* update global memory data */
521         dom0_dev.mm_data[idx] = mm_data;
522         dom0_dev.num_mem_ctx++;
523         dom0_dev.used_memsize += mm_data->mem_size;
524
525         return 0;
526 }
527
528 static int
529 dom0_check_memory (struct memory_info *meminfo)
530 {
531         int idx;
532         uint64_t mem_size;
533
534         /* round memory size to the next even number. */
535         if (meminfo->size % 2)
536                 ++meminfo->size;
537
538         mem_size = meminfo->size;
539         if (dom0_dev.num_mem_ctx > NUM_MEM_CTX) {
540                 XEN_ERR("Memory data space is full in Dom0 driver\n");
541                 return -1;
542         }
543         idx = dom0_find_memdata(meminfo->name);
544         if (idx >= 0) {
545                 XEN_ERR("Memory data name %s has already exsited in Dom0 driver.\n",
546                         meminfo->name);
547                 return -1;
548         }
549         if ((dom0_dev.used_memsize + mem_size) > rsv_memsize) {
550                 XEN_ERR("Total size can't be larger than reserved size.\n");
551                 return -1;
552         }
553
554         return 0;
555 }
556
557 static int __init
558 dom0_init(void)
559 {
560         if (!xen_domain())
561                 return -ENODEV;
562
563         if (rsv_memsize > DOM0_CONFIG_MEMSIZE) {
564                 XEN_ERR("The reserved memory size cannot be greater than %d\n",
565                         DOM0_CONFIG_MEMSIZE);
566                 return -EINVAL;
567         }
568
569         /* Setup the misc device */
570         dom0_dev.miscdev.minor = MISC_DYNAMIC_MINOR;
571         dom0_dev.miscdev.name = "dom0_mm";
572         dom0_dev.miscdev.fops = &data_fops;
573
574         /* register misc char device */
575         if (misc_register(&dom0_dev.miscdev) != 0) {
576                 XEN_ERR("Misc device registration failed\n");
577                 return -EPERM;
578         }
579
580         mutex_init(&dom0_dev.data_lock);
581         dom0_kobj = kobject_create_and_add("dom0-mm", mm_kobj);
582
583         if (!dom0_kobj) {
584                 XEN_ERR("dom0-mm object creation failed\n");
585                 misc_deregister(&dom0_dev.miscdev);
586                 return -ENOMEM;
587         }
588
589         if (sysfs_create_group(dom0_kobj, &dev_attr_grp)) {
590                 kobject_put(dom0_kobj);
591                 misc_deregister(&dom0_dev.miscdev);
592                 return -EPERM;
593         }
594
595         if (dom0_memory_reserve(rsv_memsize) < 0) {
596                 sysfs_remove_group(dom0_kobj, &dev_attr_grp);
597                 kobject_put(dom0_kobj);
598                 misc_deregister(&dom0_dev.miscdev);
599                 return -ENOMEM;
600         }
601
602         XEN_PRINT("####### DPDK Xen Dom0 module loaded  #######\n");
603
604         return 0;
605 }
606
607 static void __exit
608 dom0_exit(void)
609 {
610         if (rsv_mm_info != NULL)
611                 dom0_memory_free(rsv_memsize);
612
613         sysfs_remove_group(dom0_kobj, &dev_attr_grp);
614         kobject_put(dom0_kobj);
615         misc_deregister(&dom0_dev.miscdev);
616
617         XEN_PRINT("####### DPDK Xen Dom0 module unloaded  #######\n");
618 }
619
620 static int
621 dom0_open(struct inode *inode, struct file *file)
622 {
623         file->private_data = NULL;
624
625         XEN_PRINT(KERN_INFO "/dev/dom0_mm opened\n");
626         return 0;
627 }
628
629 static int
630 dom0_release(struct inode *inode, struct file *file)
631 {
632         int ret = 0;
633         struct dom0_mm_data *mm_data = file->private_data;
634
635         if (mm_data == NULL)
636                 return ret;
637
638         mutex_lock(&dom0_dev.data_lock);
639         if (--mm_data->refcnt == 0)
640                 ret = dom0_memory_release(mm_data);
641         mutex_unlock(&dom0_dev.data_lock);
642
643         file->private_data = NULL;
644         XEN_PRINT(KERN_INFO "/dev/dom0_mm closed\n");
645         return ret;
646 }
647
648 static int
649 dom0_mmap(struct file *file, struct vm_area_struct *vm)
650 {
651         int status = 0;
652         uint32_t idx = vm->vm_pgoff;
653         uint64_t pfn, size = vm->vm_end - vm->vm_start;
654         struct dom0_mm_data *mm_data = file->private_data;
655
656         if(mm_data == NULL)
657                 return -EINVAL;
658
659         mutex_lock(&dom0_dev.data_lock);
660         if (idx >= mm_data->num_memseg) {
661                 mutex_unlock(&dom0_dev.data_lock);
662                 return -EINVAL;
663         }
664
665         if (size > mm_data->seg_info[idx].size){
666                 mutex_unlock(&dom0_dev.data_lock);
667                 return -EINVAL;
668         }
669
670         XEN_PRINT("mmap memseg idx =%d,size = 0x%llx\n", idx, size);
671
672         pfn = mm_data->seg_info[idx].pfn;
673         mutex_unlock(&dom0_dev.data_lock);
674
675         status = remap_pfn_range(vm, vm->vm_start, pfn, size, PAGE_SHARED);
676
677         return status;
678 }
679 static int
680 dom0_ioctl(struct file *file,
681         unsigned int ioctl_num,
682         unsigned long ioctl_param)
683 {
684         int idx, ret;
685         char name[DOM0_NAME_MAX] = {0};
686         struct memory_info meminfo;
687         struct dom0_mm_data *mm_data = file->private_data;
688
689         XEN_PRINT("IOCTL num=0x%0x param=0x%0lx \n", ioctl_num, ioctl_param);
690
691         /**
692          * Switch according to the ioctl called
693          */
694         switch _IOC_NR(ioctl_num) {
695         case _IOC_NR(RTE_DOM0_IOCTL_PREPARE_MEMSEG):
696                 ret = copy_from_user(&meminfo, (void *)ioctl_param,
697                         sizeof(struct memory_info));
698                 if (ret)
699                         return  -EFAULT;
700
701                 if (mm_data != NULL) {
702                         XEN_ERR("Cannot create memory segment for the same"
703                                 " file descriptor\n");
704                         return -EINVAL;
705                 }
706
707                 /* Allocate private data */
708                 mm_data = vmalloc(sizeof(struct dom0_mm_data));
709                 if (!mm_data) {
710                         XEN_ERR("Unable to allocate device private data\n");
711                         return -ENOMEM;
712                 }
713                 memset(mm_data, 0, sizeof(struct dom0_mm_data));
714
715                 mutex_lock(&dom0_dev.data_lock);
716                 /* check if we can allocate memory*/
717                 if (dom0_check_memory(&meminfo) < 0) {
718                         mutex_unlock(&dom0_dev.data_lock);
719                         vfree(mm_data);
720                         return -EINVAL;
721                 }
722
723                 /* allocate memory and created memory segments*/
724                 if (dom0_prepare_memsegs(&meminfo, mm_data) < 0) {
725                         XEN_ERR("create memory segment fail.\n");
726                         mutex_unlock(&dom0_dev.data_lock);
727                         return -EIO;
728                 }
729
730                 file->private_data = mm_data;
731                 mutex_unlock(&dom0_dev.data_lock);
732                 break;
733
734         /* support multiple process in term of memory mapping*/
735         case _IOC_NR(RTE_DOM0_IOCTL_ATTACH_TO_MEMSEG):
736                 ret = copy_from_user(name, (void *)ioctl_param,
737                                 sizeof(char) * DOM0_NAME_MAX);
738                 if (ret)
739                         return -EFAULT;
740
741                 mutex_lock(&dom0_dev.data_lock);
742                 idx = dom0_find_memdata(name);
743                 if (idx < 0) {
744                         mutex_unlock(&dom0_dev.data_lock);
745                         return -EINVAL;
746                 }
747
748                 mm_data = dom0_dev.mm_data[idx];
749                 mm_data->refcnt++;
750                 file->private_data = mm_data;
751                 mutex_unlock(&dom0_dev.data_lock);
752                 break;
753
754         case _IOC_NR(RTE_DOM0_IOCTL_GET_NUM_MEMSEG):
755                 ret = copy_to_user((void *)ioctl_param, &mm_data->num_memseg,
756                                 sizeof(int));
757                 if (ret)
758                         return -EFAULT;
759                 break;
760
761         case _IOC_NR(RTE_DOM0_IOCTL_GET_MEMSEG_INFO):
762                 ret = copy_to_user((void *)ioctl_param,
763                                 &mm_data->seg_info[0],
764                                 sizeof(struct memseg_info) *
765                                 mm_data->num_memseg);
766                 if (ret)
767                         return -EFAULT;
768                 break;
769         default:
770                 XEN_PRINT("IOCTL default \n");
771                 break;
772         }
773
774         return 0;
775 }
776
777 module_init(dom0_init);
778 module_exit(dom0_exit);
779
780 module_param(rsv_memsize, uint, S_IRUGO | S_IWUSR);
781 MODULE_PARM_DESC(rsv_memsize, "Xen-dom0 reserved memory size(MB).\n");