xen: reserve memory at installing dom0_mm.ko
[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  
68 #include <xen/xen.h>
69 #include <xen/page.h>
70 #include <xen/xen-ops.h>
71 #include <xen/interface/memory.h>
72  
73 #include <rte_config.h>
74 #include <exec-env/rte_dom0_common.h>
75  
76 #include "dom0_mm_dev.h"
77
78 MODULE_LICENSE("Dual BSD/GPL");
79 MODULE_AUTHOR("Intel Corporation");
80 MODULE_DESCRIPTION("Kernel Module for supporting DPDK running on Xen Dom0");
81
82 static struct dom0_mm_dev dom0_dev;
83 static struct kobject *dom0_kobj = NULL;
84
85 static struct memblock_info *rsv_mm_info;
86
87 /* Default configuration for reserved memory size(2048 MB). */
88 static uint32_t rsv_memsize = 2048;
89
90 static int dom0_open(struct inode *inode, struct file *file);
91 static int dom0_release(struct inode *inode, struct file *file);
92 static int dom0_ioctl(struct file *file, unsigned int ioctl_num,
93                 unsigned long ioctl_param);
94 static int dom0_mmap(struct file *file, struct vm_area_struct *vma);
95 static int dom0_memory_free(uint32_t size);
96 static int dom0_memory_release(struct dom0_mm_data *mm_data);
97
98 static const struct file_operations data_fops = {
99         .owner = THIS_MODULE,
100         .open = dom0_open,
101         .release = dom0_release,
102         .mmap = dom0_mmap,
103         .unlocked_ioctl = (void *)dom0_ioctl,
104 };
105
106 static ssize_t
107 show_memsize_rsvd(struct device *dev, struct device_attribute *attr, char *buf)
108 {
109         return snprintf(buf, 10, "%u\n", dom0_dev.used_memsize);
110 }
111
112 static ssize_t
113 show_memsize(struct device *dev, struct device_attribute *attr, char *buf)
114 {
115         return snprintf(buf, 10, "%u\n", dom0_dev.config_memsize);
116 }
117
118 static ssize_t
119 store_memsize(struct device *dev, struct device_attribute *attr,
120             const char *buf, size_t count)
121 {
122         int err = 0;
123         unsigned long mem_size;
124         
125         if (0 != strict_strtoul(buf, 0, &mem_size)) 
126                 return  -EINVAL;
127
128         mutex_lock(&dom0_dev.data_lock);
129         if (0 == mem_size) {
130                 err = -EINVAL;
131                 goto fail;
132         } else if (mem_size > (rsv_memsize - dom0_dev.used_memsize)) {
133                 XEN_ERR("configure memory size fail\n");
134                 err = -EINVAL;
135                 goto fail;
136         } else 
137                 dom0_dev.config_memsize = mem_size;
138
139 fail:
140         mutex_unlock(&dom0_dev.data_lock);
141         return err ? err : count;
142 }
143
144 static DEVICE_ATTR(memsize, S_IRUGO | S_IWUSR, show_memsize, store_memsize);
145 static DEVICE_ATTR(memsize_rsvd, S_IRUGO, show_memsize_rsvd, NULL);
146
147 static struct attribute *dev_attrs[] = {
148         &dev_attr_memsize.attr,
149         &dev_attr_memsize_rsvd.attr,
150         NULL,
151 };
152
153 /* the memory size unit is MB */
154 static const struct attribute_group dev_attr_grp = {
155         .name = "memsize-mB",
156         .attrs = dev_attrs,
157 };
158
159
160 static void 
161 sort_viraddr(struct memblock_info *mb, int cnt)
162 {
163         int i,j; 
164         uint64_t tmp_pfn;
165         uint64_t tmp_viraddr;
166
167         /*sort virtual address and pfn */
168         for(i = 0; i < cnt; i ++) {  
169                 for(j = cnt - 1; j > i; j--) {  
170                         if(mb[j].pfn < mb[j - 1].pfn) {
171                                 tmp_pfn = mb[j - 1].pfn;
172                                 mb[j - 1].pfn = mb[j].pfn;
173                                 mb[j].pfn = tmp_pfn;
174
175                                 tmp_viraddr = mb[j - 1].vir_addr;
176                                 mb[j - 1].vir_addr = mb[j].vir_addr;
177                                 mb[j].vir_addr = tmp_viraddr;
178                         } 
179                 }
180         }
181 }
182
183 static int
184 dom0_find_memdata(const char * mem_name)
185 {
186         unsigned i;
187         int idx = -1;
188         for(i = 0; i< NUM_MEM_CTX; i++) {
189                 if(dom0_dev.mm_data[i] == NULL)
190                         continue;
191                 if (!strncmp(dom0_dev.mm_data[i]->name, mem_name, 
192                         sizeof(char) * DOM0_NAME_MAX)) {
193                         idx = i;
194                         break; 
195                 }
196         }
197
198         return idx;
199 }
200
201 static int
202 dom0_find_mempos(void)
203 {
204         unsigned i;
205         int idx = -1;
206
207         for(i = 0; i< NUM_MEM_CTX; i++) {
208                 if(dom0_dev.mm_data[i] == NULL){
209                         idx = i;
210                         break;
211                 }
212         }
213
214         return idx;
215 }
216
217 static int
218 dom0_memory_release(struct dom0_mm_data *mm_data)
219 {
220         int idx;
221         uint32_t  num_block, block_id;
222
223         /* each memory block is 2M */
224         num_block = mm_data->mem_size / SIZE_PER_BLOCK;
225         if (num_block == 0)
226                 return -EINVAL;
227
228         /* reset global memory data */
229         idx = dom0_find_memdata(mm_data->name);
230         if (idx >= 0) {
231                 dom0_dev.used_memsize -= mm_data->mem_size;
232                 dom0_dev.mm_data[idx] = NULL;
233                 dom0_dev.num_mem_ctx--;
234         }
235
236         /* reset these memory blocks status as free */
237         for (idx = 0; idx < num_block; idx++) {
238                 block_id = mm_data->block_num[idx];
239                 rsv_mm_info[block_id].used = 0;
240         }
241
242         memset(mm_data, 0, sizeof(struct dom0_mm_data));
243         vfree(mm_data);
244         return 0;
245 }
246
247 static int
248 dom0_memory_free(uint32_t rsv_size)
249 {
250         uint64_t vstart, vaddr;
251         uint32_t i, num_block, size;
252
253         if (!xen_pv_domain())
254                 return -1;
255
256         /* each memory block is 2M */
257         num_block = rsv_size / SIZE_PER_BLOCK;
258         if (num_block == 0)
259                 return -EINVAL;
260
261         /* free all memory blocks of size of 4M and destroy contiguous region */
262         for (i = 0; i < dom0_dev.num_bigblock * 2; i += 2) {
263                 vstart = rsv_mm_info[i].vir_addr;
264                 if (vstart) {
265                         if (rsv_mm_info[i].exchange_flag)
266                                 xen_destroy_contiguous_region(vstart,
267                                                 DOM0_CONTIG_NUM_ORDER);
268                         if (rsv_mm_info[i + 1].exchange_flag)
269                                 xen_destroy_contiguous_region(vstart +
270                                                 DOM0_MEMBLOCK_SIZE,
271                                                 DOM0_CONTIG_NUM_ORDER);
272                         size = DOM0_MEMBLOCK_SIZE * 2;
273                         vaddr = vstart;
274                         while (size > 0) {
275                                 ClearPageReserved(virt_to_page(vaddr));
276                                 vaddr += PAGE_SIZE;
277                                 size -= PAGE_SIZE;
278                         }
279                         free_pages(vstart, MAX_NUM_ORDER);
280                 }
281         }
282
283         /* free all memory blocks size of 2M and destroy contiguous region */
284         for (; i < num_block; i++) {
285                 vstart = rsv_mm_info[i].vir_addr;
286                 if (vstart) {
287                         if (rsv_mm_info[i].exchange_flag)
288                                 xen_destroy_contiguous_region(vstart, 
289                                         DOM0_CONTIG_NUM_ORDER);
290
291                         size = DOM0_MEMBLOCK_SIZE;
292                         vaddr = vstart;
293                         while (size > 0) {
294                                 ClearPageReserved(virt_to_page(vaddr));
295                                 vaddr += PAGE_SIZE;
296                                 size -= PAGE_SIZE;
297                         }
298                         free_pages(vstart, DOM0_CONTIG_NUM_ORDER);
299                 }
300         }
301
302         memset(rsv_mm_info, 0, sizeof(struct memblock_info) * num_block);
303         vfree(rsv_mm_info);
304         rsv_mm_info = NULL;
305
306         return 0;
307 }
308
309 static void
310 find_free_memory(uint32_t count, struct dom0_mm_data *mm_data)
311 {
312         uint32_t i = 0;
313         uint32_t j = 0;
314
315         while ((i < count) && (j < rsv_memsize / SIZE_PER_BLOCK)) {
316                 if (rsv_mm_info[j].used == 0) {
317                         mm_data->block_info[i].pfn = rsv_mm_info[j].pfn;
318                         mm_data->block_info[i].vir_addr =
319                                 rsv_mm_info[j].vir_addr;
320                         mm_data->block_info[i].mfn = rsv_mm_info[j].mfn;
321                         mm_data->block_info[i].exchange_flag =
322                                 rsv_mm_info[j].exchange_flag;
323                         mm_data->block_num[i] = j;
324                         rsv_mm_info[j].used = 1;
325                         i++;
326                 }
327                 j++;
328         }
329 }
330
331 /**
332  * Find all memory segments in which physical addresses are contiguous.
333  */
334 static void
335 find_memseg(int count, struct dom0_mm_data * mm_data)
336 {
337         int i = 0;
338         int j, k, idx = 0;
339         uint64_t zone_len, pfn, num_block;
340
341         while(i < count) {
342                 if (mm_data->block_info[i].exchange_flag == 0) {
343                         i++;
344                         continue;
345                 }
346                 k = 0;
347                 pfn = mm_data->block_info[i].pfn;
348                 mm_data->seg_info[idx].pfn = pfn;
349                 mm_data->seg_info[idx].mfn[k] = mm_data->block_info[i].mfn;
350
351                 for (j = i + 1; j < count; j++) {
352
353                         /* ignore exchange fail memory block */
354                         if (mm_data->block_info[j].exchange_flag == 0) 
355                                 break;
356                         
357                         if (mm_data->block_info[j].pfn != 
358                                 (mm_data->block_info[j - 1].pfn +
359                                          DOM0_MEMBLOCK_SIZE / PAGE_SIZE)) 
360                             break;
361                         ++k;
362                         mm_data->seg_info[idx].mfn[k] = mm_data->block_info[j].mfn;
363                 }
364
365                 num_block = j - i;
366                 zone_len = num_block * DOM0_MEMBLOCK_SIZE;
367                 mm_data->seg_info[idx].size = zone_len;
368                 
369                 XEN_PRINT("memseg id=%d, size=0x%llx\n", idx, zone_len);
370                 i = i+ num_block;
371                 idx++;
372                 if (idx == DOM0_NUM_MEMSEG)
373                         break;
374         }
375         mm_data->num_memseg = idx;
376 }
377
378 static int
379 dom0_memory_reserve(uint32_t rsv_size)
380 {
381         uint64_t pfn, vstart, vaddr;
382         uint32_t i, num_block, size, allocated_size = 0;
383
384         /* 2M as memory block */
385         num_block = rsv_size / SIZE_PER_BLOCK;
386
387         rsv_mm_info = vmalloc(sizeof(struct memblock_info) * num_block);
388         if (!rsv_mm_info) {
389                 XEN_ERR("Unable to allocate device memory information\n");
390                 return -ENOMEM;
391         }
392         memset(rsv_mm_info, 0, sizeof(struct memblock_info) * num_block);
393
394         /* try alloc size of 4M once */
395         for (i = 0; i < num_block; i += 2) {
396                 vstart = (unsigned long)
397                         __get_free_pages(GFP_ATOMIC, MAX_NUM_ORDER);
398                 if (vstart == 0)
399                         break;
400
401                 dom0_dev.num_bigblock = i / 2 + 1;
402                 allocated_size =  SIZE_PER_BLOCK * (i + 2);
403
404                 /* size of 4M */
405                 size = DOM0_MEMBLOCK_SIZE * 2;
406
407                 vaddr = vstart;
408                 while (size > 0) {
409                         SetPageReserved(virt_to_page(vaddr));
410                         vaddr += PAGE_SIZE;
411                         size -= PAGE_SIZE;
412                 }
413
414                 pfn = virt_to_pfn(vstart);
415                 rsv_mm_info[i].pfn = pfn;
416                 rsv_mm_info[i].vir_addr = vstart;
417                 rsv_mm_info[i + 1].pfn =
418                                 pfn + DOM0_MEMBLOCK_SIZE / PAGE_SIZE;
419                 rsv_mm_info[i + 1].vir_addr =
420                                 vstart + DOM0_MEMBLOCK_SIZE;
421         }
422
423         /*if it failed to alloc 4M, and continue to alloc 2M once */
424         for (; i < num_block; i++) {
425                 vstart = (unsigned long)
426                         __get_free_pages(GFP_ATOMIC, DOM0_CONTIG_NUM_ORDER);
427                 if (vstart == 0) {
428                         XEN_ERR("allocate memory fail.\n");
429                         dom0_memory_free(allocated_size);
430                         return -ENOMEM;
431                 }
432
433                 allocated_size += DOM0_MEMBLOCK_SIZE;
434
435                 size = DOM0_MEMBLOCK_SIZE;
436                 vaddr = vstart;
437                 while (size > 0) {
438                         SetPageReserved(virt_to_page(vaddr));
439                         vaddr += PAGE_SIZE;
440                         size -= PAGE_SIZE;
441                 }
442                 pfn = virt_to_pfn(vstart);
443                 rsv_mm_info[i].pfn = pfn;
444                 rsv_mm_info[i].vir_addr = vstart;
445         }
446
447         sort_viraddr(rsv_mm_info, num_block);
448         
449         for (i = 0; i< num_block; i++) {
450
451                 /*
452                  * This API is used to exchage MFN for getting a block of  
453                  * contiguous physical addresses, its maximum size is 2M.  
454                  */
455                 if (xen_create_contiguous_region(rsv_mm_info[i].vir_addr,
456                                     DOM0_CONTIG_NUM_ORDER, 0) == 0) {
457                         rsv_mm_info[i].exchange_flag = 1;
458                         rsv_mm_info[i].mfn =
459                                 pfn_to_mfn(rsv_mm_info[i].pfn);
460                         rsv_mm_info[i].used = 0;
461                 } else { 
462                         XEN_ERR("exchange memeory fail\n");
463                         rsv_mm_info[i].exchange_flag = 0;
464                         dom0_dev.fail_times++;
465                         if (dom0_dev.fail_times > MAX_EXCHANGE_FAIL_TIME) {
466                                 dom0_memory_free(rsv_size);
467                                 return  -EFAULT;
468                         }
469                 }
470         }
471         
472         return 0;
473 }
474
475 static int
476 dom0_prepare_memsegs(struct memory_info *meminfo, struct dom0_mm_data *mm_data)
477 {
478         uint32_t num_block;
479         int idx;
480
481         /* check if there is a free name buffer */
482         memcpy(mm_data->name, meminfo->name, DOM0_NAME_MAX);
483         mm_data->name[DOM0_NAME_MAX - 1] = '\0';
484         idx = dom0_find_mempos();
485         if (idx < 0)
486                 return -1;
487
488         num_block = meminfo->size / SIZE_PER_BLOCK;
489         /* find free memory and new memory segments*/
490         find_free_memory(num_block, mm_data);
491         find_memseg(num_block, mm_data);
492
493         /* update private memory data */
494         mm_data->refcnt++;
495         mm_data->mem_size = meminfo->size;
496
497         /* update global memory data */
498         dom0_dev.mm_data[idx] = mm_data;
499         dom0_dev.num_mem_ctx++;
500         dom0_dev.used_memsize += mm_data->mem_size;
501
502         return 0;
503 }
504
505 static int
506 dom0_check_memory (struct memory_info *meminfo)
507 {
508         int idx;
509         uint64_t mem_size;
510
511         /* round memory size to the next even number. */
512         if (meminfo->size % 2)
513                 ++meminfo->size;
514
515         mem_size = meminfo->size;
516         if (dom0_dev.num_mem_ctx > NUM_MEM_CTX) { 
517                 XEN_ERR("Memory data space is full in Dom0 driver\n");
518                 return -1;
519         }
520         idx = dom0_find_memdata(meminfo->name);
521         if (idx >= 0) { 
522                 XEN_ERR("Memory data name %s has already exsited in Dom0 driver.\n", 
523                         meminfo->name); 
524                 return -1;
525         }
526         if ((dom0_dev.used_memsize + mem_size) > rsv_memsize) {
527                 XEN_ERR("Total size can't be larger than reserved size.\n");
528                 return -1;
529         }
530
531         return 0;
532 }
533
534 static int __init
535 dom0_init(void)
536 {
537         if (!xen_domain())
538                 return -ENODEV;
539
540         if (rsv_memsize > DOM0_CONFIG_MEMSIZE) {
541                 XEN_ERR("The reserved memory size cannot be greater than %d\n",
542                         DOM0_CONFIG_MEMSIZE);
543                 return -EINVAL;
544         }
545
546         /* Setup the misc device */
547         dom0_dev.miscdev.minor = MISC_DYNAMIC_MINOR;
548         dom0_dev.miscdev.name = "dom0_mm";
549         dom0_dev.miscdev.fops = &data_fops;
550
551         /* register misc char device */
552         if (misc_register(&dom0_dev.miscdev) != 0) {
553                 XEN_ERR("Misc device registration failed\n");
554                 return -EPERM;
555         }
556         
557         mutex_init(&dom0_dev.data_lock);
558         dom0_kobj = kobject_create_and_add("dom0-mm", mm_kobj);
559
560         if (!dom0_kobj) {
561                 XEN_ERR("dom0-mm object creation failed\n");
562                 misc_deregister(&dom0_dev.miscdev);     
563                 return -ENOMEM;
564         }
565
566         if (sysfs_create_group(dom0_kobj, &dev_attr_grp)) {
567                 kobject_put(dom0_kobj);
568                 misc_deregister(&dom0_dev.miscdev);
569                 return -EPERM;
570         }
571
572         if (dom0_memory_reserve(rsv_memsize) < 0) {
573                 sysfs_remove_group(dom0_kobj, &dev_attr_grp);
574                 kobject_put(dom0_kobj);
575                 misc_deregister(&dom0_dev.miscdev);
576                 return -ENOMEM;
577         }
578         
579         XEN_PRINT("####### DPDK Xen Dom0 module loaded  #######\n");
580
581         return 0;
582 }
583
584 static void __exit
585 dom0_exit(void)
586 {
587         if (rsv_mm_info != NULL)
588                 dom0_memory_free(rsv_memsize);
589
590         sysfs_remove_group(dom0_kobj, &dev_attr_grp);
591         kobject_put(dom0_kobj);
592         misc_deregister(&dom0_dev.miscdev);
593
594         XEN_PRINT("####### DPDK Xen Dom0 module unloaded  #######\n");
595 }
596
597 static int
598 dom0_open(struct inode *inode, struct file *file)
599 {
600         file->private_data = NULL;
601
602         XEN_PRINT(KERN_INFO "/dev/dom0_mm opened\n");
603         return 0;
604 }
605
606 static int
607 dom0_release(struct inode *inode, struct file *file)
608 {
609         int ret = 0;
610         struct dom0_mm_data *mm_data = file->private_data;
611
612         if (mm_data == NULL)
613                 return ret;
614
615         mutex_lock(&dom0_dev.data_lock);
616         if (--mm_data->refcnt == 0) 
617                 ret = dom0_memory_release(mm_data);
618         mutex_unlock(&dom0_dev.data_lock);
619
620         file->private_data = NULL;
621         XEN_PRINT(KERN_INFO "/dev/dom0_mm closed\n");
622         return ret;
623 }
624
625 static int 
626 dom0_mmap(struct file *file, struct vm_area_struct *vm)
627 {
628         int status = 0;
629         uint32_t idx = vm->vm_pgoff;
630         uint64_t pfn, size = vm->vm_end - vm->vm_start;
631         struct dom0_mm_data *mm_data = file->private_data;
632
633         if(mm_data == NULL)
634                 return -EINVAL;
635
636         mutex_lock(&dom0_dev.data_lock);
637         if (idx >= mm_data->num_memseg) {
638                 mutex_unlock(&dom0_dev.data_lock);
639                 return -EINVAL;
640         }
641         
642         if (size > mm_data->seg_info[idx].size){
643                 mutex_unlock(&dom0_dev.data_lock);
644                 return -EINVAL;
645         }
646
647         XEN_PRINT("mmap memseg idx =%d,size = 0x%llx\n", idx, size);
648
649         pfn = mm_data->seg_info[idx].pfn;
650         mutex_unlock(&dom0_dev.data_lock);
651
652         status = remap_pfn_range(vm, vm->vm_start, pfn, size, PAGE_SHARED);
653
654         return status;
655 }
656 static int
657 dom0_ioctl(struct file *file,
658         unsigned int ioctl_num,
659         unsigned long ioctl_param)
660 {
661         int idx, ret;
662         char name[DOM0_NAME_MAX] = {0};
663         struct memory_info meminfo;
664         struct dom0_mm_data *mm_data = file->private_data;
665
666         XEN_PRINT("IOCTL num=0x%0x param=0x%0lx \n", ioctl_num, ioctl_param);
667
668         /**
669          * Switch according to the ioctl called
670          */
671         switch _IOC_NR(ioctl_num) {
672         case _IOC_NR(RTE_DOM0_IOCTL_PREPARE_MEMSEG):
673                 ret = copy_from_user(&meminfo, (void *)ioctl_param,
674                         sizeof(struct memory_info));
675                 if (ret)  
676                         return  -EFAULT;
677
678                 if (mm_data != NULL) {
679                         XEN_ERR("Cannot create memory segment for the same"
680                                 " file descriptor\n");
681                         return -EINVAL;
682                 }
683
684                 /* Allocate private data */
685                 mm_data = vmalloc(sizeof(struct dom0_mm_data));
686                 if (!mm_data) {
687                         XEN_ERR("Unable to allocate device private data\n");
688                         return -ENOMEM;
689                 }
690                 memset(mm_data, 0, sizeof(struct dom0_mm_data));
691
692                 mutex_lock(&dom0_dev.data_lock);
693                 /* check if we can allocate memory*/
694                 if (dom0_check_memory(&meminfo) < 0) {
695                         mutex_unlock(&dom0_dev.data_lock);
696                         vfree(mm_data);
697                         return -EINVAL;
698                 }
699
700                 /* allocate memory and created memory segments*/
701                 if (dom0_prepare_memsegs(&meminfo, mm_data) < 0) {
702                         XEN_ERR("create memory segment fail.\n");
703                         mutex_unlock(&dom0_dev.data_lock);
704                         return -EIO;
705                 }
706
707                 file->private_data = mm_data;
708                 mutex_unlock(&dom0_dev.data_lock);
709                 break;
710
711         /* support multiple process in term of memory mapping*/
712         case _IOC_NR(RTE_DOM0_IOCTL_ATTACH_TO_MEMSEG):
713                 ret = copy_from_user(name, (void *)ioctl_param,
714                                 sizeof(char) * DOM0_NAME_MAX);
715                 if (ret) 
716                         return -EFAULT;
717
718                 mutex_lock(&dom0_dev.data_lock);
719                 idx = dom0_find_memdata(name);
720                 if (idx < 0) {
721                         mutex_unlock(&dom0_dev.data_lock);
722                         return -EINVAL;
723                 }
724                 
725                 mm_data = dom0_dev.mm_data[idx];
726                 mm_data->refcnt++;
727                 file->private_data = mm_data;
728                 mutex_unlock(&dom0_dev.data_lock);
729                 break;
730
731         case _IOC_NR(RTE_DOM0_IOCTL_GET_NUM_MEMSEG):
732                 ret = copy_to_user((void *)ioctl_param, &mm_data->num_memseg, 
733                                 sizeof(int));
734                 if (ret)
735                         return -EFAULT;
736                 break;
737
738         case _IOC_NR(RTE_DOM0_IOCTL_GET_MEMSEG_INFO):
739                 ret = copy_to_user((void *)ioctl_param,
740                                 &mm_data->seg_info[0], 
741                                 sizeof(struct memseg_info) * 
742                                 mm_data->num_memseg);
743                 if (ret) 
744                         return -EFAULT;
745                 break;
746         default:
747                 XEN_PRINT("IOCTL default \n");
748                 break;
749         }
750         
751         return 0;
752 }
753
754 module_init(dom0_init);
755 module_exit(dom0_exit);
756
757 module_param(rsv_memsize, uint, S_IRUGO | S_IWUSR);
758 MODULE_PARM_DESC(rsv_memsize, "Xen-dom0 reserved memory size(MB).\n");