[Feature][ZXW-88]merge P50 version

Only Configure: No
Affected branch: master
Affected module: unknown
Is it affected on both ZXIC and MTK: only ZXIC
Self-test: Yes
Doc Update: No

Change-Id: I34667719d9e0e7e29e8e4368848601cde0a48408
diff --git a/ap/os/linux/linux-3.4.x/ipc/shm.c b/ap/os/linux/linux-3.4.x/ipc/shm.c
index 47d3255..8bf7f7b 100755
--- a/ap/os/linux/linux-3.4.x/ipc/shm.c
+++ b/ap/os/linux/linux-3.4.x/ipc/shm.c
@@ -72,11 +72,6 @@
 static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
 #endif
 
-#ifdef CONFIG_SYSVIPC_CROSS_SHM
-extern int shm_remote_free_pages(struct vm_area_struct *unmap_vma);
-extern int shm_do_remote_map_vma(struct vm_area_struct *vma, key_t key);
-#endif
-
 void shm_init_ns(struct ipc_namespace *ns)
 {
 	ns->shm_ctlmax = SHMMAX;
@@ -150,20 +145,50 @@
 }
 
 #ifdef CONFIG_SYSVIPC_CROSS_SHM
-void shm_mmap_pagetable(struct vm_area_struct *vma, struct file *file)
+key_t shm_do_remote_analy_key(struct file *file)
 {
-	int ret = 0;
+	key_t  key = 0;	
+	char   *shm_name = NULL;
 	struct shm_file_data *sfd;
 	struct shmid_kernel  *shp;
+	struct path    *shm_path  = NULL;
+	struct dentry  *shm_dentry = NULL;
 
-	sfd = shm_file_data(file);
-	shp = shm_lock(sfd->ns, sfd->id);
+	if (file && (file->shm_flags == SHM_REMOTE_SYSV_YES))
+	{
+		sfd = shm_file_data(file);
+		shp = shm_lock(sfd->ns, sfd->id);
+		key = shp->shm_perm.key;
+		shm_unlock(shp);
+	}
+	else if (file && (file->shm_flags == SHM_REMOTE_POSIX_YES))
+	{
+		shm_path = &file->f_path;
+		
+		if(shm_path && (shm_path->dentry))
+		{
+			shm_name = shm_path->dentry->d_name.name;
+			if (!shm_name)
+				panic("shm_posix_mmap_pagetable name is NULL\n");
+		}
+		key = shm_hash_name_to_key(shm_name, strlen(shm_name));
+	}
+	return key;
+}
 
-	ret = shm_do_remote_map_vma(vma, shp->shm_perm.key);
+int shm_ipc_mmap_pagetable(struct vm_area_struct *vma, struct file *file)
+{
+	int   ret = 0;
+	key_t shm_key = 0;
+		
+	shm_key = shm_do_remote_analy_key(file);
+	ret     = shm_do_remote_map_vma(vma, shm_key);
 	if (ret < 0)
-		printk("shm_mmap_pagetable Error");
-
-	shm_unlock(shp);
+	{
+		printk("shm_ipc_mmap_pagetable Error: No Mem\n");
+		return -ENOMEM;
+	}
+	return ret;
 }
 #endif
 
@@ -266,10 +291,7 @@
 	shp->shm_lprid = task_tgid_vnr(current);
 	shp->shm_dtim = get_seconds();
 	shp->shm_nattch--;
-#ifdef CONFIG_SYSVIPC_CROSS_SHM
-	if (shp->shm_perm.rpmflag == TRUE)
-		shm_remote_free_pages(shp->shm_perm.key);
-#endif
+
 	if (shm_may_destroy(ns, shp))
 		shm_destroy(ns, shp);
 	else
@@ -548,10 +570,21 @@
 	shp->shm_file = file;
 	shp->shm_creator = current;
 #ifdef CONFIG_SYSVIPC_CROSS_SHM
-	if((key & SHM_REMOTE_ATTR_MASK) == SHM_REMOTE_ATTR_MASK)
-		shp->shm_perm.rpmflag = TRUE;
+	if((key & SHM_REMOTE_SYSV_MASK) == SHM_REMOTE_SYSV_MASK)
+	{
+		error = shm_do_newseg_check(key, size);
+		if (error < 0)
+		{
+			printk("shm size error, should be the same PAGE_ALIGN size\n");
+			return error;
+		}
+		else
+			shp->shm_perm.rpmflag = TRUE;
+	}
 	else
+	{
 		shp->shm_perm.rpmflag = FALSE;
+	}
 #endif
 	/*
 	 * shmid gets reported as "inode#" in /proc/pid/maps.
@@ -1087,7 +1120,7 @@
 	sfd->vm_ops = NULL;
 #ifdef CONFIG_SYSVIPC_CROSS_SHM	
 	if(shp->shm_perm.rpmflag == TRUE)
-		file->f_flags = SHM_REMOTE_ATTR_YES;
+		file->shm_flags = SHM_REMOTE_SYSV_YES;
 #endif
 	down_write(&current->mm->mmap_sem);
 	if (addr && !(shmflg & SHM_REMAP)) {
diff --git a/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.c b/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.c
index 598cb28..183a8bd 100755
--- a/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.c
+++ b/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.c
@@ -23,6 +23,10 @@
 #define SHM_UNIT_BUFF_ORDER       (12)
 #define SHM_KEYS_STATUS_LEN       (4*1024)
 #define SHM_REMOTE_BUFF_LEN       (128*1024)
+#define SHM_POSIX_HASH_CHARS      (26)
+#define SHM_POSIX_HASH_BASE       (62)
+#define SHM_POSIX_HASH_MASK       (0x7FF)
+
 #define SHM_BUFF_BASE_PHY_ADDR    (g_shm_phyAddr)
  
 #define SHM_UNIT_BUFF_SIZE        (1UL<<SHM_UNIT_BUFF_ORDER) /*4KB*/
@@ -51,6 +55,36 @@
 struct shm_entity *shm_remote_manager;
 
 /*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_hash_name_to_key
+* ²ÎÊý˵Ã÷:
+*    (´«Èë²ÎÊý) name: ¹²ÏíÄÚ´æÃû³Æ
+*    (´«Èë²ÎÊý) len: ¹²ÏíÄÚ´æÃû³Æ³¤¶È
+*    (´«³ö²ÎÊý) ÎÞ
+* ·µ »Ø Öµ:     
+* ÆäËü˵Ã÷:     This function is used for calc hash value of the name(-2048~-4096)
+*******************************************************************************/
+key_t shm_hash_name_to_key(const char *name, int len)
+{
+    int   i        = 0;
+    key_t tmp_key  = 0;
+    key_t hash_key = 0;
+    unsigned long long id = 0;
+
+    for (; i < len; i++)
+    {
+        if (name[i] >= 'A' && name[i] <= 'Z')
+            id = id*SHM_POSIX_HASH_BASE + name[i]-'A';
+        else if (name[i] >= 'a' && name[i] <= 'z')
+            id = id*SHM_POSIX_HASH_BASE + name[i]-'a' + SHM_POSIX_HASH_CHARS;
+        else if (name[i] >= '0' && name[i] <= '9')
+            id = id*SHM_POSIX_HASH_BASE + name[i]-'0' + 2*SHM_POSIX_HASH_CHARS;
+    }
+    tmp_key =(id & SHM_POSIX_HASH_MASK) + (SHM_POSIX_HASH_MASK + 1);
+    hash_key = ~tmp_key + 1; 
+    return hash_key;
+}
+
+/*******************************************************************************
 * ¹¦ÄÜÃèÊö:     shm_quary_keyArray
 * ²ÎÊý˵Ã÷:
 *    (´«Èë²ÎÊý)    void
@@ -330,6 +364,58 @@
 }
 
 /*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_do_newseg_check
+* ²ÎÊý˵Ã÷:     
+*    (´«Èë²ÎÊý)    void
+*    (´«³ö²ÎÊý)    void
+* ·µ »Ø Öµ:     SHM_CTRL_OK or SHM_CTRL_ERROR
+* ÆäËü˵Ã÷:     This function is used for check key and len                    
+*******************************************************************************/
+int shm_do_newseg_check(key_t key, unsigned long len)
+{
+    int                  ret        = 0;
+    int                  key_index  = 0;
+    unsigned int         shm_weight = 0;
+    unsigned int         shm_pages  = 0;
+    struct shm_key_node  *key_node  = NULL;
+
+    if(g_shm_region == NULL)
+    {
+        printk("shm_do_newsg_check:Shm region is not ready\n");
+        return SHM_CTRL_ERROR;
+    }
+    soft_spin_lock(SHM_SFLOCK);
+
+    key_index = shm_quary_keyArray(key);
+
+    if (key_index < 0) 
+    {
+        soft_spin_unlock(SHM_SFLOCK);    
+        return SHM_CTRL_OK;
+    }
+    
+    if ((0 <= key_index) && (key_index < SHM_UNIT_NUM_BITS))
+    {
+        key_node = &shm_remote_manager->keys_info_head[key_index];
+    }
+    else
+    {
+        soft_spin_unlock(SHM_SFLOCK);
+        panic("key_index out of range: failed\n");
+    }
+
+    shm_pages  =  PAGE_ALIGN(len) >> PAGE_SHIFT;
+    shm_weight = bitmap_weight(key_node->shm_inuse_index, SHM_UNIT_NUM_BITS);
+    soft_spin_unlock(SHM_SFLOCK);
+
+    /*APºÍCAP¹²ÏíÄÚ´æ´óСӦƥÅä*/
+    if(shm_weight != shm_pages) 
+        return -EINVAL;
+    else
+        return SHM_CTRL_OK;
+}
+
+/*******************************************************************************
 * ¹¦ÄÜÃèÊö:     shm_do_remote_map_vma
 * ²ÎÊý˵Ã÷:     
 *    (´«Èë²ÎÊý)    void
@@ -374,9 +460,14 @@
     vm_addr = vma->vm_start;
     
     if ((0 <= key_index) && (key_index < SHM_UNIT_NUM_BITS))
+    {
         key_node = &shm_remote_manager->keys_info_head[key_index];
+    }
     else
+    {
+        soft_spin_unlock(SHM_SFLOCK);
         panic("key_index out of range: failed\n");
+    }
 
     memcpy(shm_inuse_tmp, key_node->shm_inuse_index, sizeof(shm_inuse_tmp));
 
diff --git a/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.h b/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.h
index 5a850a1..4726ea8 100755
--- a/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.h
+++ b/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.h
@@ -29,19 +29,24 @@
 #include <mach/spinlock.h>
 
 /**
- * Êý¾ÝÀàÐͶ¨Òå
- */
+ * ºê¶¨Òå
+*/
 #define TRUE   1
 #define FALSE  0
-#define SHM_REMOTE_ATTR_YES       (0x594553) /*YES ASCIIÂë*/
-#define SHM_REMOTE_ATTR_MASK      (0xFFFFF000)
+
 #define SHM_CTRL_OK               (0)
 #define SHM_CTRL_ERROR            (-1)
 #define SHM_CTRL_VMA_LINK_NUM     (2)
 #define SHM_CTRL_MEMSYNC_CHANNEL  (15)
 #define SHM_CTRL_CHANNEL_SIZE     (0x40)
 #define SHM_CTRL_LONG_32BIT       (32)
+#define SHM_REMOTE_SYSV_YES       (0x73797376) /*SYSV ASCIIÂë*/
+#define SHM_REMOTE_POSIX_YES      (0x706F7378)  /*POSX ASCIIÂë*/
+#define SHM_REMOTE_SYSV_MASK      (0xFFFFF800) /*(key:-1~-2047)*/
 
+/**
+ * Êý¾ÝÀàÐͶ¨Òå
+ */
 struct shm_pool_msg
 {
     unsigned int shm_len;
@@ -50,7 +55,12 @@
     phys_addr_t  key_manage_phy;
 };
 
-
+extern int shm_remote_free_pages(key_t key);
+extern key_t shm_hash_name_to_key(const char *name, int len);
+extern int shm_do_newseg_check(key_t key, unsigned long len);
+extern int shm_do_remote_map_vma(struct vm_area_struct *vma, key_t key);
+extern void shm_unmap_page_range(struct mm_struct *mm, struct vm_area_struct *vma,
+                                 unsigned long addr, unsigned long end);
 #endif
 #endif // _SHM_CTRL_H