LCOV - code coverage report
Current view: top level - drivers/char/broadcom/vc_sm - vmcs_sm.c (source / functions) Hit Total Coverage
Test: Real Lines: 61 1090 5.6 %
Date: 2020-10-17 15:46:43 Functions: 3 50 6.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  ****************************************************************************
       3                 :            :  * Copyright 2011-2012 Broadcom Corporation.  All rights reserved.
       4                 :            :  *
       5                 :            :  * Unless you and Broadcom execute a separate written software license
       6                 :            :  * agreement governing use of this software, this software is licensed to you
       7                 :            :  * under the terms of the GNU General Public License version 2, available at
       8                 :            :  * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
       9                 :            :  *
      10                 :            :  * Notwithstanding the above, under no circumstances may you combine this
      11                 :            :  * software in any way with any other Broadcom software provided under a
      12                 :            :  * license other than the GPL, without Broadcom's express prior written
      13                 :            :  * consent.
      14                 :            :  ****************************************************************************
      15                 :            :  */
      16                 :            : 
      17                 :            : /* ---- Include Files ----------------------------------------------------- */
      18                 :            : 
      19                 :            : #include <linux/cdev.h>
      20                 :            : #include <linux/broadcom/vc_mem.h>
      21                 :            : #include <linux/device.h>
      22                 :            : #include <linux/debugfs.h>
      23                 :            : #include <linux/dma-mapping.h>
      24                 :            : #include <linux/dma-buf.h>
      25                 :            : #include <linux/errno.h>
      26                 :            : #include <linux/fs.h>
      27                 :            : #include <linux/hugetlb.h>
      28                 :            : #include <linux/ioctl.h>
      29                 :            : #include <linux/kernel.h>
      30                 :            : #include <linux/list.h>
      31                 :            : #include <linux/module.h>
      32                 :            : #include <linux/mm.h>
      33                 :            : #include <linux/of.h>
      34                 :            : #include <linux/platform_device.h>
      35                 :            : #include <linux/pfn.h>
      36                 :            : #include <linux/proc_fs.h>
      37                 :            : #include <linux/pagemap.h>
      38                 :            : #include <linux/semaphore.h>
      39                 :            : #include <linux/slab.h>
      40                 :            : #include <linux/seq_file.h>
      41                 :            : #include <linux/types.h>
      42                 :            : #include <asm/cacheflush.h>
      43                 :            : 
      44                 :            : #include "vchiq_connected.h"
      45                 :            : #include "vc_vchi_sm.h"
      46                 :            : 
      47                 :            : #include <linux/broadcom/vmcs_sm_ioctl.h>
      48                 :            : #include "vc_sm_knl.h"
      49                 :            : 
      50                 :            : /* ---- Private Constants and Types --------------------------------------- */
      51                 :            : 
      52                 :            : #define DEVICE_NAME              "vcsm"
      53                 :            : #define DRIVER_NAME              "bcm2835-vcsm"
      54                 :            : #define DEVICE_MINOR             0
      55                 :            : 
      56                 :            : #define VC_SM_DIR_ROOT_NAME       "vc-smem"
      57                 :            : #define VC_SM_DIR_ALLOC_NAME      "alloc"
      58                 :            : #define VC_SM_STATE               "state"
      59                 :            : #define VC_SM_STATS               "statistics"
      60                 :            : #define VC_SM_RESOURCES           "resources"
      61                 :            : #define VC_SM_DEBUG               "debug"
      62                 :            : #define VC_SM_WRITE_BUF_SIZE      128
      63                 :            : 
      64                 :            : /* Statistics tracked per resource and globally. */
      65                 :            : enum sm_stats_t {
      66                 :            :         /* Attempt. */
      67                 :            :         ALLOC,
      68                 :            :         FREE,
      69                 :            :         LOCK,
      70                 :            :         UNLOCK,
      71                 :            :         MAP,
      72                 :            :         FLUSH,
      73                 :            :         INVALID,
      74                 :            :         IMPORT,
      75                 :            : 
      76                 :            :         END_ATTEMPT,
      77                 :            : 
      78                 :            :         /* Failure. */
      79                 :            :         ALLOC_FAIL,
      80                 :            :         FREE_FAIL,
      81                 :            :         LOCK_FAIL,
      82                 :            :         UNLOCK_FAIL,
      83                 :            :         MAP_FAIL,
      84                 :            :         FLUSH_FAIL,
      85                 :            :         INVALID_FAIL,
      86                 :            :         IMPORT_FAIL,
      87                 :            : 
      88                 :            :         END_ALL,
      89                 :            : 
      90                 :            : };
      91                 :            : 
      92                 :            : static const char *const sm_stats_human_read[] = {
      93                 :            :         "Alloc",
      94                 :            :         "Free",
      95                 :            :         "Lock",
      96                 :            :         "Unlock",
      97                 :            :         "Map",
      98                 :            :         "Cache Flush",
      99                 :            :         "Cache Invalidate",
     100                 :            :         "Import",
     101                 :            : };
     102                 :            : 
     103                 :            : typedef int (*VC_SM_SHOW) (struct seq_file *s, void *v);
     104                 :            : struct sm_pde_t {
     105                 :            :         VC_SM_SHOW show;          /* Debug fs function hookup. */
     106                 :            :         struct dentry *dir_entry; /* Debug fs directory entry. */
     107                 :            :         void *priv_data;          /* Private data */
     108                 :            : 
     109                 :            : };
     110                 :            : 
     111                 :            : /* Single resource allocation tracked for all devices. */
     112                 :            : struct sm_mmap {
     113                 :            :         struct list_head map_list;      /* Linked list of maps. */
     114                 :            : 
     115                 :            :         struct sm_resource_t *resource; /* Pointer to the resource. */
     116                 :            : 
     117                 :            :         pid_t res_pid;                  /* PID owning that resource. */
     118                 :            :         unsigned int res_vc_hdl;        /* Resource handle (videocore). */
     119                 :            :         unsigned int res_usr_hdl;       /* Resource handle (user). */
     120                 :            : 
     121                 :            :         unsigned long res_addr; /* Mapped virtual address. */
     122                 :            :         struct vm_area_struct *vma;     /* VM area for this mapping. */
     123                 :            :         unsigned int ref_count;         /* Reference count to this vma. */
     124                 :            : 
     125                 :            :         /* Used to link maps associated with a resource. */
     126                 :            :         struct list_head resource_map_list;
     127                 :            : };
     128                 :            : 
     129                 :            : /* Single resource allocation tracked for each opened device. */
     130                 :            : struct sm_resource_t {
     131                 :            :         struct list_head resource_list; /* List of resources. */
     132                 :            :         struct list_head global_resource_list;  /* Global list of resources. */
     133                 :            : 
     134                 :            :         pid_t pid;              /* PID owning that resource. */
     135                 :            :         uint32_t res_guid;      /* Unique identifier. */
     136                 :            :         uint32_t lock_count;    /* Lock count for this resource. */
     137                 :            :         uint32_t ref_count;     /* Ref count for this resource. */
     138                 :            : 
     139                 :            :         uint32_t res_handle;    /* Resource allocation handle. */
     140                 :            :         void *res_base_mem;     /* Resource base memory address. */
     141                 :            :         uint32_t res_size;      /* Resource size allocated. */
     142                 :            :         enum vmcs_sm_cache_e res_cached;        /* Resource cache type. */
     143                 :            :         struct sm_resource_t *res_shared;       /* Shared resource */
     144                 :            : 
     145                 :            :         enum sm_stats_t res_stats[END_ALL];     /* Resource statistics. */
     146                 :            : 
     147                 :            :         uint8_t map_count;      /* Counter of mappings for this resource. */
     148                 :            :         struct list_head map_list;      /* Maps associated with a resource. */
     149                 :            : 
     150                 :            :         /* DMABUF related fields */
     151                 :            :         struct dma_buf *dma_buf;
     152                 :            :         struct dma_buf_attachment *attach;
     153                 :            :         struct sg_table *sgt;
     154                 :            :         dma_addr_t dma_addr;
     155                 :            : 
     156                 :            :         struct sm_priv_data_t *private;
     157                 :            :         bool map;               /* whether to map pages up front */
     158                 :            : };
     159                 :            : 
     160                 :            : /* Private file data associated with each opened device. */
     161                 :            : struct sm_priv_data_t {
     162                 :            :         struct list_head resource_list; /* List of resources. */
     163                 :            : 
     164                 :            :         pid_t pid;                      /* PID of creator. */
     165                 :            : 
     166                 :            :         struct dentry *dir_pid;    /* Debug fs entries root. */
     167                 :            :         struct sm_pde_t dir_stats; /* Debug fs entries statistics sub-tree. */
     168                 :            :         struct sm_pde_t dir_res;   /* Debug fs resource sub-tree. */
     169                 :            : 
     170                 :            :         int restart_sys;           /* Tracks restart on interrupt. */
     171                 :            :         enum vc_sm_msg_type int_action; /* Interrupted action. */
     172                 :            :         uint32_t int_trans_id;     /* Interrupted transaction. */
     173                 :            : 
     174                 :            : };
     175                 :            : 
     176                 :            : /* Global state information. */
     177                 :            : struct sm_state_t {
     178                 :            :         struct platform_device *pdev;
     179                 :            :         struct sm_instance *sm_handle;  /* Handle for videocore service. */
     180                 :            :         struct dentry *dir_root;   /* Debug fs entries root. */
     181                 :            :         struct dentry *dir_alloc;  /* Debug fs entries allocations. */
     182                 :            :         struct sm_pde_t dir_stats; /* Debug fs entries statistics sub-tree. */
     183                 :            :         struct sm_pde_t dir_state; /* Debug fs entries state sub-tree. */
     184                 :            :         struct dentry *debug;      /* Debug fs entries debug. */
     185                 :            : 
     186                 :            :         struct mutex map_lock;          /* Global map lock. */
     187                 :            :         struct list_head map_list;      /* List of maps. */
     188                 :            :         struct list_head resource_list; /* List of resources. */
     189                 :            : 
     190                 :            :         enum sm_stats_t deceased[END_ALL];    /* Natural termination stats. */
     191                 :            :         enum sm_stats_t terminated[END_ALL];  /* Forced termination stats. */
     192                 :            :         uint32_t res_deceased_cnt;            /* Natural termination counter. */
     193                 :            :         uint32_t res_terminated_cnt;          /* Forced termination counter. */
     194                 :            : 
     195                 :            :         struct cdev sm_cdev;    /* Device. */
     196                 :            :         dev_t sm_devid;         /* Device identifier. */
     197                 :            :         struct class *sm_class; /* Class. */
     198                 :            :         struct device *sm_dev;  /* Device. */
     199                 :            : 
     200                 :            :         struct sm_priv_data_t *data_knl;    /* Kernel internal data tracking. */
     201                 :            : 
     202                 :            :         struct mutex lock;      /* Global lock. */
     203                 :            :         uint32_t guid;          /* GUID (next) tracker. */
     204                 :            : 
     205                 :            : };
     206                 :            : 
     207                 :            : /* ---- Private Variables ----------------------------------------------- */
     208                 :            : 
     209                 :            : static struct sm_state_t *sm_state;
     210                 :            : static int sm_inited;
     211                 :            : 
     212                 :            : #if 0
     213                 :            : static const char *const sm_cache_map_vector[] = {
     214                 :            :         "(null)",
     215                 :            :         "host",
     216                 :            :         "videocore",
     217                 :            :         "host+videocore",
     218                 :            : };
     219                 :            : #endif
     220                 :            : 
     221                 :            : /* ---- Private Function Prototypes -------------------------------------- */
     222                 :            : 
     223                 :            : /* ---- Private Functions ------------------------------------------------ */
     224                 :            : 
     225                 :            : static inline unsigned int vcaddr_to_pfn(unsigned long vc_addr)
     226                 :            : {
     227                 :            :         unsigned long pfn = vc_addr & 0x3FFFFFFF;
     228                 :            : 
     229                 :            :         pfn += mm_vc_mem_phys_addr;
     230                 :            :         pfn >>= PAGE_SHIFT;
     231                 :            :         return pfn;
     232                 :            : }
     233                 :            : 
     234                 :            : /*
     235                 :            :  * Carries over to the state statistics the statistics once owned by a deceased
     236                 :            :  * resource.
     237                 :            :  */
     238                 :          0 : static void vc_sm_resource_deceased(struct sm_resource_t *p_res, int terminated)
     239                 :            : {
     240                 :          0 :         if (sm_state != NULL) {
     241                 :          0 :                 if (p_res != NULL) {
     242                 :            :                         int ix;
     243                 :            : 
     244                 :          0 :                         if (terminated)
     245                 :          0 :                                 sm_state->res_terminated_cnt++;
     246                 :            :                         else
     247                 :          0 :                                 sm_state->res_deceased_cnt++;
     248                 :            : 
     249                 :          0 :                         for (ix = 0; ix < END_ALL; ix++) {
     250                 :          0 :                                 if (terminated)
     251                 :          0 :                                         sm_state->terminated[ix] +=
     252                 :          0 :                                             p_res->res_stats[ix];
     253                 :            :                                 else
     254                 :          0 :                                         sm_state->deceased[ix] +=
     255                 :          0 :                                             p_res->res_stats[ix];
     256                 :            :                         }
     257                 :            :                 }
     258                 :            :         }
     259                 :          0 : }
     260                 :            : 
     261                 :            : /*
     262                 :            :  * Fetch a videocore handle corresponding to a mapping of the pid+address
     263                 :            :  * returns 0 (ie NULL) if no such handle exists in the global map.
     264                 :            :  */
     265                 :          0 : static unsigned int vmcs_sm_vc_handle_from_pid_and_address(unsigned int pid,
     266                 :            :                                                            unsigned int addr)
     267                 :            : {
     268                 :            :         struct sm_mmap *map = NULL;
     269                 :            :         unsigned int handle = 0;
     270                 :            : 
     271                 :          0 :         if (!sm_state || addr == 0)
     272                 :            :                 goto out;
     273                 :            : 
     274                 :          0 :         mutex_lock(&(sm_state->map_lock));
     275                 :            : 
     276                 :            :         /* Lookup the resource. */
     277                 :          0 :         if (!list_empty(&sm_state->map_list)) {
     278                 :          0 :                 list_for_each_entry(map, &sm_state->map_list, map_list) {
     279                 :          0 :                         if (map->res_pid != pid)
     280                 :          0 :                                 continue;
     281                 :          0 :                         if (addr < map->res_addr ||
     282                 :          0 :                                                 addr >= (map->res_addr + map->resource->res_size))
     283                 :          0 :                                 continue;
     284                 :            : 
     285                 :            :                         pr_debug("[%s]: global map %p (pid %u, addr %lx) -> vc-hdl %x (usr-hdl %x)\n",
     286                 :            :                                 __func__, map, map->res_pid, map->res_addr,
     287                 :            :                                 map->res_vc_hdl, map->res_usr_hdl);
     288                 :            : 
     289                 :          0 :                         handle = map->res_vc_hdl;
     290                 :          0 :                         break;
     291                 :            :                 }
     292                 :            :         }
     293                 :            : 
     294                 :          0 :         mutex_unlock(&(sm_state->map_lock));
     295                 :            : 
     296                 :            : out:
     297                 :            :         /*
     298                 :            :          * Use a debug log here as it may be a valid situation that we query
     299                 :            :          * for something that is not mapped, we do not want a kernel log each
     300                 :            :          * time around.
     301                 :            :          *
     302                 :            :          * There are other error log that would pop up accordingly if someone
     303                 :            :          * subsequently tries to use something invalid after being told not to
     304                 :            :          * use it...
     305                 :            :          */
     306                 :            :         if (handle == 0) {
     307                 :            :                 pr_debug("[%s]: not a valid map (pid %u, addr %x)\n",
     308                 :            :                         __func__, pid, addr);
     309                 :            :         }
     310                 :            : 
     311                 :          0 :         return handle;
     312                 :            : }
     313                 :            : 
     314                 :            : /*
     315                 :            :  * Fetch a user handle corresponding to a mapping of the pid+address
     316                 :            :  * returns 0 (ie NULL) if no such handle exists in the global map.
     317                 :            :  */
     318                 :          0 : static unsigned int vmcs_sm_usr_handle_from_pid_and_address(unsigned int pid,
     319                 :            :                                                             unsigned int addr)
     320                 :            : {
     321                 :            :         struct sm_mmap *map = NULL;
     322                 :            :         unsigned int handle = 0;
     323                 :            : 
     324                 :          0 :         if (!sm_state || addr == 0)
     325                 :            :                 goto out;
     326                 :            : 
     327                 :          0 :         mutex_lock(&(sm_state->map_lock));
     328                 :            : 
     329                 :            :         /* Lookup the resource. */
     330                 :          0 :         if (!list_empty(&sm_state->map_list)) {
     331                 :          0 :                 list_for_each_entry(map, &sm_state->map_list, map_list) {
     332                 :          0 :                         if (map->res_pid != pid)
     333                 :          0 :                                 continue;
     334                 :          0 :                         if (addr < map->res_addr ||
     335                 :          0 :                                                 addr >= (map->res_addr + map->resource->res_size))
     336                 :          0 :                                 continue;
     337                 :            : 
     338                 :            :                         pr_debug("[%s]: global map %p (pid %u, addr %lx) -> usr-hdl %x (vc-hdl %x)\n",
     339                 :            :                                 __func__, map, map->res_pid, map->res_addr,
     340                 :            :                                 map->res_usr_hdl, map->res_vc_hdl);
     341                 :            : 
     342                 :          0 :                         handle = map->res_usr_hdl;
     343                 :          0 :                         break;
     344                 :            :                 }
     345                 :            :         }
     346                 :            : 
     347                 :          0 :         mutex_unlock(&(sm_state->map_lock));
     348                 :            : 
     349                 :            : out:
     350                 :            :         /*
     351                 :            :          * Use a debug log here as it may be a valid situation that we query
     352                 :            :          * for something that is not mapped yet.
     353                 :            :          *
     354                 :            :          * There are other error log that would pop up accordingly if someone
     355                 :            :          * subsequently tries to use something invalid after being told not to
     356                 :            :          * use it...
     357                 :            :          */
     358                 :            :         if (handle == 0)
     359                 :            :                 pr_debug("[%s]: not a valid map (pid %u, addr %x)\n",
     360                 :            :                         __func__, pid, addr);
     361                 :            : 
     362                 :          0 :         return handle;
     363                 :            : }
     364                 :            : 
     365                 :            : #if defined(DO_NOT_USE)
     366                 :            : /*
     367                 :            :  * Fetch an address corresponding to a mapping of the pid+handle
     368                 :            :  * returns 0 (ie NULL) if no such address exists in the global map.
     369                 :            :  */
     370                 :            : static unsigned int vmcs_sm_usr_address_from_pid_and_vc_handle(unsigned int pid,
     371                 :            :                                                                unsigned int hdl)
     372                 :            : {
     373                 :            :         struct sm_mmap *map = NULL;
     374                 :            :         unsigned int addr = 0;
     375                 :            : 
     376                 :            :         if (sm_state == NULL || hdl == 0)
     377                 :            :                 goto out;
     378                 :            : 
     379                 :            :         mutex_lock(&(sm_state->map_lock));
     380                 :            : 
     381                 :            :         /* Lookup the resource. */
     382                 :            :         if (!list_empty(&sm_state->map_list)) {
     383                 :            :                 list_for_each_entry(map, &sm_state->map_list, map_list) {
     384                 :            :                         if (map->res_pid != pid || map->res_vc_hdl != hdl)
     385                 :            :                                 continue;
     386                 :            : 
     387                 :            :                         pr_debug("[%s]: global map %p (pid %u, vc-hdl %x, usr-hdl %x) -> addr %lx\n",
     388                 :            :                                 __func__, map, map->res_pid, map->res_vc_hdl,
     389                 :            :                                 map->res_usr_hdl, map->res_addr);
     390                 :            : 
     391                 :            :                         addr = map->res_addr;
     392                 :            :                         break;
     393                 :            :                 }
     394                 :            :         }
     395                 :            : 
     396                 :            :         mutex_unlock(&(sm_state->map_lock));
     397                 :            : 
     398                 :            : out:
     399                 :            :         /*
     400                 :            :          * Use a debug log here as it may be a valid situation that we query
     401                 :            :          * for something that is not mapped, we do not want a kernel log each
     402                 :            :          * time around.
     403                 :            :          *
     404                 :            :          * There are other error log that would pop up accordingly if someone
     405                 :            :          * subsequently tries to use something invalid after being told not to
     406                 :            :          * use it...
     407                 :            :          */
     408                 :            :         if (addr == 0)
     409                 :            :                 pr_debug("[%s]: not a valid map (pid %u, hdl %x)\n",
     410                 :            :                         __func__, pid, hdl);
     411                 :            : 
     412                 :            :         return addr;
     413                 :            : }
     414                 :            : #endif
     415                 :            : 
     416                 :            : /*
     417                 :            :  * Fetch an address corresponding to a mapping of the pid+handle
     418                 :            :  * returns 0 (ie NULL) if no such address exists in the global map.
     419                 :            :  */
     420                 :          0 : static unsigned int vmcs_sm_usr_address_from_pid_and_usr_handle(unsigned int
     421                 :            :                                                                 pid,
     422                 :            :                                                                 unsigned int
     423                 :            :                                                                 hdl)
     424                 :            : {
     425                 :            :         struct sm_mmap *map = NULL;
     426                 :            :         unsigned int addr = 0;
     427                 :            : 
     428                 :          0 :         if (sm_state == NULL || hdl == 0)
     429                 :            :                 goto out;
     430                 :            : 
     431                 :          0 :         mutex_lock(&(sm_state->map_lock));
     432                 :            : 
     433                 :            :         /* Lookup the resource. */
     434                 :          0 :         if (!list_empty(&sm_state->map_list)) {
     435                 :          0 :                 list_for_each_entry(map, &sm_state->map_list, map_list) {
     436                 :          0 :                         if (map->res_pid != pid || map->res_usr_hdl != hdl)
     437                 :          0 :                                 continue;
     438                 :            : 
     439                 :            :                         pr_debug("[%s]: global map %p (pid %u, vc-hdl %x, usr-hdl %x) -> addr %lx\n",
     440                 :            :                                 __func__, map, map->res_pid, map->res_vc_hdl,
     441                 :            :                                 map->res_usr_hdl, map->res_addr);
     442                 :            : 
     443                 :          0 :                         addr = map->res_addr;
     444                 :          0 :                         break;
     445                 :            :                 }
     446                 :            :         }
     447                 :            : 
     448                 :          0 :         mutex_unlock(&(sm_state->map_lock));
     449                 :            : 
     450                 :            : out:
     451                 :            :         /*
     452                 :            :          * Use a debug log here as it may be a valid situation that we query
     453                 :            :          * for something that is not mapped, we do not want a kernel log each
     454                 :            :          * time around.
     455                 :            :          *
     456                 :            :          * There are other error log that would pop up accordingly if someone
     457                 :            :          * subsequently tries to use something invalid after being told not to
     458                 :            :          * use it...
     459                 :            :          */
     460                 :            :         if (addr == 0)
     461                 :            :                 pr_debug("[%s]: not a valid map (pid %u, hdl %x)\n", __func__,
     462                 :            :                                 pid, hdl);
     463                 :            : 
     464                 :          0 :         return addr;
     465                 :            : }
     466                 :            : 
     467                 :            : /* Adds a resource mapping to the global data list. */
     468                 :          0 : static void vmcs_sm_add_map(struct sm_state_t *state,
     469                 :            :                             struct sm_resource_t *resource, struct sm_mmap *map)
     470                 :            : {
     471                 :          0 :         mutex_lock(&(state->map_lock));
     472                 :            : 
     473                 :            :         /* Add to the global list of mappings */
     474                 :          0 :         list_add(&map->map_list, &state->map_list);
     475                 :            : 
     476                 :            :         /* Add to the list of mappings for this resource */
     477                 :          0 :         list_add(&map->resource_map_list, &resource->map_list);
     478                 :          0 :         resource->map_count++;
     479                 :            : 
     480                 :          0 :         mutex_unlock(&(state->map_lock));
     481                 :            : 
     482                 :            :         pr_debug("[%s]: added map %p (pid %u, vc-hdl %x, usr-hdl %x, addr %lx)\n",
     483                 :            :                 __func__, map, map->res_pid, map->res_vc_hdl,
     484                 :            :                 map->res_usr_hdl, map->res_addr);
     485                 :          0 : }
     486                 :            : 
     487                 :            : /* Removes a resource mapping from the global data list. */
     488                 :          0 : static void vmcs_sm_remove_map(struct sm_state_t *state,
     489                 :            :                                struct sm_resource_t *resource,
     490                 :            :                                struct sm_mmap *map)
     491                 :            : {
     492                 :          0 :         mutex_lock(&(state->map_lock));
     493                 :            : 
     494                 :            :         /* Remove from the global list of mappings */
     495                 :            :         list_del(&map->map_list);
     496                 :            : 
     497                 :            :         /* Remove from the list of mapping for this resource */
     498                 :            :         list_del(&map->resource_map_list);
     499                 :          0 :         if (resource->map_count > 0)
     500                 :          0 :                 resource->map_count--;
     501                 :            : 
     502                 :          0 :         mutex_unlock(&(state->map_lock));
     503                 :            : 
     504                 :            :         pr_debug("[%s]: removed map %p (pid %d, vc-hdl %x, usr-hdl %x, addr %lx)\n",
     505                 :            :                 __func__, map, map->res_pid, map->res_vc_hdl, map->res_usr_hdl,
     506                 :            :                 map->res_addr);
     507                 :            : 
     508                 :          0 :         kfree(map);
     509                 :          0 : }
     510                 :            : 
     511                 :            : /* Read callback for the global state proc entry. */
     512                 :          0 : static int vc_sm_global_state_show(struct seq_file *s, void *v)
     513                 :            : {
     514                 :            :         struct sm_mmap *map = NULL;
     515                 :            :         struct sm_resource_t *resource = NULL;
     516                 :            :         int map_count = 0;
     517                 :            :         int resource_count = 0;
     518                 :            : 
     519                 :          0 :         if (sm_state == NULL)
     520                 :            :                 return 0;
     521                 :            : 
     522                 :          0 :         seq_printf(s, "\nVC-ServiceHandle     0x%x\n",
     523                 :          0 :                    (unsigned int)sm_state->sm_handle);
     524                 :            : 
     525                 :            :         /* Log all applicable mapping(s). */
     526                 :            : 
     527                 :          0 :         mutex_lock(&(sm_state->map_lock));
     528                 :          0 :         seq_puts(s, "\nResources\n");
     529                 :          0 :         if (!list_empty(&sm_state->resource_list)) {
     530                 :          0 :                 list_for_each_entry(resource, &sm_state->resource_list,
     531                 :            :                                     global_resource_list) {
     532                 :          0 :                         resource_count++;
     533                 :            : 
     534                 :          0 :                         seq_printf(s, "\nResource                %p\n",
     535                 :            :                                    resource);
     536                 :          0 :                         seq_printf(s, "           PID          %u\n",
     537                 :            :                                    resource->pid);
     538                 :          0 :                         seq_printf(s, "           RES_GUID     0x%x\n",
     539                 :            :                                    resource->res_guid);
     540                 :          0 :                         seq_printf(s, "           LOCK_COUNT   %u\n",
     541                 :            :                                    resource->lock_count);
     542                 :          0 :                         seq_printf(s, "           REF_COUNT    %u\n",
     543                 :            :                                    resource->ref_count);
     544                 :          0 :                         seq_printf(s, "           res_handle   0x%X\n",
     545                 :            :                                    resource->res_handle);
     546                 :          0 :                         seq_printf(s, "           res_base_mem %p\n",
     547                 :            :                                    resource->res_base_mem);
     548                 :          0 :                         seq_printf(s, "           SIZE         %d\n",
     549                 :            :                                    resource->res_size);
     550                 :          0 :                         seq_printf(s, "           DMABUF       %p\n",
     551                 :            :                                    resource->dma_buf);
     552                 :          0 :                         seq_printf(s, "           ATTACH       %p\n",
     553                 :            :                                    resource->attach);
     554                 :          0 :                         seq_printf(s, "           SGT          %p\n",
     555                 :            :                                    resource->sgt);
     556                 :          0 :                         seq_printf(s, "           DMA_ADDR     %pad\n",
     557                 :            :                                    &resource->dma_addr);
     558                 :            :                 }
     559                 :            :         }
     560                 :          0 :         seq_printf(s, "\n\nTotal resource count:   %d\n\n", resource_count);
     561                 :            : 
     562                 :          0 :         seq_puts(s, "\nMappings\n");
     563                 :          0 :         if (!list_empty(&sm_state->map_list)) {
     564                 :          0 :                 list_for_each_entry(map, &sm_state->map_list, map_list) {
     565                 :          0 :                         map_count++;
     566                 :            : 
     567                 :          0 :                         seq_printf(s, "\nMapping                0x%x\n",
     568                 :            :                                    (unsigned int)map);
     569                 :          0 :                         seq_printf(s, "           TGID        %u\n",
     570                 :            :                                    map->res_pid);
     571                 :          0 :                         seq_printf(s, "           VC-HDL      0x%x\n",
     572                 :            :                                    map->res_vc_hdl);
     573                 :          0 :                         seq_printf(s, "           USR-HDL     0x%x\n",
     574                 :            :                                    map->res_usr_hdl);
     575                 :          0 :                         seq_printf(s, "           USR-ADDR    0x%lx\n",
     576                 :            :                                    map->res_addr);
     577                 :          0 :                         seq_printf(s, "           SIZE        %d\n",
     578                 :          0 :                                    map->resource->res_size);
     579                 :            :                 }
     580                 :            :         }
     581                 :            : 
     582                 :          0 :         mutex_unlock(&(sm_state->map_lock));
     583                 :          0 :         seq_printf(s, "\n\nTotal map count:   %d\n\n", map_count);
     584                 :            : 
     585                 :          0 :         return 0;
     586                 :            : }
     587                 :            : 
     588                 :          0 : static int vc_sm_global_statistics_show(struct seq_file *s, void *v)
     589                 :            : {
     590                 :            :         int ix;
     591                 :            : 
     592                 :            :         /* Global state tracked statistics. */
     593                 :          0 :         if (sm_state != NULL) {
     594                 :          0 :                 seq_puts(s, "\nDeceased Resources Statistics\n");
     595                 :            : 
     596                 :          0 :                 seq_printf(s, "\nNatural Cause (%u occurences)\n",
     597                 :          0 :                            sm_state->res_deceased_cnt);
     598                 :          0 :                 for (ix = 0; ix < END_ATTEMPT; ix++) {
     599                 :          0 :                         if (sm_state->deceased[ix] > 0) {
     600                 :          0 :                                 seq_printf(s, "                %u\t%s\n",
     601                 :            :                                            sm_state->deceased[ix],
     602                 :            :                                            sm_stats_human_read[ix]);
     603                 :            :                         }
     604                 :            :                 }
     605                 :          0 :                 seq_puts(s, "\n");
     606                 :          0 :                 for (ix = 0; ix < END_ATTEMPT; ix++) {
     607                 :          0 :                         if (sm_state->deceased[ix + END_ATTEMPT] > 0) {
     608                 :          0 :                                 seq_printf(s, "                %u\tFAILED %s\n",
     609                 :            :                                            sm_state->deceased[ix + END_ATTEMPT],
     610                 :            :                                            sm_stats_human_read[ix]);
     611                 :            :                         }
     612                 :            :                 }
     613                 :            : 
     614                 :          0 :                 seq_printf(s, "\nForcefull (%u occurences)\n",
     615                 :          0 :                            sm_state->res_terminated_cnt);
     616                 :          0 :                 for (ix = 0; ix < END_ATTEMPT; ix++) {
     617                 :          0 :                         if (sm_state->terminated[ix] > 0) {
     618                 :          0 :                                 seq_printf(s, "                %u\t%s\n",
     619                 :            :                                            sm_state->terminated[ix],
     620                 :            :                                            sm_stats_human_read[ix]);
     621                 :            :                         }
     622                 :            :                 }
     623                 :          0 :                 seq_puts(s, "\n");
     624                 :          0 :                 for (ix = 0; ix < END_ATTEMPT; ix++) {
     625                 :          0 :                         if (sm_state->terminated[ix + END_ATTEMPT] > 0) {
     626                 :          0 :                                 seq_printf(s, "                %u\tFAILED %s\n",
     627                 :            :                                            sm_state->terminated[ix +
     628                 :            :                                                                 END_ATTEMPT],
     629                 :            :                                            sm_stats_human_read[ix]);
     630                 :            :                         }
     631                 :            :                 }
     632                 :            :         }
     633                 :            : 
     634                 :          0 :         return 0;
     635                 :            : }
     636                 :            : 
     637                 :            : #if 0
     638                 :            : /* Read callback for the statistics proc entry. */
     639                 :            : static int vc_sm_statistics_show(struct seq_file *s, void *v)
     640                 :            : {
     641                 :            :         int ix;
     642                 :            :         struct sm_priv_data_t *file_data;
     643                 :            :         struct sm_resource_t *resource;
     644                 :            :         int res_count = 0;
     645                 :            :         struct sm_pde_t *p_pde;
     646                 :            : 
     647                 :            :         p_pde = (struct sm_pde_t *)(s->private);
     648                 :            :         file_data = (struct sm_priv_data_t *)(p_pde->priv_data);
     649                 :            : 
     650                 :            :         if (file_data == NULL)
     651                 :            :                 return 0;
     652                 :            : 
     653                 :            :         /* Per process statistics. */
     654                 :            : 
     655                 :            :         seq_printf(s, "\nStatistics for TGID %d\n", file_data->pid);
     656                 :            : 
     657                 :            :         mutex_lock(&(sm_state->map_lock));
     658                 :            : 
     659                 :            :         if (!list_empty(&file_data->resource_list)) {
     660                 :            :                 list_for_each_entry(resource, &file_data->resource_list,
     661                 :            :                                     resource_list) {
     662                 :            :                         res_count++;
     663                 :            : 
     664                 :            :                         seq_printf(s, "\nGUID:         0x%x\n\n",
     665                 :            :                                    resource->res_guid);
     666                 :            :                         for (ix = 0; ix < END_ATTEMPT; ix++) {
     667                 :            :                                 if (resource->res_stats[ix] > 0) {
     668                 :            :                                         seq_printf(s,
     669                 :            :                                                    "                %u\t%s\n",
     670                 :            :                                                    resource->res_stats[ix],
     671                 :            :                                                    sm_stats_human_read[ix]);
     672                 :            :                                 }
     673                 :            :                         }
     674                 :            :                         seq_puts(s, "\n");
     675                 :            :                         for (ix = 0; ix < END_ATTEMPT; ix++) {
     676                 :            :                                 if (resource->res_stats[ix + END_ATTEMPT] > 0) {
     677                 :            :                                         seq_printf(s,
     678                 :            :                                                    "                %u\tFAILED %s\n",
     679                 :            :                                                    resource->res_stats[
     680                 :            :                                                    ix + END_ATTEMPT],
     681                 :            :                                                    sm_stats_human_read[ix]);
     682                 :            :                                 }
     683                 :            :                         }
     684                 :            :                 }
     685                 :            :         }
     686                 :            : 
     687                 :            :         mutex_unlock(&(sm_state->map_lock));
     688                 :            : 
     689                 :            :         seq_printf(s, "\nResources Count %d\n", res_count);
     690                 :            : 
     691                 :            :         return 0;
     692                 :            : }
     693                 :            : #endif
     694                 :            : 
     695                 :            : #if 0
     696                 :            : /* Read callback for the allocation proc entry.  */
     697                 :            : static int vc_sm_alloc_show(struct seq_file *s, void *v)
     698                 :            : {
     699                 :            :         struct sm_priv_data_t *file_data;
     700                 :            :         struct sm_resource_t *resource;
     701                 :            :         int alloc_count = 0;
     702                 :            :         struct sm_pde_t *p_pde;
     703                 :            : 
     704                 :            :         p_pde = (struct sm_pde_t *)(s->private);
     705                 :            :         file_data = (struct sm_priv_data_t *)(p_pde->priv_data);
     706                 :            : 
     707                 :            :         if (!file_data)
     708                 :            :                 return 0;
     709                 :            : 
     710                 :            :         /* Per process statistics.  */
     711                 :            :         seq_printf(s, "\nAllocation for TGID %d\n", file_data->pid);
     712                 :            : 
     713                 :            :         mutex_lock(&(sm_state->map_lock));
     714                 :            : 
     715                 :            :         if (!list_empty(&file_data->resource_list)) {
     716                 :            :                 list_for_each_entry(resource, &file_data->resource_list,
     717                 :            :                                     resource_list) {
     718                 :            :                         alloc_count++;
     719                 :            : 
     720                 :            :                         seq_printf(s, "\nGUID:              0x%x\n",
     721                 :            :                                    resource->res_guid);
     722                 :            :                         seq_printf(s, "Lock Count:        %u\n",
     723                 :            :                                    resource->lock_count);
     724                 :            :                         seq_printf(s, "Mapped:            %s\n",
     725                 :            :                                    (resource->map_count ? "yes" : "no"));
     726                 :            :                         seq_printf(s, "VC-handle:         0x%x\n",
     727                 :            :                                    resource->res_handle);
     728                 :            :                         seq_printf(s, "VC-address:        0x%p\n",
     729                 :            :                                    resource->res_base_mem);
     730                 :            :                         seq_printf(s, "VC-size (bytes):   %u\n",
     731                 :            :                                    resource->res_size);
     732                 :            :                         seq_printf(s, "Cache:             %s\n",
     733                 :            :                                    sm_cache_map_vector[resource->res_cached]);
     734                 :            :                 }
     735                 :            :         }
     736                 :            : 
     737                 :            :         mutex_unlock(&(sm_state->map_lock));
     738                 :            : 
     739                 :            :         seq_printf(s, "\n\nTotal allocation count: %d\n\n", alloc_count);
     740                 :            : 
     741                 :            :         return 0;
     742                 :            : }
     743                 :            : #endif
     744                 :            : 
     745                 :          0 : static int vc_sm_seq_file_show(struct seq_file *s, void *v)
     746                 :            : {
     747                 :            :         struct sm_pde_t *sm_pde;
     748                 :            : 
     749                 :          0 :         sm_pde = (struct sm_pde_t *)(s->private);
     750                 :            : 
     751                 :          0 :         if (sm_pde && sm_pde->show)
     752                 :          0 :                 sm_pde->show(s, v);
     753                 :            : 
     754                 :          0 :         return 0;
     755                 :            : }
     756                 :            : 
     757                 :          0 : static int vc_sm_single_open(struct inode *inode, struct file *file)
     758                 :            : {
     759                 :          0 :         return single_open(file, vc_sm_seq_file_show, inode->i_private);
     760                 :            : }
     761                 :            : 
     762                 :            : static const struct file_operations vc_sm_debug_fs_fops = {
     763                 :            :         .open = vc_sm_single_open,
     764                 :            :         .read = seq_read,
     765                 :            :         .llseek = seq_lseek,
     766                 :            :         .release = single_release,
     767                 :            : };
     768                 :            : 
     769                 :            : /*
     770                 :            :  * Adds a resource to the private data list which tracks all the allocated
     771                 :            :  * data.
     772                 :            :  */
     773                 :          0 : static void vmcs_sm_add_resource(struct sm_priv_data_t *privdata,
     774                 :            :                                  struct sm_resource_t *resource)
     775                 :            : {
     776                 :          0 :         mutex_lock(&(sm_state->map_lock));
     777                 :          0 :         list_add(&resource->resource_list, &privdata->resource_list);
     778                 :          0 :         list_add(&resource->global_resource_list, &sm_state->resource_list);
     779                 :          0 :         mutex_unlock(&(sm_state->map_lock));
     780                 :            : 
     781                 :            :         pr_debug("[%s]: added resource %p (base addr %p, hdl %x, size %u, cache %u)\n",
     782                 :            :                 __func__, resource, resource->res_base_mem,
     783                 :            :                 resource->res_handle, resource->res_size, resource->res_cached);
     784                 :          0 : }
     785                 :            : 
     786                 :            : /*
     787                 :            :  * Locates a resource and acquire a reference on it.
     788                 :            :  * The resource won't be deleted while there is a reference on it.
     789                 :            :  */
     790                 :          0 : static struct sm_resource_t *vmcs_sm_acquire_resource(struct sm_priv_data_t
     791                 :            :                                                       *private,
     792                 :            :                                                       unsigned int res_guid)
     793                 :            : {
     794                 :            :         struct sm_resource_t *resource, *ret = NULL;
     795                 :            : 
     796                 :          0 :         mutex_lock(&(sm_state->map_lock));
     797                 :            : 
     798                 :          0 :         list_for_each_entry(resource, &private->resource_list, resource_list) {
     799                 :          0 :                 if (resource->res_guid != res_guid)
     800                 :          0 :                         continue;
     801                 :            : 
     802                 :            :                 pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
     803                 :            :                         __func__, resource, resource->res_guid,
     804                 :            :                         resource->res_base_mem, resource->res_handle,
     805                 :            :                         resource->res_size, resource->res_cached);
     806                 :          0 :                 resource->ref_count++;
     807                 :          0 :                 ret = resource;
     808                 :          0 :                 break;
     809                 :            :         }
     810                 :            : 
     811                 :          0 :         mutex_unlock(&(sm_state->map_lock));
     812                 :            : 
     813                 :          0 :         return ret;
     814                 :            : }
     815                 :            : 
     816                 :            : /*
     817                 :            :  * Locates a resource and acquire a reference on it.
     818                 :            :  * The resource won't be deleted while there is a reference on it.
     819                 :            :  */
     820                 :          0 : static struct sm_resource_t *vmcs_sm_acquire_first_resource(
     821                 :            :                 struct sm_priv_data_t *private)
     822                 :            : {
     823                 :            :         struct sm_resource_t *resource, *ret = NULL;
     824                 :            : 
     825                 :          0 :         mutex_lock(&(sm_state->map_lock));
     826                 :            : 
     827                 :          0 :         list_for_each_entry(resource, &private->resource_list, resource_list) {
     828                 :            :                 pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
     829                 :            :                         __func__, resource, resource->res_guid,
     830                 :            :                         resource->res_base_mem, resource->res_handle,
     831                 :            :                         resource->res_size, resource->res_cached);
     832                 :          0 :                 resource->ref_count++;
     833                 :            :                 ret = resource;
     834                 :          0 :                 break;
     835                 :            :         }
     836                 :            : 
     837                 :          0 :         mutex_unlock(&(sm_state->map_lock));
     838                 :            : 
     839                 :          0 :         return ret;
     840                 :            : }
     841                 :            : 
     842                 :            : /*
     843                 :            :  * Locates a resource and acquire a reference on it.
     844                 :            :  * The resource won't be deleted while there is a reference on it.
     845                 :            :  */
     846                 :          0 : static struct sm_resource_t *vmcs_sm_acquire_global_resource(unsigned int
     847                 :            :                                                              res_guid)
     848                 :            : {
     849                 :            :         struct sm_resource_t *resource, *ret = NULL;
     850                 :            : 
     851                 :          0 :         mutex_lock(&(sm_state->map_lock));
     852                 :            : 
     853                 :          0 :         list_for_each_entry(resource, &sm_state->resource_list,
     854                 :            :                             global_resource_list) {
     855                 :          0 :                 if (resource->res_guid != res_guid)
     856                 :          0 :                         continue;
     857                 :            : 
     858                 :            :                 pr_debug("[%s]: located resource %p (guid: %x, base addr %p, hdl %x, size %u, cache %u)\n",
     859                 :            :                         __func__, resource, resource->res_guid,
     860                 :            :                         resource->res_base_mem, resource->res_handle,
     861                 :            :                         resource->res_size, resource->res_cached);
     862                 :          0 :                 resource->ref_count++;
     863                 :          0 :                 ret = resource;
     864                 :          0 :                 break;
     865                 :            :         }
     866                 :            : 
     867                 :          0 :         mutex_unlock(&(sm_state->map_lock));
     868                 :            : 
     869                 :          0 :         return ret;
     870                 :            : }
     871                 :            : 
     872                 :            : /*
     873                 :            :  * Release a previously acquired resource.
     874                 :            :  * The resource will be deleted when its refcount reaches 0.
     875                 :            :  */
     876                 :          0 : static void vmcs_sm_release_resource(struct sm_resource_t *resource, int force)
     877                 :            : {
     878                 :          0 :         struct sm_priv_data_t *private = resource->private;
     879                 :            :         struct sm_mmap *map, *map_tmp;
     880                 :            :         struct sm_resource_t *res_tmp;
     881                 :            :         int ret;
     882                 :            : 
     883                 :          0 :         mutex_lock(&(sm_state->map_lock));
     884                 :            : 
     885                 :          0 :         if (--resource->ref_count) {
     886                 :          0 :                 if (force)
     887                 :          0 :                         pr_err("[%s]: resource %p in use\n", __func__, resource);
     888                 :            : 
     889                 :          0 :                 mutex_unlock(&(sm_state->map_lock));
     890                 :          0 :                 return;
     891                 :            :         }
     892                 :            : 
     893                 :            :         /* Time to free the resource. Start by removing it from the list */
     894                 :            :         list_del(&resource->resource_list);
     895                 :            :         list_del(&resource->global_resource_list);
     896                 :            : 
     897                 :            :         /*
     898                 :            :          * Walk the global resource list, find out if the resource is used
     899                 :            :          * somewhere else. In which case we don't want to delete it.
     900                 :            :          */
     901                 :          0 :         list_for_each_entry(res_tmp, &sm_state->resource_list,
     902                 :            :                             global_resource_list) {
     903                 :          0 :                 if (res_tmp->res_handle == resource->res_handle) {
     904                 :          0 :                         resource->res_handle = 0;
     905                 :          0 :                         break;
     906                 :            :                 }
     907                 :            :         }
     908                 :            : 
     909                 :          0 :         mutex_unlock(&(sm_state->map_lock));
     910                 :            : 
     911                 :            :         pr_debug("[%s]: freeing data - guid %x, hdl %x, base address %p\n",
     912                 :            :                 __func__, resource->res_guid, resource->res_handle,
     913                 :            :                 resource->res_base_mem);
     914                 :          0 :         resource->res_stats[FREE]++;
     915                 :            : 
     916                 :            :         /* Make sure the resource we're removing is unmapped first */
     917                 :          0 :         if (resource->map_count && !list_empty(&resource->map_list)) {
     918                 :          0 :                 down_write(&current->mm->mmap_sem);
     919                 :          0 :                 list_for_each_entry_safe(map, map_tmp, &resource->map_list,
     920                 :            :                                          resource_map_list) {
     921                 :          0 :                         ret =
     922                 :          0 :                             do_munmap(current->mm, map->res_addr,
     923                 :            :                                       resource->res_size, NULL);
     924                 :          0 :                         if (ret) {
     925                 :          0 :                                 pr_err("[%s]: could not unmap resource %p\n",
     926                 :            :                                         __func__, resource);
     927                 :            :                         }
     928                 :            :                 }
     929                 :          0 :                 up_write(&current->mm->mmap_sem);
     930                 :            :         }
     931                 :            : 
     932                 :            :         /* Free up the videocore allocated resource. */
     933                 :          0 :         if (resource->res_handle) {
     934                 :          0 :                 struct vc_sm_free_t free = {
     935                 :          0 :                         resource->res_handle, (uint32_t)resource->res_base_mem
     936                 :            :                 };
     937                 :          0 :                 int status = vc_vchi_sm_free(sm_state->sm_handle, &free,
     938                 :            :                                              &private->int_trans_id);
     939                 :          0 :                 if (status != 0 && status != -EINTR) {
     940                 :          0 :                         pr_err("[%s]: failed to free memory on videocore (status: %u, trans_id: %u)\n",
     941                 :            :                              __func__, status, private->int_trans_id);
     942                 :          0 :                         resource->res_stats[FREE_FAIL]++;
     943                 :            :                         ret = -EPERM;
     944                 :            :                 }
     945                 :            :         }
     946                 :            : 
     947                 :          0 :         if (resource->sgt)
     948                 :          0 :                 dma_buf_unmap_attachment(resource->attach, resource->sgt,
     949                 :            :                                          DMA_BIDIRECTIONAL);
     950                 :          0 :         if (resource->attach)
     951                 :          0 :                 dma_buf_detach(resource->dma_buf, resource->attach);
     952                 :          0 :         if (resource->dma_buf)
     953                 :          0 :                 dma_buf_put(resource->dma_buf);
     954                 :            : 
     955                 :            :         /* Free up the shared resource. */
     956                 :          0 :         if (resource->res_shared)
     957                 :          0 :                 vmcs_sm_release_resource(resource->res_shared, 0);
     958                 :            : 
     959                 :            :         /* Free up the local resource tracking this allocation. */
     960                 :          0 :         vc_sm_resource_deceased(resource, force);
     961                 :          0 :         kfree(resource);
     962                 :            : }
     963                 :            : 
     964                 :            : /*
     965                 :            :  * Dump the map table for the driver.  If process is -1, dumps the whole table,
     966                 :            :  * if process is a valid pid (non -1) dump only the entries associated with the
     967                 :            :  * pid of interest.
     968                 :            :  */
     969                 :          0 : static void vmcs_sm_host_walk_map_per_pid(int pid)
     970                 :            : {
     971                 :            :         struct sm_mmap *map = NULL;
     972                 :            : 
     973                 :            :         /* Make sure the device was started properly. */
     974                 :          0 :         if (sm_state == NULL) {
     975                 :          0 :                 pr_err("[%s]: invalid device\n", __func__);
     976                 :          0 :                 return;
     977                 :            :         }
     978                 :            : 
     979                 :          0 :         mutex_lock(&(sm_state->map_lock));
     980                 :            : 
     981                 :            :         /* Log all applicable mapping(s). */
     982                 :          0 :         if (!list_empty(&sm_state->map_list)) {
     983                 :          0 :                 list_for_each_entry(map, &sm_state->map_list, map_list) {
     984                 :          0 :                         if (pid == -1 || map->res_pid == pid) {
     985                 :          0 :                                 pr_info("[%s]: tgid: %u - vc-hdl: %x, usr-hdl: %x, usr-addr: %lx\n",
     986                 :            :                                      __func__, map->res_pid, map->res_vc_hdl,
     987                 :            :                                      map->res_usr_hdl, map->res_addr);
     988                 :            :                         }
     989                 :            :                 }
     990                 :            :         }
     991                 :            : 
     992                 :          0 :         mutex_unlock(&(sm_state->map_lock));
     993                 :            : }
     994                 :            : 
     995                 :            : /*
     996                 :            :  * Dump the allocation table from host side point of view.  This only dumps the
     997                 :            :  * data allocated for this process/device referenced by the file_data.
     998                 :            :  */
     999                 :          0 : static void vmcs_sm_host_walk_alloc(struct sm_priv_data_t *file_data)
    1000                 :            : {
    1001                 :            :         struct sm_resource_t *resource = NULL;
    1002                 :            : 
    1003                 :            :         /* Make sure the device was started properly. */
    1004                 :          0 :         if ((sm_state == NULL) || (file_data == NULL)) {
    1005                 :          0 :                 pr_err("[%s]: invalid device\n", __func__);
    1006                 :          0 :                 return;
    1007                 :            :         }
    1008                 :            : 
    1009                 :          0 :         mutex_lock(&(sm_state->map_lock));
    1010                 :            : 
    1011                 :          0 :         if (!list_empty(&file_data->resource_list)) {
    1012                 :          0 :                 list_for_each_entry(resource, &file_data->resource_list,
    1013                 :            :                                     resource_list) {
    1014                 :          0 :                         pr_info("[%s]: guid: %x - hdl: %x, vc-mem: %p, size: %u, cache: %u\n",
    1015                 :            :                              __func__, resource->res_guid, resource->res_handle,
    1016                 :            :                              resource->res_base_mem, resource->res_size,
    1017                 :            :                              resource->res_cached);
    1018                 :            :                 }
    1019                 :            :         }
    1020                 :            : 
    1021                 :          0 :         mutex_unlock(&(sm_state->map_lock));
    1022                 :            : }
    1023                 :            : 
    1024                 :            : /* Create support for private data tracking. */
    1025                 :          2 : static struct sm_priv_data_t *vc_sm_create_priv_data(pid_t id)
    1026                 :            : {
    1027                 :            :         char alloc_name[32];
    1028                 :            :         struct sm_priv_data_t *file_data = NULL;
    1029                 :            : 
    1030                 :            :         /* Allocate private structure. */
    1031                 :          2 :         file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
    1032                 :            : 
    1033                 :          2 :         if (!file_data) {
    1034                 :          0 :                 pr_err("[%s]: cannot allocate file data\n", __func__);
    1035                 :          0 :                 goto out;
    1036                 :            :         }
    1037                 :            : 
    1038                 :          2 :         snprintf(alloc_name, sizeof(alloc_name), "%d", id);
    1039                 :            : 
    1040                 :          2 :         INIT_LIST_HEAD(&file_data->resource_list);
    1041                 :          2 :         file_data->pid = id;
    1042                 :          2 :         file_data->dir_pid = debugfs_create_dir(alloc_name,
    1043                 :          2 :                         sm_state->dir_alloc);
    1044                 :            : #if 0
    1045                 :            :   /* TODO: fix this to support querying statistics per pid */
    1046                 :            : 
    1047                 :            :         if (IS_ERR_OR_NULL(file_data->dir_pid)) {
    1048                 :            :                 file_data->dir_pid = NULL;
    1049                 :            :         } else {
    1050                 :            :                 struct dentry *dir_entry;
    1051                 :            : 
    1052                 :            :                 dir_entry = debugfs_create_file(VC_SM_RESOURCES, 0444,
    1053                 :            :                                 file_data->dir_pid, file_data,
    1054                 :            :                                 vc_sm_debug_fs_fops);
    1055                 :            : 
    1056                 :            :                 file_data->dir_res.dir_entry = dir_entry;
    1057                 :            :                 file_data->dir_res.priv_data = file_data;
    1058                 :            :                 file_data->dir_res.show = &vc_sm_alloc_show;
    1059                 :            : 
    1060                 :            :                 dir_entry = debugfs_create_file(VC_SM_STATS, 0444,
    1061                 :            :                                 file_data->dir_pid, file_data,
    1062                 :            :                                 vc_sm_debug_fs_fops);
    1063                 :            : 
    1064                 :            :                 file_data->dir_res.dir_entry = dir_entry;
    1065                 :            :                 file_data->dir_res.priv_data = file_data;
    1066                 :            :                 file_data->dir_res.show = &vc_sm_statistics_show;
    1067                 :            :         }
    1068                 :            :         pr_debug("[%s]: private data allocated %p\n", __func__, file_data);
    1069                 :            : 
    1070                 :            : #endif
    1071                 :            : out:
    1072                 :          2 :         return file_data;
    1073                 :            : }
    1074                 :            : 
    1075                 :            : /*
    1076                 :            :  * Open the device.  Creates a private state to help track all allocation
    1077                 :            :  * associated with this device.
    1078                 :            :  */
    1079                 :          0 : static int vc_sm_open(struct inode *inode, struct file *file)
    1080                 :            : {
    1081                 :            :         int ret = 0;
    1082                 :            : 
    1083                 :            :         /* Make sure the device was started properly. */
    1084                 :          0 :         if (!sm_state) {
    1085                 :          0 :                 pr_err("[%s]: invalid device\n", __func__);
    1086                 :            :                 ret = -EPERM;
    1087                 :          0 :                 goto out;
    1088                 :            :         }
    1089                 :            : 
    1090                 :          0 :         file->private_data = vc_sm_create_priv_data(current->tgid);
    1091                 :          0 :         if (file->private_data == NULL) {
    1092                 :          0 :                 pr_err("[%s]: failed to create data tracker\n", __func__);
    1093                 :            : 
    1094                 :            :                 ret = -ENOMEM;
    1095                 :          0 :                 goto out;
    1096                 :            :         }
    1097                 :            : 
    1098                 :            : out:
    1099                 :          0 :         return ret;
    1100                 :            : }
    1101                 :            : 
    1102                 :            : /*
    1103                 :            :  * Close the device.  Free up all resources still associated with this device
    1104                 :            :  * at the time.
    1105                 :            :  */
    1106                 :          0 : static int vc_sm_release(struct inode *inode, struct file *file)
    1107                 :            : {
    1108                 :          0 :         struct sm_priv_data_t *file_data =
    1109                 :            :             (struct sm_priv_data_t *)file->private_data;
    1110                 :            :         struct sm_resource_t *resource;
    1111                 :            :         int ret = 0;
    1112                 :            : 
    1113                 :            :         /* Make sure the device was started properly. */
    1114                 :          0 :         if (sm_state == NULL || file_data == NULL) {
    1115                 :          0 :                 pr_err("[%s]: invalid device\n", __func__);
    1116                 :            :                 ret = -EPERM;
    1117                 :          0 :                 goto out;
    1118                 :            :         }
    1119                 :            : 
    1120                 :            :         pr_debug("[%s]: using private data %p\n", __func__, file_data);
    1121                 :            : 
    1122                 :          0 :         if (file_data->restart_sys == -EINTR) {
    1123                 :            :                 struct vc_sm_action_clean_t action_clean;
    1124                 :            : 
    1125                 :            :                 pr_debug("[%s]: releasing following EINTR on %u (trans_id: %u) (likely due to signal)...\n",
    1126                 :            :                         __func__, file_data->int_action,
    1127                 :            :                         file_data->int_trans_id);
    1128                 :            : 
    1129                 :          0 :                 action_clean.res_action = file_data->int_action;
    1130                 :          0 :                 action_clean.action_trans_id = file_data->int_trans_id;
    1131                 :            : 
    1132                 :          0 :                 vc_vchi_sm_clean_up(sm_state->sm_handle, &action_clean);
    1133                 :            :         }
    1134                 :            : 
    1135                 :          0 :         while ((resource = vmcs_sm_acquire_first_resource(file_data)) != NULL) {
    1136                 :          0 :                 vmcs_sm_release_resource(resource, 0);
    1137                 :          0 :                 vmcs_sm_release_resource(resource, 1);
    1138                 :            :         }
    1139                 :            : 
    1140                 :            :         /* Remove the corresponding proc entry. */
    1141                 :          0 :         debugfs_remove_recursive(file_data->dir_pid);
    1142                 :            : 
    1143                 :            :         /* Terminate the private data. */
    1144                 :          0 :         kfree(file_data);
    1145                 :            : 
    1146                 :            : out:
    1147                 :          0 :         return ret;
    1148                 :            : }
    1149                 :            : 
    1150                 :          0 : static void vcsm_vma_open(struct vm_area_struct *vma)
    1151                 :            : {
    1152                 :          0 :         struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data;
    1153                 :            : 
    1154                 :            :         pr_debug("[%s]: virt %lx-%lx, pid %i, pfn %i\n",
    1155                 :            :                 __func__, vma->vm_start, vma->vm_end, (int)current->tgid,
    1156                 :            :                 (int)vma->vm_pgoff);
    1157                 :            : 
    1158                 :          0 :         map->ref_count++;
    1159                 :          0 : }
    1160                 :            : 
    1161                 :          0 : static void vcsm_vma_close(struct vm_area_struct *vma)
    1162                 :            : {
    1163                 :          0 :         struct sm_mmap *map = (struct sm_mmap *)vma->vm_private_data;
    1164                 :            : 
    1165                 :            :         pr_debug("[%s]: virt %lx-%lx, pid %i, pfn %i\n",
    1166                 :            :                 __func__, vma->vm_start, vma->vm_end, (int)current->tgid,
    1167                 :            :                 (int)vma->vm_pgoff);
    1168                 :            : 
    1169                 :          0 :         map->ref_count--;
    1170                 :            : 
    1171                 :            :         /* Remove from the map table. */
    1172                 :          0 :         if (map->ref_count == 0)
    1173                 :          0 :                 vmcs_sm_remove_map(sm_state, map->resource, map);
    1174                 :          0 : }
    1175                 :            : 
    1176                 :          0 : static vm_fault_t vcsm_vma_fault(struct vm_fault *vmf)
    1177                 :            : {
    1178                 :          0 :         struct sm_mmap *map = (struct sm_mmap *)vmf->vma->vm_private_data;
    1179                 :          0 :         struct sm_resource_t *resource = map->resource;
    1180                 :            :         pgoff_t page_offset;
    1181                 :            :         unsigned long pfn;
    1182                 :            :         vm_fault_t ret;
    1183                 :            : 
    1184                 :            :         /* Lock the resource if necessary. */
    1185                 :          0 :         if (!resource->lock_count) {
    1186                 :            :                 struct vc_sm_lock_unlock_t lock_unlock;
    1187                 :            :                 struct vc_sm_lock_result_t lock_result;
    1188                 :            :                 int status;
    1189                 :            : 
    1190                 :          0 :                 lock_unlock.res_handle = resource->res_handle;
    1191                 :          0 :                 lock_unlock.res_mem = (uint32_t)resource->res_base_mem;
    1192                 :            : 
    1193                 :            :                 pr_debug("[%s]: attempt to lock data - hdl %x, base address %p\n",
    1194                 :            :                         __func__, lock_unlock.res_handle,
    1195                 :            :                         (void *)lock_unlock.res_mem);
    1196                 :            : 
    1197                 :            :                 /* Lock the videocore allocated resource. */
    1198                 :          0 :                 status = vc_vchi_sm_lock(sm_state->sm_handle,
    1199                 :            :                                          &lock_unlock, &lock_result, 0);
    1200                 :          0 :                 if (status || !lock_result.res_mem) {
    1201                 :          0 :                         pr_err("[%s]: failed to lock memory on videocore (status: %u)\n",
    1202                 :            :                                         __func__, status);
    1203                 :          0 :                         resource->res_stats[LOCK_FAIL]++;
    1204                 :          0 :                         return VM_FAULT_SIGBUS;
    1205                 :            :                 }
    1206                 :            : 
    1207                 :            :                 pfn = vcaddr_to_pfn((unsigned long)resource->res_base_mem);
    1208                 :            :                 outer_inv_range(__pfn_to_phys(pfn),
    1209                 :            :                                 __pfn_to_phys(pfn) + resource->res_size);
    1210                 :            : 
    1211                 :          0 :                 resource->res_stats[LOCK]++;
    1212                 :          0 :                 resource->lock_count++;
    1213                 :            : 
    1214                 :            :                 /* Keep track of the new base memory. */
    1215                 :          0 :                 if (lock_result.res_mem &&
    1216                 :          0 :                     lock_result.res_old_mem &&
    1217                 :            :                     (lock_result.res_mem != lock_result.res_old_mem)) {
    1218                 :          0 :                         resource->res_base_mem = (void *)lock_result.res_mem;
    1219                 :            :                 }
    1220                 :            :         }
    1221                 :            : 
    1222                 :            :         /* We don't use vmf->pgoff since that has the fake offset */
    1223                 :          0 :         page_offset = ((unsigned long)vmf->address - vmf->vma->vm_start);
    1224                 :          0 :         pfn = (uint32_t)resource->res_base_mem & 0x3FFFFFFF;
    1225                 :          0 :         pfn += mm_vc_mem_phys_addr;
    1226                 :          0 :         pfn += page_offset;
    1227                 :          0 :         pfn >>= PAGE_SHIFT;
    1228                 :            : 
    1229                 :            :         /* Finally, remap it */
    1230                 :          0 :         ret = vmf_insert_pfn(vmf->vma, (unsigned long)vmf->address, pfn);
    1231                 :          0 :         if (ret != VM_FAULT_NOPAGE)
    1232                 :          0 :                 pr_err("[%s]: failed to map page pfn:%lx virt:%lx ret:%d\n", __func__,
    1233                 :            :                         pfn, (unsigned long)vmf->address, ret);
    1234                 :          0 :         return ret;
    1235                 :            : }
    1236                 :            : 
    1237                 :            : static const struct vm_operations_struct vcsm_vm_ops = {
    1238                 :            :         .open = vcsm_vma_open,
    1239                 :            :         .close = vcsm_vma_close,
    1240                 :            :         .fault = vcsm_vma_fault,
    1241                 :            : };
    1242                 :            : 
    1243                 :            : /* Converts VCSM_CACHE_OP_* to an operating function. */
    1244                 :          0 : static void (*cache_op_to_func(const unsigned cache_op))
    1245                 :            :                 (const void*, const void*)
    1246                 :            : {
    1247                 :          0 :         switch (cache_op) {
    1248                 :            :         case VCSM_CACHE_OP_NOP:
    1249                 :            :                 return NULL;
    1250                 :            : 
    1251                 :            :         case VCSM_CACHE_OP_INV:
    1252                 :          0 :                 return dmac_inv_range;
    1253                 :            : 
    1254                 :            :         case VCSM_CACHE_OP_CLEAN:
    1255                 :          0 :                 return dmac_clean_range;
    1256                 :            : 
    1257                 :            :         case VCSM_CACHE_OP_FLUSH:
    1258                 :          0 :                 return dmac_flush_range;
    1259                 :            : 
    1260                 :            :         default:
    1261                 :          0 :                 pr_err("[%s]: Invalid cache_op: 0x%08x\n", __func__, cache_op);
    1262                 :          0 :                 return NULL;
    1263                 :            :         }
    1264                 :            : }
    1265                 :            : 
    1266                 :            : /*
    1267                 :            :  * Clean/invalid/flush cache of which buffer is already pinned (i.e. accessed).
    1268                 :            :  */
    1269                 :          0 : static int clean_invalid_contiguous_mem_2d(const void __user *addr,
    1270                 :            :                 const size_t block_count, const size_t block_size, const size_t stride,
    1271                 :            :                 const unsigned cache_op)
    1272                 :            : {
    1273                 :            :         size_t i;
    1274                 :            :         void (*op_fn)(const void*, const void*);
    1275                 :            : 
    1276                 :          0 :         if (!block_size) {
    1277                 :          0 :                 pr_err("[%s]: size cannot be 0\n", __func__);
    1278                 :          0 :                 return -EINVAL;
    1279                 :            :         }
    1280                 :            : 
    1281                 :          0 :         op_fn = cache_op_to_func(cache_op);
    1282                 :          0 :         if (op_fn == NULL)
    1283                 :            :                 return -EINVAL;
    1284                 :            : 
    1285                 :          0 :         for (i = 0; i < block_count; i ++, addr += stride)
    1286                 :          0 :                 op_fn(addr, addr + block_size);
    1287                 :            : 
    1288                 :            :         return 0;
    1289                 :            : }
    1290                 :            : 
    1291                 :            : /* Clean/invalid/flush cache of which buffer may be non-pinned. */
    1292                 :            : /* The caller must lock current->mm->mmap_sem for read. */
    1293                 :          0 : static int clean_invalid_mem_walk(unsigned long addr, const size_t size,
    1294                 :            :                 const unsigned cache_op)
    1295                 :            : {
    1296                 :            :         pgd_t *pgd;
    1297                 :            :         pud_t *pud;
    1298                 :            :         pmd_t *pmd;
    1299                 :            :         pte_t *pte;
    1300                 :            :         unsigned long pgd_next, pud_next, pmd_next;
    1301                 :          0 :         const unsigned long end = ALIGN(addr + size, PAGE_SIZE);
    1302                 :            :         void (*op_fn)(const void*, const void*);
    1303                 :            : 
    1304                 :          0 :         addr &= PAGE_MASK;
    1305                 :            : 
    1306                 :          0 :         if (addr >= end)
    1307                 :            :                 return 0;
    1308                 :            : 
    1309                 :          0 :         op_fn = cache_op_to_func(cache_op);
    1310                 :          0 :         if (op_fn == NULL)
    1311                 :            :                 return -EINVAL;
    1312                 :            : 
    1313                 :            :         /* Walk PGD */
    1314                 :          0 :         pgd = pgd_offset(current->mm, addr);
    1315                 :            :         do {
    1316                 :          0 :                 pgd_next = pgd_addr_end(addr, end);
    1317                 :            : 
    1318                 :            :                 if (pgd_none(*pgd) || pgd_bad(*pgd))
    1319                 :            :                         continue;
    1320                 :            : 
    1321                 :            :                 /* Walk PUD */
    1322                 :            :                 pud = pud_offset(pgd, addr);
    1323                 :            :                 do {
    1324                 :            :                         pud_next = pud_addr_end(addr, pgd_next);
    1325                 :            :                         if (pud_none(*pud) || pud_bad(*pud))
    1326                 :            :                                 continue;
    1327                 :            : 
    1328                 :            :                         /* Walk PMD */
    1329                 :            :                         pmd = pmd_offset(pud, addr);
    1330                 :            :                         do {
    1331                 :            :                                 pmd_next = pmd_addr_end(addr, pud_next);
    1332                 :          0 :                                 if (pmd_none(*pmd) || pmd_bad(*pmd))
    1333                 :          0 :                                         continue;
    1334                 :            : 
    1335                 :            :                                 /* Walk PTE */
    1336                 :          0 :                                 pte = pte_offset_map(pmd, addr);
    1337                 :            :                                 do {
    1338                 :          0 :                                         if (pte_none(*pte) || !pte_present(*pte))
    1339                 :          0 :                                                 continue;
    1340                 :            : 
    1341                 :          0 :                                         op_fn((const void __user*) addr,
    1342                 :          0 :                                                         (const void __user*) (addr + PAGE_SIZE));
    1343                 :          0 :                                 } while (pte++, addr += PAGE_SIZE, addr != pmd_next);
    1344                 :            :                                 pte_unmap(pte);
    1345                 :            : 
    1346                 :            :                         } while (pmd++, addr = pmd_next, addr != pud_next);
    1347                 :            : 
    1348                 :            :                 } while (pud++, addr = pud_next, addr != pgd_next);
    1349                 :            : 
    1350                 :          0 :         } while (pgd++, addr = pgd_next, addr != end);
    1351                 :            : 
    1352                 :            :         return 0;
    1353                 :            : }
    1354                 :            : 
    1355                 :            : /* Clean/invalid/flush cache of buffer in resource */
    1356                 :          0 : static int clean_invalid_resource_walk(const void __user *addr,
    1357                 :            :                 const size_t size, const unsigned cache_op, const int usr_hdl,
    1358                 :            :                 struct sm_resource_t *resource)
    1359                 :            : {
    1360                 :            :         int err;
    1361                 :            :         enum sm_stats_t stat_attempt, stat_failure;
    1362                 :            :         void __user *res_addr;
    1363                 :            : 
    1364                 :          0 :         if (resource == NULL) {
    1365                 :          0 :                 pr_err("[%s]: resource is NULL\n", __func__);
    1366                 :          0 :                 return -EINVAL;
    1367                 :            :         }
    1368                 :          0 :         if (resource->res_cached != VMCS_SM_CACHE_HOST &&
    1369                 :            :                                 resource->res_cached != VMCS_SM_CACHE_BOTH)
    1370                 :            :                 return 0;
    1371                 :            : 
    1372                 :          0 :         switch (cache_op) {
    1373                 :            :         case VCSM_CACHE_OP_NOP:
    1374                 :            :                 return 0;
    1375                 :            :         case VCSM_CACHE_OP_INV:
    1376                 :            :                 stat_attempt = INVALID;
    1377                 :            :                 stat_failure = INVALID_FAIL;
    1378                 :            :                 break;
    1379                 :            :         case VCSM_CACHE_OP_CLEAN:
    1380                 :            :                 /* Like the original VMCS_SM_CMD_CLEAN_INVALID ioctl handler does. */
    1381                 :            :                 stat_attempt = FLUSH;
    1382                 :            :                 stat_failure = FLUSH_FAIL;
    1383                 :          0 :                 break;
    1384                 :            :         case VCSM_CACHE_OP_FLUSH:
    1385                 :            :                 stat_attempt = FLUSH;
    1386                 :            :                 stat_failure = FLUSH_FAIL;
    1387                 :          0 :                 break;
    1388                 :            :         default:
    1389                 :          0 :                 pr_err("[%s]: Invalid cache_op: 0x%08x\n", __func__, cache_op);
    1390                 :          0 :                 return -EINVAL;
    1391                 :            :         }
    1392                 :          0 :         resource->res_stats[stat_attempt]++;
    1393                 :            : 
    1394                 :          0 :         if (size > resource->res_size) {
    1395                 :          0 :                 pr_err("[%s]: size (0x%08zu) is larger than res_size (0x%08zu)\n",
    1396                 :            :                                 __func__, size, resource->res_size);
    1397                 :          0 :                 return -EFAULT;
    1398                 :            :         }
    1399                 :          0 :         res_addr = (void __user*) vmcs_sm_usr_address_from_pid_and_usr_handle(
    1400                 :          0 :                         current->tgid, usr_hdl);
    1401                 :          0 :         if (res_addr == NULL) {
    1402                 :          0 :                 pr_err("[%s]: Failed to get user address "
    1403                 :            :                                 "from pid (%d) and user handle (%d)\n", __func__, current->tgid,
    1404                 :            :                                 resource->res_handle);
    1405                 :          0 :                 return -EINVAL;
    1406                 :            :         }
    1407                 :          0 :         if (!(res_addr <= addr && addr + size <= res_addr + resource->res_size)) {
    1408                 :          0 :                 pr_err("[%s]: Addr (0x%p-0x%p) out of range (0x%p-0x%p)\n",
    1409                 :            :                                 __func__, addr, addr + size, res_addr,
    1410                 :            :                                 res_addr + resource->res_size);
    1411                 :          0 :                 return -EFAULT;
    1412                 :            :         }
    1413                 :            : 
    1414                 :          0 :         down_read(&current->mm->mmap_sem);
    1415                 :          0 :         err = clean_invalid_mem_walk((unsigned long) addr, size, cache_op);
    1416                 :          0 :         up_read(&current->mm->mmap_sem);
    1417                 :            : 
    1418                 :          0 :         if (err)
    1419                 :          0 :                 resource->res_stats[stat_failure]++;
    1420                 :            : 
    1421                 :          0 :         return err;
    1422                 :            : }
    1423                 :            : 
    1424                 :            : /* Map an allocated data into something that the user space. */
    1425                 :          0 : static int vc_sm_mmap(struct file *file, struct vm_area_struct *vma)
    1426                 :            : {
    1427                 :            :         int ret = 0;
    1428                 :          0 :         struct sm_priv_data_t *file_data =
    1429                 :            :             (struct sm_priv_data_t *)file->private_data;
    1430                 :            :         struct sm_resource_t *resource = NULL;
    1431                 :            :         struct sm_mmap *map = NULL;
    1432                 :            : 
    1433                 :            :         /* Make sure the device was started properly. */
    1434                 :          0 :         if ((sm_state == NULL) || (file_data == NULL)) {
    1435                 :          0 :                 pr_err("[%s]: invalid device\n", __func__);
    1436                 :          0 :                 return -EPERM;
    1437                 :            :         }
    1438                 :            : 
    1439                 :            :         pr_debug("[%s]: private data %p, guid %x\n", __func__, file_data,
    1440                 :            :                 ((unsigned int)vma->vm_pgoff << PAGE_SHIFT));
    1441                 :            : 
    1442                 :            :         /*
    1443                 :            :          * We lookup to make sure that the data we are being asked to mmap is
    1444                 :            :          * something that we allocated.
    1445                 :            :          *
    1446                 :            :          * We use the offset information as the key to tell us which resource
    1447                 :            :          * we are mapping.
    1448                 :            :          */
    1449                 :          0 :         resource = vmcs_sm_acquire_resource(file_data,
    1450                 :          0 :                                             ((unsigned int)vma->vm_pgoff <<
    1451                 :            :                                              PAGE_SHIFT));
    1452                 :          0 :         if (resource == NULL) {
    1453                 :          0 :                 pr_err("[%s]: failed to locate resource for guid %x\n", __func__,
    1454                 :            :                         ((unsigned int)vma->vm_pgoff << PAGE_SHIFT));
    1455                 :          0 :                 return -ENOMEM;
    1456                 :            :         }
    1457                 :            : 
    1458                 :            :         pr_debug("[%s]: guid %x, tgid %u, %u, %u\n",
    1459                 :            :                 __func__, resource->res_guid, current->tgid, resource->pid,
    1460                 :            :                 file_data->pid);
    1461                 :            : 
    1462                 :            :         /* Check permissions. */
    1463                 :          0 :         if (resource->pid && (resource->pid != current->tgid)) {
    1464                 :          0 :                 pr_err("[%s]: current tgid %u != %u owner\n",
    1465                 :            :                         __func__, current->tgid, resource->pid);
    1466                 :            :                 ret = -EPERM;
    1467                 :          0 :                 goto error;
    1468                 :            :         }
    1469                 :            : 
    1470                 :            :         /* Verify that what we are asked to mmap is proper. */
    1471                 :          0 :         if (resource->res_size != (unsigned int)(vma->vm_end - vma->vm_start)) {
    1472                 :          0 :                 pr_err("[%s]: size inconsistency (resource: %u - mmap: %u)\n",
    1473                 :            :                         __func__,
    1474                 :            :                         resource->res_size,
    1475                 :            :                         (unsigned int)(vma->vm_end - vma->vm_start));
    1476                 :            : 
    1477                 :            :                 ret = -EINVAL;
    1478                 :          0 :                 goto error;
    1479                 :            :         }
    1480                 :            : 
    1481                 :            :         /*
    1482                 :            :          * Keep track of the tuple in the global resource list such that one
    1483                 :            :          * can do a mapping lookup for address/memory handle.
    1484                 :            :          */
    1485                 :          0 :         map = kzalloc(sizeof(*map), GFP_KERNEL);
    1486                 :          0 :         if (map == NULL) {
    1487                 :          0 :                 pr_err("[%s]: failed to allocate global tracking resource\n",
    1488                 :            :                         __func__);
    1489                 :            :                 ret = -ENOMEM;
    1490                 :          0 :                 goto error;
    1491                 :            :         }
    1492                 :            : 
    1493                 :          0 :         map->res_pid = current->tgid;
    1494                 :          0 :         map->res_vc_hdl = resource->res_handle;
    1495                 :          0 :         map->res_usr_hdl = resource->res_guid;
    1496                 :          0 :         map->res_addr = (unsigned long)vma->vm_start;
    1497                 :          0 :         map->resource = resource;
    1498                 :          0 :         map->vma = vma;
    1499                 :          0 :         vmcs_sm_add_map(sm_state, resource, map);
    1500                 :            : 
    1501                 :            :         /*
    1502                 :            :          * We are not actually mapping the pages, we just provide a fault
    1503                 :            :          * handler to allow pages to be mapped when accessed
    1504                 :            :          */
    1505                 :          0 :         vma->vm_flags |=
    1506                 :            :             VM_IO | VM_PFNMAP | VM_DONTCOPY | VM_DONTEXPAND;
    1507                 :          0 :         vma->vm_ops = &vcsm_vm_ops;
    1508                 :          0 :         vma->vm_private_data = map;
    1509                 :            : 
    1510                 :            :         /* vm_pgoff is the first PFN of the mapped memory */
    1511                 :          0 :         vma->vm_pgoff = (unsigned long)resource->res_base_mem & 0x3FFFFFFF;
    1512                 :          0 :         vma->vm_pgoff += mm_vc_mem_phys_addr;
    1513                 :          0 :         vma->vm_pgoff >>= PAGE_SHIFT;
    1514                 :            : 
    1515                 :          0 :         if ((resource->res_cached == VMCS_SM_CACHE_NONE) ||
    1516                 :            :             (resource->res_cached == VMCS_SM_CACHE_VC)) {
    1517                 :            :                 /* Allocated non host cached memory, honour it. */
    1518                 :          0 :                 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
    1519                 :            :         }
    1520                 :            : 
    1521                 :            :         pr_debug("[%s]: resource %p (guid %x) - cnt %u, base address %p, handle %x, size %u (%u), cache %u\n",
    1522                 :            :                 __func__,
    1523                 :            :                 resource, resource->res_guid, resource->lock_count,
    1524                 :            :                 resource->res_base_mem, resource->res_handle,
    1525                 :            :                 resource->res_size, (unsigned int)(vma->vm_end - vma->vm_start),
    1526                 :            :                 resource->res_cached);
    1527                 :            : 
    1528                 :            :         pr_debug("[%s]: resource %p (base address %p, handle %x) - map-count %d, usr-addr %x\n",
    1529                 :            :                 __func__, resource, resource->res_base_mem,
    1530                 :            :                 resource->res_handle, resource->map_count,
    1531                 :            :                 (unsigned int)vma->vm_start);
    1532                 :            : 
    1533                 :            :         vcsm_vma_open(vma);
    1534                 :          0 :         resource->res_stats[MAP]++;
    1535                 :          0 :         vmcs_sm_release_resource(resource, 0);
    1536                 :            : 
    1537                 :          0 :         if (resource->map) {
    1538                 :            :                 /* We don't use vmf->pgoff since that has the fake offset */
    1539                 :            :                 unsigned long addr;
    1540                 :            : 
    1541                 :          0 :                 for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) {
    1542                 :            :                         /* Finally, remap it */
    1543                 :          0 :                         unsigned long pfn = (unsigned long)resource->res_base_mem & 0x3FFFFFFF;
    1544                 :            : 
    1545                 :          0 :                         pfn += mm_vc_mem_phys_addr;
    1546                 :          0 :                         pfn += addr - vma->vm_start;
    1547                 :          0 :                         pfn >>= PAGE_SHIFT;
    1548                 :          0 :                         ret = vmf_insert_pfn(vma, addr, pfn);
    1549                 :            :                 }
    1550                 :            :         }
    1551                 :            : 
    1552                 :            :         return 0;
    1553                 :            : 
    1554                 :            : error:
    1555                 :          0 :         resource->res_stats[MAP_FAIL]++;
    1556                 :          0 :         vmcs_sm_release_resource(resource, 0);
    1557                 :          0 :         return ret;
    1558                 :            : }
    1559                 :            : 
    1560                 :            : /* Allocate a shared memory handle and block. */
    1561                 :          0 : static int vc_sm_ioctl_alloc(struct sm_priv_data_t *private,
    1562                 :            :                              struct vmcs_sm_ioctl_alloc *ioparam)
    1563                 :            : {
    1564                 :            :         int ret = 0;
    1565                 :            :         int status;
    1566                 :            :         struct sm_resource_t *resource;
    1567                 :          0 :         struct vc_sm_alloc_t alloc = { 0 };
    1568                 :          0 :         struct vc_sm_alloc_result_t result = { 0 };
    1569                 :          0 :         enum vmcs_sm_cache_e cached = ioparam->cached;
    1570                 :            :         bool map = false;
    1571                 :            : 
    1572                 :            :         /* flag to requst buffer is mapped up front, rather than lazily */
    1573                 :          0 :         if (cached & 0x80) {
    1574                 :            :                 map = true;
    1575                 :          0 :                 cached &= ~0x80;
    1576                 :            :         }
    1577                 :            : 
    1578                 :            :         /* Setup our allocation parameters */
    1579                 :          0 :         alloc.type = ((cached == VMCS_SM_CACHE_VC)
    1580                 :          0 :                       || (cached ==
    1581                 :          0 :                           VMCS_SM_CACHE_BOTH)) ? VC_SM_ALLOC_CACHED :
    1582                 :            :             VC_SM_ALLOC_NON_CACHED;
    1583                 :          0 :         alloc.base_unit = ioparam->size;
    1584                 :          0 :         alloc.num_unit = ioparam->num;
    1585                 :          0 :         alloc.allocator = current->tgid;
    1586                 :            :         /* Align to kernel page size */
    1587                 :          0 :         alloc.alignement = 4096;
    1588                 :            :         /* Align the size to the kernel page size */
    1589                 :          0 :         alloc.base_unit =
    1590                 :          0 :             (alloc.base_unit + alloc.alignement - 1) & ~(alloc.alignement - 1);
    1591                 :          0 :         if (*ioparam->name) {
    1592                 :          0 :                 memcpy(alloc.name, ioparam->name, sizeof(alloc.name) - 1);
    1593                 :            :         } else {
    1594                 :          0 :                 memcpy(alloc.name, VMCS_SM_RESOURCE_NAME_DEFAULT,
    1595                 :            :                        sizeof(VMCS_SM_RESOURCE_NAME_DEFAULT));
    1596                 :            :         }
    1597                 :            : 
    1598                 :            :         pr_debug("[%s]: attempt to allocate \"%s\" data - type %u, base %u (%u), num %u, alignement %u\n",
    1599                 :            :                 __func__, alloc.name, alloc.type, ioparam->size,
    1600                 :            :                 alloc.base_unit, alloc.num_unit, alloc.alignement);
    1601                 :            : 
    1602                 :            :         /* Allocate local resource to track this allocation. */
    1603                 :          0 :         resource = kzalloc(sizeof(*resource), GFP_KERNEL);
    1604                 :          0 :         if (!resource) {
    1605                 :            :                 ret = -ENOMEM;
    1606                 :            :                 goto error;
    1607                 :            :         }
    1608                 :          0 :         INIT_LIST_HEAD(&resource->map_list);
    1609                 :          0 :         resource->ref_count++;
    1610                 :          0 :         resource->pid = current->tgid;
    1611                 :            : 
    1612                 :            :         /* Allocate the videocore resource. */
    1613                 :          0 :         status = vc_vchi_sm_alloc(sm_state->sm_handle, &alloc, &result,
    1614                 :            :                                   &private->int_trans_id);
    1615                 :          0 :         if (status == -EINTR) {
    1616                 :            :                 pr_debug("[%s]: requesting allocate memory action restart (trans_id: %u)\n",
    1617                 :            :                         __func__, private->int_trans_id);
    1618                 :            :                 ret = -ERESTARTSYS;
    1619                 :          0 :                 private->restart_sys = -EINTR;
    1620                 :          0 :                 private->int_action = VC_SM_MSG_TYPE_ALLOC;
    1621                 :          0 :                 goto error;
    1622                 :          0 :         } else if (status != 0 || !result.res_mem) {
    1623                 :          0 :                 pr_err("[%s]: failed to allocate memory on videocore (status: %u, trans_id: %u)\n",
    1624                 :            :                      __func__, status, private->int_trans_id);
    1625                 :            :                 ret = -ENOMEM;
    1626                 :          0 :                 resource->res_stats[ALLOC_FAIL]++;
    1627                 :          0 :                 goto error;
    1628                 :            :         }
    1629                 :            : 
    1630                 :            :         /* Keep track of the resource we created. */
    1631                 :          0 :         resource->private = private;
    1632                 :          0 :         resource->res_handle = result.res_handle;
    1633                 :          0 :         resource->res_base_mem = (void *)result.res_mem;
    1634                 :          0 :         resource->res_size = alloc.base_unit * alloc.num_unit;
    1635                 :          0 :         resource->res_cached = cached;
    1636                 :          0 :         resource->map = map;
    1637                 :            : 
    1638                 :            :         /*
    1639                 :            :          * Kernel/user GUID.  This global identifier is used for mmap'ing the
    1640                 :            :          * allocated region from user space, it is passed as the mmap'ing
    1641                 :            :          * offset, we use it to 'hide' the videocore handle/address.
    1642                 :            :          */
    1643                 :          0 :         mutex_lock(&sm_state->lock);
    1644                 :          0 :         resource->res_guid = ++sm_state->guid;
    1645                 :          0 :         mutex_unlock(&sm_state->lock);
    1646                 :          0 :         resource->res_guid <<= PAGE_SHIFT;
    1647                 :            : 
    1648                 :          0 :         vmcs_sm_add_resource(private, resource);
    1649                 :            : 
    1650                 :            :         pr_debug("[%s]: allocated data - guid %x, hdl %x, base address %p, size %d, cache %d\n",
    1651                 :            :                 __func__, resource->res_guid, resource->res_handle,
    1652                 :            :                 resource->res_base_mem, resource->res_size,
    1653                 :            :                 resource->res_cached);
    1654                 :            : 
    1655                 :            :         /* We're done */
    1656                 :          0 :         resource->res_stats[ALLOC]++;
    1657                 :          0 :         ioparam->handle = resource->res_guid;
    1658                 :          0 :         return 0;
    1659                 :            : 
    1660                 :            : error:
    1661                 :          0 :         pr_err("[%s]: failed to allocate \"%s\" data (%i) - type %u, base %u (%u), num %u, alignment %u\n",
    1662                 :            :              __func__, alloc.name, ret, alloc.type, ioparam->size,
    1663                 :            :              alloc.base_unit, alloc.num_unit, alloc.alignement);
    1664                 :          0 :         if (resource != NULL) {
    1665                 :          0 :                 vc_sm_resource_deceased(resource, 1);
    1666                 :          0 :                 kfree(resource);
    1667                 :            :         }
    1668                 :          0 :         return ret;
    1669                 :            : }
    1670                 :            : 
    1671                 :            : /* Share an allocate memory handle and block.*/
    1672                 :          0 : static int vc_sm_ioctl_alloc_share(struct sm_priv_data_t *private,
    1673                 :            :                                    struct vmcs_sm_ioctl_alloc_share *ioparam)
    1674                 :            : {
    1675                 :            :         struct sm_resource_t *resource, *shared_resource;
    1676                 :            :         int ret = 0;
    1677                 :            : 
    1678                 :            :         pr_debug("[%s]: attempt to share resource %u\n", __func__,
    1679                 :            :                         ioparam->handle);
    1680                 :            : 
    1681                 :          0 :         shared_resource = vmcs_sm_acquire_global_resource(ioparam->handle);
    1682                 :          0 :         if (shared_resource == NULL) {
    1683                 :            :                 ret = -ENOMEM;
    1684                 :            :                 goto error;
    1685                 :            :         }
    1686                 :            : 
    1687                 :            :         /* Allocate local resource to track this allocation. */
    1688                 :          0 :         resource = kzalloc(sizeof(*resource), GFP_KERNEL);
    1689                 :          0 :         if (resource == NULL) {
    1690                 :          0 :                 pr_err("[%s]: failed to allocate local tracking resource\n",
    1691                 :            :                         __func__);
    1692                 :            :                 ret = -ENOMEM;
    1693                 :          0 :                 goto error;
    1694                 :            :         }
    1695                 :          0 :         INIT_LIST_HEAD(&resource->map_list);
    1696                 :          0 :         resource->ref_count++;
    1697                 :          0 :         resource->pid = current->tgid;
    1698                 :            : 
    1699                 :            :         /* Keep track of the resource we created. */
    1700                 :          0 :         resource->private = private;
    1701                 :          0 :         resource->res_handle = shared_resource->res_handle;
    1702                 :          0 :         resource->res_base_mem = shared_resource->res_base_mem;
    1703                 :          0 :         resource->res_size = shared_resource->res_size;
    1704                 :          0 :         resource->res_cached = shared_resource->res_cached;
    1705                 :          0 :         resource->res_shared = shared_resource;
    1706                 :            : 
    1707                 :          0 :         mutex_lock(&sm_state->lock);
    1708                 :          0 :         resource->res_guid = ++sm_state->guid;
    1709                 :          0 :         mutex_unlock(&sm_state->lock);
    1710                 :          0 :         resource->res_guid <<= PAGE_SHIFT;
    1711                 :            : 
    1712                 :          0 :         vmcs_sm_add_resource(private, resource);
    1713                 :            : 
    1714                 :            :         pr_debug("[%s]: allocated data - guid %x, hdl %x, base address %p, size %d, cache %d\n",
    1715                 :            :                 __func__, resource->res_guid, resource->res_handle,
    1716                 :            :                 resource->res_base_mem, resource->res_size,
    1717                 :            :                 resource->res_cached);
    1718                 :            : 
    1719                 :            :         /* We're done */
    1720                 :          0 :         resource->res_stats[ALLOC]++;
    1721                 :          0 :         ioparam->handle = resource->res_guid;
    1722                 :          0 :         ioparam->size = resource->res_size;
    1723                 :          0 :         return 0;
    1724                 :            : 
    1725                 :            : error:
    1726                 :          0 :         pr_err("[%s]: failed to share %u\n", __func__, ioparam->handle);
    1727                 :          0 :         if (shared_resource != NULL)
    1728                 :          0 :                 vmcs_sm_release_resource(shared_resource, 0);
    1729                 :            : 
    1730                 :            :         return ret;
    1731                 :            : }
    1732                 :            : 
    1733                 :            : /* Free a previously allocated shared memory handle and block.*/
    1734                 :          0 : static int vc_sm_ioctl_free(struct sm_priv_data_t *private,
    1735                 :            :                             struct vmcs_sm_ioctl_free *ioparam)
    1736                 :            : {
    1737                 :          0 :         struct sm_resource_t *resource =
    1738                 :          0 :             vmcs_sm_acquire_resource(private, ioparam->handle);
    1739                 :            : 
    1740                 :          0 :         if (resource == NULL) {
    1741                 :          0 :                 pr_err("[%s]: resource for guid %u does not exist\n", __func__,
    1742                 :            :                         ioparam->handle);
    1743                 :          0 :                 return -EINVAL;
    1744                 :            :         }
    1745                 :            : 
    1746                 :            :         /* Check permissions. */
    1747                 :          0 :         if (resource->pid && (resource->pid != current->tgid)) {
    1748                 :          0 :                 pr_err("[%s]: current tgid %u != %u owner\n",
    1749                 :            :                         __func__, current->tgid, resource->pid);
    1750                 :          0 :                 vmcs_sm_release_resource(resource, 0);
    1751                 :          0 :                 return -EPERM;
    1752                 :            :         }
    1753                 :            : 
    1754                 :          0 :         vmcs_sm_release_resource(resource, 0);
    1755                 :          0 :         vmcs_sm_release_resource(resource, 0);
    1756                 :          0 :         return 0;
    1757                 :            : }
    1758                 :            : 
    1759                 :            : /* Resize a previously allocated shared memory handle and block. */
    1760                 :          0 : static int vc_sm_ioctl_resize(struct sm_priv_data_t *private,
    1761                 :            :                               struct vmcs_sm_ioctl_resize *ioparam)
    1762                 :            : {
    1763                 :            :         int ret = 0;
    1764                 :            :         int status;
    1765                 :            :         struct vc_sm_resize_t resize;
    1766                 :            :         struct sm_resource_t *resource;
    1767                 :            : 
    1768                 :            :         /* Locate resource from GUID. */
    1769                 :          0 :         resource = vmcs_sm_acquire_resource(private, ioparam->handle);
    1770                 :          0 :         if (!resource) {
    1771                 :          0 :                 pr_err("[%s]: failed resource - guid %x\n",
    1772                 :            :                                 __func__, ioparam->handle);
    1773                 :            :                 ret = -EFAULT;
    1774                 :          0 :                 goto error;
    1775                 :            :         }
    1776                 :            : 
    1777                 :            :         /*
    1778                 :            :          * If the resource is locked, its reference count will be not NULL,
    1779                 :            :          * in which case we will not be allowed to resize it anyways, so
    1780                 :            :          * reject the attempt here.
    1781                 :            :          */
    1782                 :          0 :         if (resource->lock_count != 0) {
    1783                 :          0 :                 pr_err("[%s]: cannot resize - guid %x, ref-cnt %d\n",
    1784                 :            :                      __func__, ioparam->handle, resource->lock_count);
    1785                 :            :                 ret = -EFAULT;
    1786                 :          0 :                 goto error;
    1787                 :            :         }
    1788                 :            : 
    1789                 :            :         /* Check permissions. */
    1790                 :          0 :         if (resource->pid && (resource->pid != current->tgid)) {
    1791                 :          0 :                 pr_err("[%s]: current tgid %u != %u owner\n", __func__,
    1792                 :            :                                 current->tgid, resource->pid);
    1793                 :            :                 ret = -EPERM;
    1794                 :          0 :                 goto error;
    1795                 :            :         }
    1796                 :            : 
    1797                 :          0 :         if (resource->map_count != 0) {
    1798                 :          0 :                 pr_err("[%s]: cannot resize - guid %x, ref-cnt %d\n",
    1799                 :            :                      __func__, ioparam->handle, resource->map_count);
    1800                 :            :                 ret = -EFAULT;
    1801                 :          0 :                 goto error;
    1802                 :            :         }
    1803                 :            : 
    1804                 :          0 :         resize.res_handle = resource->res_handle;
    1805                 :          0 :         resize.res_mem = (uint32_t)resource->res_base_mem;
    1806                 :          0 :         resize.res_new_size = ioparam->new_size;
    1807                 :            : 
    1808                 :            :         pr_debug("[%s]: attempt to resize data - guid %x, hdl %x, base address %p\n",
    1809                 :            :                 __func__, ioparam->handle, resize.res_handle,
    1810                 :            :                 (void *)resize.res_mem);
    1811                 :            : 
    1812                 :            :         /* Resize the videocore allocated resource. */
    1813                 :          0 :         status = vc_vchi_sm_resize(sm_state->sm_handle, &resize,
    1814                 :            :                                    &private->int_trans_id);
    1815                 :          0 :         if (status == -EINTR) {
    1816                 :            :                 pr_debug("[%s]: requesting resize memory action restart (trans_id: %u)\n",
    1817                 :            :                         __func__, private->int_trans_id);
    1818                 :            :                 ret = -ERESTARTSYS;
    1819                 :          0 :                 private->restart_sys = -EINTR;
    1820                 :          0 :                 private->int_action = VC_SM_MSG_TYPE_RESIZE;
    1821                 :          0 :                 goto error;
    1822                 :          0 :         } else if (status) {
    1823                 :          0 :                 pr_err("[%s]: failed to resize memory on videocore (status: %u, trans_id: %u)\n",
    1824                 :            :                      __func__, status, private->int_trans_id);
    1825                 :            :                 ret = -EPERM;
    1826                 :          0 :                 goto error;
    1827                 :            :         }
    1828                 :            : 
    1829                 :            :         pr_debug("[%s]: success to resize data - hdl %x, size %d -> %d\n",
    1830                 :            :                 __func__, resize.res_handle, resource->res_size,
    1831                 :            :                 resize.res_new_size);
    1832                 :            : 
    1833                 :            :         /* Successfully resized, save the information and inform the user. */
    1834                 :          0 :         ioparam->old_size = resource->res_size;
    1835                 :          0 :         resource->res_size = resize.res_new_size;
    1836                 :            : 
    1837                 :            : error:
    1838                 :          0 :         if (resource)
    1839                 :          0 :                 vmcs_sm_release_resource(resource, 0);
    1840                 :            : 
    1841                 :          0 :         return ret;
    1842                 :            : }
    1843                 :            : 
    1844                 :            : /* Lock a previously allocated shared memory handle and block. */
    1845                 :          0 : static int vc_sm_ioctl_lock(struct sm_priv_data_t *private,
    1846                 :            :                             struct vmcs_sm_ioctl_lock_unlock *ioparam,
    1847                 :            :                             int change_cache, enum vmcs_sm_cache_e cache_type,
    1848                 :            :                             unsigned int vc_addr)
    1849                 :            : {
    1850                 :            :         int status;
    1851                 :            :         struct vc_sm_lock_unlock_t lock;
    1852                 :            :         struct vc_sm_lock_result_t result;
    1853                 :            :         struct sm_resource_t *resource;
    1854                 :            :         int ret = 0;
    1855                 :            :         struct sm_mmap *map, *map_tmp;
    1856                 :            :         unsigned long phys_addr;
    1857                 :            : 
    1858                 :            :         map = NULL;
    1859                 :            : 
    1860                 :            :         /* Locate resource from GUID. */
    1861                 :          0 :         resource = vmcs_sm_acquire_resource(private, ioparam->handle);
    1862                 :          0 :         if (resource == NULL) {
    1863                 :            :                 ret = -EINVAL;
    1864                 :            :                 goto error;
    1865                 :            :         }
    1866                 :            : 
    1867                 :            :         /* Check permissions. */
    1868                 :          0 :         if (resource->pid && (resource->pid != current->tgid)) {
    1869                 :          0 :                 pr_err("[%s]: current tgid %u != %u owner\n", __func__,
    1870                 :            :                                 current->tgid, resource->pid);
    1871                 :            :                 ret = -EPERM;
    1872                 :          0 :                 goto error;
    1873                 :            :         }
    1874                 :            : 
    1875                 :          0 :         lock.res_handle = resource->res_handle;
    1876                 :          0 :         lock.res_mem = (uint32_t)resource->res_base_mem;
    1877                 :            : 
    1878                 :            :         /* Take the lock and get the address to be mapped. */
    1879                 :          0 :         if (vc_addr == 0) {
    1880                 :            :                 pr_debug("[%s]: attempt to lock data - guid %x, hdl %x, base address %p\n",
    1881                 :            :                         __func__, ioparam->handle, lock.res_handle,
    1882                 :            :                         (void *)lock.res_mem);
    1883                 :            : 
    1884                 :            :                 /* Lock the videocore allocated resource. */
    1885                 :          0 :                 status = vc_vchi_sm_lock(sm_state->sm_handle, &lock, &result,
    1886                 :            :                                          &private->int_trans_id);
    1887                 :          0 :                 if (status == -EINTR) {
    1888                 :            :                         pr_debug("[%s]: requesting lock memory action restart (trans_id: %u)\n",
    1889                 :            :                                 __func__, private->int_trans_id);
    1890                 :            :                         ret = -ERESTARTSYS;
    1891                 :          0 :                         private->restart_sys = -EINTR;
    1892                 :          0 :                         private->int_action = VC_SM_MSG_TYPE_LOCK;
    1893                 :          0 :                         goto error;
    1894                 :          0 :                 } else if (status ||
    1895                 :          0 :                            (!status && !(void *)result.res_mem)) {
    1896                 :          0 :                         pr_err("[%s]: failed to lock memory on videocore (status: %u, trans_id: %u)\n",
    1897                 :            :                              __func__, status, private->int_trans_id);
    1898                 :            :                         ret = -EPERM;
    1899                 :          0 :                         resource->res_stats[LOCK_FAIL]++;
    1900                 :          0 :                         goto error;
    1901                 :            :                 }
    1902                 :            : 
    1903                 :            :                 pr_debug("[%s]: succeed to lock data - hdl %x, base address %p (%p), ref-cnt %d\n",
    1904                 :            :                         __func__, lock.res_handle, (void *)result.res_mem,
    1905                 :            :                         (void *)lock.res_mem, resource->lock_count);
    1906                 :            :         }
    1907                 :            :         /* Lock assumed taken already, address to be mapped is known. */
    1908                 :            :         else
    1909                 :          0 :                 resource->res_base_mem = (void *)vc_addr;
    1910                 :            : 
    1911                 :          0 :         resource->res_stats[LOCK]++;
    1912                 :          0 :         resource->lock_count++;
    1913                 :            : 
    1914                 :            :         /* Keep track of the new base memory allocation if it has changed. */
    1915                 :          0 :         if ((vc_addr == 0) &&
    1916                 :          0 :             ((void *)result.res_mem) &&
    1917                 :          0 :             ((void *)result.res_old_mem) &&
    1918                 :            :             (result.res_mem != result.res_old_mem)) {
    1919                 :          0 :                 resource->res_base_mem = (void *)result.res_mem;
    1920                 :            : 
    1921                 :            :                 /* Kernel allocated resources. */
    1922                 :          0 :                 if (resource->pid == 0) {
    1923                 :          0 :                         if (!list_empty(&resource->map_list)) {
    1924                 :          0 :                                 list_for_each_entry_safe(map, map_tmp,
    1925                 :            :                                                          &resource->map_list,
    1926                 :            :                                                          resource_map_list) {
    1927                 :          0 :                                         if (map->res_addr) {
    1928                 :          0 :                                                 iounmap((void *)map->res_addr);
    1929                 :          0 :                                                 map->res_addr = 0;
    1930                 :            : 
    1931                 :          0 :                                                 vmcs_sm_remove_map(sm_state,
    1932                 :            :                                                                 map->resource,
    1933                 :            :                                                                 map);
    1934                 :          0 :                                                 break;
    1935                 :            :                                         }
    1936                 :            :                                 }
    1937                 :            :                         }
    1938                 :            :                 }
    1939                 :            :         }
    1940                 :            : 
    1941                 :          0 :         if (change_cache)
    1942                 :          0 :                 resource->res_cached = cache_type;
    1943                 :            : 
    1944                 :          0 :         if (resource->map_count) {
    1945                 :          0 :                 ioparam->addr =
    1946                 :          0 :                     vmcs_sm_usr_address_from_pid_and_usr_handle(
    1947                 :          0 :                                     current->tgid, ioparam->handle);
    1948                 :            : 
    1949                 :            :                 pr_debug("[%s] map_count %d private->pid %d current->tgid %d hnd %x addr %u\n",
    1950                 :            :                         __func__, resource->map_count, private->pid,
    1951                 :            :                         current->tgid, ioparam->handle, ioparam->addr);
    1952                 :            :         } else {
    1953                 :            :                 /* Kernel allocated resources. */
    1954                 :          0 :                 if (resource->pid == 0) {
    1955                 :            :                         pr_debug("[%s]: attempt mapping kernel resource - guid %x, hdl %x\n",
    1956                 :            :                                 __func__, ioparam->handle, lock.res_handle);
    1957                 :            : 
    1958                 :          0 :                         ioparam->addr = 0;
    1959                 :            : 
    1960                 :          0 :                         map = kzalloc(sizeof(*map), GFP_KERNEL);
    1961                 :          0 :                         if (map == NULL) {
    1962                 :          0 :                                 pr_err("[%s]: failed allocating tracker\n",
    1963                 :            :                                                 __func__);
    1964                 :            :                                 ret = -ENOMEM;
    1965                 :          0 :                                 goto error;
    1966                 :            :                         } else {
    1967                 :          0 :                                 phys_addr = (uint32_t)resource->res_base_mem &
    1968                 :            :                                     0x3FFFFFFF;
    1969                 :          0 :                                 phys_addr += mm_vc_mem_phys_addr;
    1970                 :          0 :                                 if (resource->res_cached
    1971                 :            :                                                 == VMCS_SM_CACHE_HOST) {
    1972                 :          0 :                                         ioparam->addr = (unsigned long)
    1973                 :            :                                         /* TODO - make cached work */
    1974                 :          0 :                                             ioremap_nocache(phys_addr,
    1975                 :            :                                                            resource->res_size);
    1976                 :            : 
    1977                 :            :                                         pr_debug("[%s]: mapping kernel - guid %x, hdl %x - cached mapping %u\n",
    1978                 :            :                                                 __func__, ioparam->handle,
    1979                 :            :                                                 lock.res_handle, ioparam->addr);
    1980                 :            :                                 } else {
    1981                 :          0 :                                         ioparam->addr = (unsigned long)
    1982                 :          0 :                                             ioremap_nocache(phys_addr,
    1983                 :            :                                                             resource->res_size);
    1984                 :            : 
    1985                 :            :                                         pr_debug("[%s]: mapping kernel- guid %x, hdl %x - non cached mapping %u\n",
    1986                 :            :                                                 __func__, ioparam->handle,
    1987                 :            :                                                 lock.res_handle, ioparam->addr);
    1988                 :            :                                 }
    1989                 :            : 
    1990                 :          0 :                                 map->res_pid = 0;
    1991                 :          0 :                                 map->res_vc_hdl = resource->res_handle;
    1992                 :          0 :                                 map->res_usr_hdl = resource->res_guid;
    1993                 :          0 :                                 map->res_addr = ioparam->addr;
    1994                 :          0 :                                 map->resource = resource;
    1995                 :          0 :                                 map->vma = NULL;
    1996                 :            : 
    1997                 :          0 :                                 vmcs_sm_add_map(sm_state, resource, map);
    1998                 :            :                         }
    1999                 :            :                 } else
    2000                 :          0 :                         ioparam->addr = 0;
    2001                 :            :         }
    2002                 :            : 
    2003                 :            : error:
    2004                 :          0 :         if (resource)
    2005                 :          0 :                 vmcs_sm_release_resource(resource, 0);
    2006                 :            : 
    2007                 :          0 :         return ret;
    2008                 :            : }
    2009                 :            : 
    2010                 :            : /* Unlock a previously allocated shared memory handle and block.*/
    2011                 :          0 : static int vc_sm_ioctl_unlock(struct sm_priv_data_t *private,
    2012                 :            :                               struct vmcs_sm_ioctl_lock_unlock *ioparam,
    2013                 :            :                               int flush, int wait_reply, int no_vc_unlock)
    2014                 :            : {
    2015                 :            :         int status;
    2016                 :            :         struct vc_sm_lock_unlock_t unlock;
    2017                 :            :         struct sm_mmap *map, *map_tmp;
    2018                 :            :         struct sm_resource_t *resource;
    2019                 :            :         int ret = 0;
    2020                 :            : 
    2021                 :            :         map = NULL;
    2022                 :            : 
    2023                 :            :         /* Locate resource from GUID. */
    2024                 :          0 :         resource = vmcs_sm_acquire_resource(private, ioparam->handle);
    2025                 :          0 :         if (resource == NULL) {
    2026                 :            :                 ret = -EINVAL;
    2027                 :            :                 goto error;
    2028                 :            :         }
    2029                 :            : 
    2030                 :            :         /* Check permissions. */
    2031                 :          0 :         if (resource->pid && (resource->pid != current->tgid)) {
    2032                 :          0 :                 pr_err("[%s]: current tgid %u != %u owner\n",
    2033                 :            :                         __func__, current->tgid, resource->pid);
    2034                 :            :                 ret = -EPERM;
    2035                 :          0 :                 goto error;
    2036                 :            :         }
    2037                 :            : 
    2038                 :          0 :         unlock.res_handle = resource->res_handle;
    2039                 :          0 :         unlock.res_mem = (uint32_t)resource->res_base_mem;
    2040                 :            : 
    2041                 :            :         pr_debug("[%s]: attempt to unlock data - guid %x, hdl %x, base address %p\n",
    2042                 :            :                 __func__, ioparam->handle, unlock.res_handle,
    2043                 :            :                 (void *)unlock.res_mem);
    2044                 :            : 
    2045                 :            :         /* User space allocated resources. */
    2046                 :          0 :         if (resource->pid) {
    2047                 :            :                 /* Flush if requested */
    2048                 :          0 :                 if (resource->res_cached && flush) {
    2049                 :            :                         dma_addr_t phys_addr = 0;
    2050                 :            : 
    2051                 :          0 :                         resource->res_stats[FLUSH]++;
    2052                 :            : 
    2053                 :            :                         phys_addr =
    2054                 :            :                             (dma_addr_t)((uint32_t)resource->res_base_mem &
    2055                 :            :                                          0x3FFFFFFF);
    2056                 :            :                         phys_addr += (dma_addr_t)mm_vc_mem_phys_addr;
    2057                 :            : 
    2058                 :            :                         /* L1 cache flush */
    2059                 :          0 :                         down_read(&current->mm->mmap_sem);
    2060                 :          0 :                         list_for_each_entry(map, &resource->map_list,
    2061                 :            :                                             resource_map_list) {
    2062                 :          0 :                                 if (map->vma) {
    2063                 :          0 :                                         const unsigned long start = map->vma->vm_start;
    2064                 :          0 :                                         const unsigned long end = map->vma->vm_end;
    2065                 :            : 
    2066                 :          0 :                                         ret = clean_invalid_mem_walk(start, end - start,
    2067                 :            :                                                         VCSM_CACHE_OP_FLUSH);
    2068                 :          0 :                                         if (ret)
    2069                 :            :                                                 goto error;
    2070                 :            :                                 }
    2071                 :            :                         }
    2072                 :          0 :                         up_read(&current->mm->mmap_sem);
    2073                 :            : 
    2074                 :            :                         /* L2 cache flush */
    2075                 :            :                         outer_clean_range(phys_addr,
    2076                 :            :                                           phys_addr +
    2077                 :            :                                           (size_t) resource->res_size);
    2078                 :            :                 }
    2079                 :            : 
    2080                 :            :                 /* We need to zap all the vmas associated with this resource */
    2081                 :          0 :                 if (resource->lock_count == 1) {
    2082                 :          0 :                         down_read(&current->mm->mmap_sem);
    2083                 :          0 :                         list_for_each_entry(map, &resource->map_list,
    2084                 :            :                                             resource_map_list) {
    2085                 :          0 :                                 if (map->vma) {
    2086                 :          0 :                                         zap_vma_ptes(map->vma,
    2087                 :            :                                                      map->vma->vm_start,
    2088                 :          0 :                                                      map->vma->vm_end -
    2089                 :          0 :                                                      map->vma->vm_start);
    2090                 :            :                                 }
    2091                 :            :                         }
    2092                 :          0 :                         up_read(&current->mm->mmap_sem);
    2093                 :            :                 }
    2094                 :            :         }
    2095                 :            :         /* Kernel allocated resources. */
    2096                 :            :         else {
    2097                 :            :                 /* Global + Taken in this context */
    2098                 :          0 :                 if (resource->ref_count == 2) {
    2099                 :          0 :                         if (!list_empty(&resource->map_list)) {
    2100                 :          0 :                                 list_for_each_entry_safe(map, map_tmp,
    2101                 :            :                                                 &resource->map_list,
    2102                 :            :                                                 resource_map_list) {
    2103                 :          0 :                                         if (map->res_addr) {
    2104                 :          0 :                                                 if (flush &&
    2105                 :          0 :                                                                 (resource->res_cached ==
    2106                 :            :                                                                         VMCS_SM_CACHE_HOST)) {
    2107                 :            :                                                         unsigned long
    2108                 :            :                                                                 phys_addr;
    2109                 :            :                                                         phys_addr = (uint32_t)
    2110                 :            :                                                                 resource->res_base_mem & 0x3FFFFFFF;
    2111                 :            :                                                         phys_addr +=
    2112                 :            :                                                                 mm_vc_mem_phys_addr;
    2113                 :            : 
    2114                 :            :                                                         /* L1 cache flush */
    2115                 :          0 :                                                         dmac_flush_range((const
    2116                 :            :                                                                                 void
    2117                 :            :                                                                                 *)
    2118                 :          0 :                                                                         map->res_addr, (const void *)
    2119                 :          0 :                                                                         (map->res_addr + resource->res_size));
    2120                 :            : 
    2121                 :            :                                                         /* L2 cache flush */
    2122                 :            :                                                         outer_clean_range
    2123                 :            :                                                                 (phys_addr,
    2124                 :            :                                                                  phys_addr +
    2125                 :            :                                                                  (size_t)
    2126                 :            :                                                                  resource->res_size);
    2127                 :            :                                                 }
    2128                 :            : 
    2129                 :          0 :                                                 iounmap((void *)map->res_addr);
    2130                 :          0 :                                                 map->res_addr = 0;
    2131                 :            : 
    2132                 :          0 :                                                 vmcs_sm_remove_map(sm_state,
    2133                 :            :                                                                 map->resource,
    2134                 :            :                                                                 map);
    2135                 :          0 :                                                 break;
    2136                 :            :                                         }
    2137                 :            :                                 }
    2138                 :            :                         }
    2139                 :            :                 }
    2140                 :            :         }
    2141                 :            : 
    2142                 :          0 :         if (resource->lock_count) {
    2143                 :            :                 /* Bypass the videocore unlock. */
    2144                 :          0 :                 if (no_vc_unlock)
    2145                 :            :                         status = 0;
    2146                 :            :                 /* Unlock the videocore allocated resource. */
    2147                 :            :                 else {
    2148                 :          0 :                         status =
    2149                 :          0 :                             vc_vchi_sm_unlock(sm_state->sm_handle, &unlock,
    2150                 :            :                                               &private->int_trans_id,
    2151                 :            :                                               wait_reply);
    2152                 :          0 :                         if (status == -EINTR) {
    2153                 :            :                                 pr_debug("[%s]: requesting unlock memory action restart (trans_id: %u)\n",
    2154                 :            :                                         __func__, private->int_trans_id);
    2155                 :            : 
    2156                 :            :                                 ret = -ERESTARTSYS;
    2157                 :          0 :                                 resource->res_stats[UNLOCK]--;
    2158                 :          0 :                                 private->restart_sys = -EINTR;
    2159                 :          0 :                                 private->int_action = VC_SM_MSG_TYPE_UNLOCK;
    2160                 :          0 :                                 goto error;
    2161                 :          0 :                         } else if (status != 0) {
    2162                 :          0 :                                 pr_err("[%s]: failed to unlock vc mem (status: %u, trans_id: %u)\n",
    2163                 :            :                                      __func__, status, private->int_trans_id);
    2164                 :            : 
    2165                 :            :                                 ret = -EPERM;
    2166                 :          0 :                                 resource->res_stats[UNLOCK_FAIL]++;
    2167                 :          0 :                                 goto error;
    2168                 :            :                         }
    2169                 :            :                 }
    2170                 :            : 
    2171                 :          0 :                 resource->res_stats[UNLOCK]++;
    2172                 :          0 :                 resource->lock_count--;
    2173                 :            :         }
    2174                 :            : 
    2175                 :            :         pr_debug("[%s]: success to unlock data - hdl %x, base address %p, ref-cnt %d\n",
    2176                 :            :                 __func__, unlock.res_handle, (void *)unlock.res_mem,
    2177                 :            :                 resource->lock_count);
    2178                 :            : 
    2179                 :            : error:
    2180                 :          0 :         if (resource)
    2181                 :          0 :                 vmcs_sm_release_resource(resource, 0);
    2182                 :            : 
    2183                 :          0 :         return ret;
    2184                 :            : }
    2185                 :            : 
    2186                 :            : /* Import a contiguous block of memory to be shared with VC. */
    2187                 :          0 : static int vc_sm_ioctl_import_dmabuf(struct sm_priv_data_t *private,
    2188                 :            :                                      struct vmcs_sm_ioctl_import_dmabuf *ioparam,
    2189                 :            :                                      struct dma_buf *src_dma_buf)
    2190                 :            : {
    2191                 :            :         int ret = 0;
    2192                 :            :         int status;
    2193                 :            :         struct sm_resource_t *resource = NULL;
    2194                 :          0 :         struct vc_sm_import import = { 0 };
    2195                 :          0 :         struct vc_sm_import_result result = { 0 };
    2196                 :            :         struct dma_buf *dma_buf;
    2197                 :            :         struct dma_buf_attachment *attach = NULL;
    2198                 :            :         struct sg_table *sgt = NULL;
    2199                 :            : 
    2200                 :            :         /* Setup our allocation parameters */
    2201                 :          0 :         if (src_dma_buf) {
    2202                 :          0 :                 get_dma_buf(src_dma_buf);
    2203                 :            :                 dma_buf = src_dma_buf;
    2204                 :            :         } else {
    2205                 :          0 :                 dma_buf = dma_buf_get(ioparam->dmabuf_fd);
    2206                 :            :         }
    2207                 :          0 :         if (IS_ERR(dma_buf))
    2208                 :          0 :                 return PTR_ERR(dma_buf);
    2209                 :            : 
    2210                 :          0 :         attach = dma_buf_attach(dma_buf, &sm_state->pdev->dev);
    2211                 :          0 :         if (IS_ERR(attach)) {
    2212                 :            :                 ret = PTR_ERR(attach);
    2213                 :          0 :                 goto error;
    2214                 :            :         }
    2215                 :            : 
    2216                 :          0 :         sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
    2217                 :          0 :         if (IS_ERR(sgt)) {
    2218                 :            :                 ret = PTR_ERR(sgt);
    2219                 :          0 :                 goto error;
    2220                 :            :         }
    2221                 :            : 
    2222                 :            :         /* Verify that the address block is contiguous */
    2223                 :          0 :         if (sgt->nents != 1) {
    2224                 :            :                 ret = -ENOMEM;
    2225                 :            :                 goto error;
    2226                 :            :         }
    2227                 :            : 
    2228                 :          0 :         import.type = ((ioparam->cached == VMCS_SM_CACHE_VC) ||
    2229                 :            :                        (ioparam->cached == VMCS_SM_CACHE_BOTH)) ?
    2230                 :          0 :                                 VC_SM_ALLOC_CACHED : VC_SM_ALLOC_NON_CACHED;
    2231                 :          0 :         import.addr = (uint32_t)sg_dma_address(sgt->sgl);
    2232                 :          0 :         import.size = sg_dma_len(sgt->sgl);
    2233                 :          0 :         import.allocator = current->tgid;
    2234                 :            : 
    2235                 :          0 :         if (*ioparam->name)
    2236                 :          0 :                 memcpy(import.name, ioparam->name, sizeof(import.name) - 1);
    2237                 :            :         else
    2238                 :          0 :                 memcpy(import.name, VMCS_SM_RESOURCE_NAME_DEFAULT,
    2239                 :            :                        sizeof(VMCS_SM_RESOURCE_NAME_DEFAULT));
    2240                 :            : 
    2241                 :            :         pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %p, size %u\n",
    2242                 :            :                  __func__, import.name, import.type,
    2243                 :            :                  (void *)import.addr, import.size);
    2244                 :            : 
    2245                 :            :         /* Allocate local resource to track this allocation. */
    2246                 :          0 :         resource = kzalloc(sizeof(*resource), GFP_KERNEL);
    2247                 :          0 :         if (!resource) {
    2248                 :            :                 ret = -ENOMEM;
    2249                 :            :                 goto error;
    2250                 :            :         }
    2251                 :          0 :         INIT_LIST_HEAD(&resource->map_list);
    2252                 :          0 :         resource->ref_count++;
    2253                 :          0 :         resource->pid = current->tgid;
    2254                 :            : 
    2255                 :            :         /* Allocate the videocore resource. */
    2256                 :          0 :         status = vc_vchi_sm_import(sm_state->sm_handle, &import, &result,
    2257                 :            :                                    &private->int_trans_id);
    2258                 :          0 :         if (status == -EINTR) {
    2259                 :            :                 pr_debug("[%s]: requesting import memory action restart (trans_id: %u)\n",
    2260                 :            :                          __func__, private->int_trans_id);
    2261                 :            :                 ret = -ERESTARTSYS;
    2262                 :          0 :                 private->restart_sys = -EINTR;
    2263                 :          0 :                 private->int_action = VC_SM_MSG_TYPE_IMPORT;
    2264                 :          0 :                 goto error;
    2265                 :          0 :         } else if (status || !result.res_handle) {
    2266                 :            :                 pr_debug("[%s]: failed to import memory on videocore (status: %u, trans_id: %u)\n",
    2267                 :            :                          __func__, status, private->int_trans_id);
    2268                 :            :                 ret = -ENOMEM;
    2269                 :          0 :                 resource->res_stats[ALLOC_FAIL]++;
    2270                 :          0 :                 goto error;
    2271                 :            :         }
    2272                 :            : 
    2273                 :            :         /* Keep track of the resource we created. */
    2274                 :          0 :         resource->private = private;
    2275                 :          0 :         resource->res_handle = result.res_handle;
    2276                 :          0 :         resource->res_size = import.size;
    2277                 :          0 :         resource->res_cached = ioparam->cached;
    2278                 :            : 
    2279                 :          0 :         resource->dma_buf = dma_buf;
    2280                 :          0 :         resource->attach = attach;
    2281                 :          0 :         resource->sgt = sgt;
    2282                 :          0 :         resource->dma_addr = sg_dma_address(sgt->sgl);
    2283                 :            : 
    2284                 :            :         /*
    2285                 :            :          * Kernel/user GUID.  This global identifier is used for mmap'ing the
    2286                 :            :          * allocated region from user space, it is passed as the mmap'ing
    2287                 :            :          * offset, we use it to 'hide' the videocore handle/address.
    2288                 :            :          */
    2289                 :          0 :         mutex_lock(&sm_state->lock);
    2290                 :          0 :         resource->res_guid = ++sm_state->guid;
    2291                 :          0 :         mutex_unlock(&sm_state->lock);
    2292                 :          0 :         resource->res_guid <<= PAGE_SHIFT;
    2293                 :            : 
    2294                 :          0 :         vmcs_sm_add_resource(private, resource);
    2295                 :            : 
    2296                 :            :         /* We're done */
    2297                 :          0 :         resource->res_stats[IMPORT]++;
    2298                 :          0 :         ioparam->handle = resource->res_guid;
    2299                 :          0 :         return 0;
    2300                 :            : 
    2301                 :            : error:
    2302                 :          0 :         if (resource) {
    2303                 :          0 :                 resource->res_stats[IMPORT_FAIL]++;
    2304                 :          0 :                 vc_sm_resource_deceased(resource, 1);
    2305                 :          0 :                 kfree(resource);
    2306                 :            :         }
    2307                 :          0 :         if (sgt)
    2308                 :          0 :                 dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
    2309                 :          0 :         if (attach)
    2310                 :          0 :                 dma_buf_detach(dma_buf, attach);
    2311                 :          0 :         dma_buf_put(dma_buf);
    2312                 :          0 :         return ret;
    2313                 :            : }
    2314                 :            : 
    2315                 :            : /* Handle control from host. */
    2316                 :          0 : static long vc_sm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    2317                 :            : {
    2318                 :            :         int ret = 0;
    2319                 :          0 :         unsigned int cmdnr = _IOC_NR(cmd);
    2320                 :          0 :         struct sm_priv_data_t *file_data =
    2321                 :            :             (struct sm_priv_data_t *)file->private_data;
    2322                 :            :         struct sm_resource_t *resource = NULL;
    2323                 :            : 
    2324                 :            :         /* Validate we can work with this device. */
    2325                 :          0 :         if ((sm_state == NULL) || (file_data == NULL)) {
    2326                 :          0 :                 pr_err("[%s]: invalid device\n", __func__);
    2327                 :            :                 ret = -EPERM;
    2328                 :          0 :                 goto out;
    2329                 :            :         }
    2330                 :            : 
    2331                 :            :         pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
    2332                 :            :                         current->tgid, file_data->pid);
    2333                 :            : 
    2334                 :            :         /* Action is a re-post of a previously interrupted action? */
    2335                 :          0 :         if (file_data->restart_sys == -EINTR) {
    2336                 :            :                 struct vc_sm_action_clean_t action_clean;
    2337                 :            : 
    2338                 :            :                 pr_debug("[%s]: clean up of action %u (trans_id: %u) following EINTR\n",
    2339                 :            :                         __func__, file_data->int_action,
    2340                 :            :                         file_data->int_trans_id);
    2341                 :            : 
    2342                 :          0 :                 action_clean.res_action = file_data->int_action;
    2343                 :          0 :                 action_clean.action_trans_id = file_data->int_trans_id;
    2344                 :            : 
    2345                 :          0 :                 vc_vchi_sm_clean_up(sm_state->sm_handle, &action_clean);
    2346                 :            : 
    2347                 :          0 :                 file_data->restart_sys = 0;
    2348                 :            :         }
    2349                 :            : 
    2350                 :            :         /* Now process the command. */
    2351                 :          0 :         switch (cmdnr) {
    2352                 :            :                 /* New memory allocation.
    2353                 :            :                  */
    2354                 :            :         case VMCS_SM_CMD_ALLOC:
    2355                 :            :                 {
    2356                 :            :                         struct vmcs_sm_ioctl_alloc ioparam;
    2357                 :            : 
    2358                 :            :                         /* Get the parameter data. */
    2359                 :          0 :                         if (copy_from_user
    2360                 :            :                             (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
    2361                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2362                 :            :                                                 __func__, cmdnr);
    2363                 :            :                                 ret = -EFAULT;
    2364                 :          0 :                                 goto out;
    2365                 :            :                         }
    2366                 :            : 
    2367                 :          0 :                         ret = vc_sm_ioctl_alloc(file_data, &ioparam);
    2368                 :          0 :                         if (!ret &&
    2369                 :          0 :                             (copy_to_user((void *)arg,
    2370                 :            :                                           &ioparam, sizeof(ioparam)) != 0)) {
    2371                 :          0 :                                 struct vmcs_sm_ioctl_free freeparam = {
    2372                 :          0 :                                         ioparam.handle
    2373                 :            :                                 };
    2374                 :          0 :                                 pr_err("[%s]: failed to copy-to-user for cmd %x\n",
    2375                 :            :                                                 __func__, cmdnr);
    2376                 :          0 :                                 vc_sm_ioctl_free(file_data, &freeparam);
    2377                 :            :                                 ret = -EFAULT;
    2378                 :            :                         }
    2379                 :            : 
    2380                 :            :                         /* Done. */
    2381                 :            :                         goto out;
    2382                 :            :                 }
    2383                 :            :                 break;
    2384                 :            : 
    2385                 :            :                 /* Share existing memory allocation. */
    2386                 :            :         case VMCS_SM_CMD_ALLOC_SHARE:
    2387                 :            :                 {
    2388                 :            :                         struct vmcs_sm_ioctl_alloc_share ioparam;
    2389                 :            : 
    2390                 :            :                         /* Get the parameter data. */
    2391                 :          0 :                         if (copy_from_user
    2392                 :            :                             (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
    2393                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2394                 :            :                                                 __func__, cmdnr);
    2395                 :            :                                 ret = -EFAULT;
    2396                 :          0 :                                 goto out;
    2397                 :            :                         }
    2398                 :            : 
    2399                 :          0 :                         ret = vc_sm_ioctl_alloc_share(file_data, &ioparam);
    2400                 :            : 
    2401                 :            :                         /* Copy result back to user. */
    2402                 :          0 :                         if (!ret
    2403                 :          0 :                             && copy_to_user((void *)arg, &ioparam,
    2404                 :            :                                             sizeof(ioparam)) != 0) {
    2405                 :          0 :                                 struct vmcs_sm_ioctl_free freeparam = {
    2406                 :          0 :                                         ioparam.handle
    2407                 :            :                                 };
    2408                 :          0 :                                 pr_err("[%s]: failed to copy-to-user for cmd %x\n",
    2409                 :            :                                                 __func__, cmdnr);
    2410                 :          0 :                                 vc_sm_ioctl_free(file_data, &freeparam);
    2411                 :            :                                 ret = -EFAULT;
    2412                 :            :                         }
    2413                 :            : 
    2414                 :            :                         /* Done. */
    2415                 :            :                         goto out;
    2416                 :            :                 }
    2417                 :            :                 break;
    2418                 :            : 
    2419                 :            :         case VMCS_SM_CMD_IMPORT_DMABUF:
    2420                 :            :                 {
    2421                 :            :                         struct vmcs_sm_ioctl_import_dmabuf ioparam;
    2422                 :            : 
    2423                 :            :                         /* Get the parameter data. */
    2424                 :          0 :                         if (copy_from_user
    2425                 :            :                             (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
    2426                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2427                 :            :                                        __func__, cmdnr);
    2428                 :            :                                 ret = -EFAULT;
    2429                 :          0 :                                 goto out;
    2430                 :            :                         }
    2431                 :            : 
    2432                 :          0 :                         ret = vc_sm_ioctl_import_dmabuf(file_data, &ioparam,
    2433                 :            :                                                         NULL);
    2434                 :          0 :                         if (!ret &&
    2435                 :          0 :                             (copy_to_user((void *)arg,
    2436                 :            :                                           &ioparam, sizeof(ioparam)) != 0)) {
    2437                 :          0 :                                 struct vmcs_sm_ioctl_free freeparam = {
    2438                 :          0 :                                         ioparam.handle
    2439                 :            :                                 };
    2440                 :          0 :                                 pr_err("[%s]: failed to copy-to-user for cmd %x\n",
    2441                 :            :                                        __func__, cmdnr);
    2442                 :          0 :                                 vc_sm_ioctl_free(file_data, &freeparam);
    2443                 :            :                                 ret = -EFAULT;
    2444                 :            :                         }
    2445                 :            : 
    2446                 :            :                         /* Done. */
    2447                 :            :                         goto out;
    2448                 :            :                 }
    2449                 :            :                 break;
    2450                 :            : 
    2451                 :            :                 /* Lock (attempt to) *and* register a cache behavior change. */
    2452                 :            :         case VMCS_SM_CMD_LOCK_CACHE:
    2453                 :            :                 {
    2454                 :            :                         struct vmcs_sm_ioctl_lock_cache ioparam;
    2455                 :            :                         struct vmcs_sm_ioctl_lock_unlock lock;
    2456                 :            : 
    2457                 :            :                         /* Get parameter data. */
    2458                 :          0 :                         if (copy_from_user
    2459                 :            :                             (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
    2460                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2461                 :            :                                                 __func__, cmdnr);
    2462                 :            :                                 ret = -EFAULT;
    2463                 :          0 :                                 goto out;
    2464                 :            :                         }
    2465                 :            : 
    2466                 :          0 :                         lock.handle = ioparam.handle;
    2467                 :          0 :                         ret =
    2468                 :          0 :                             vc_sm_ioctl_lock(file_data, &lock, 1,
    2469                 :            :                                              ioparam.cached, 0);
    2470                 :            : 
    2471                 :            :                         /* Done. */
    2472                 :          0 :                         goto out;
    2473                 :            :                 }
    2474                 :            :                 break;
    2475                 :            : 
    2476                 :            :                 /* Lock (attempt to) existing memory allocation. */
    2477                 :            :         case VMCS_SM_CMD_LOCK:
    2478                 :            :                 {
    2479                 :            :                         struct vmcs_sm_ioctl_lock_unlock ioparam;
    2480                 :            : 
    2481                 :            :                         /* Get parameter data. */
    2482                 :          0 :                         if (copy_from_user
    2483                 :            :                             (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
    2484                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2485                 :            :                                                 __func__, cmdnr);
    2486                 :            :                                 ret = -EFAULT;
    2487                 :          0 :                                 goto out;
    2488                 :            :                         }
    2489                 :            : 
    2490                 :          0 :                         ret = vc_sm_ioctl_lock(file_data, &ioparam, 0, 0, 0);
    2491                 :            : 
    2492                 :            :                         /* Copy result back to user. */
    2493                 :          0 :                         if (copy_to_user((void *)arg, &ioparam, sizeof(ioparam))
    2494                 :            :                             != 0) {
    2495                 :          0 :                                 pr_err("[%s]: failed to copy-to-user for cmd %x\n",
    2496                 :            :                                      __func__, cmdnr);
    2497                 :            :                                 ret = -EFAULT;
    2498                 :            :                         }
    2499                 :            : 
    2500                 :            :                         /* Done. */
    2501                 :            :                         goto out;
    2502                 :            :                 }
    2503                 :            :                 break;
    2504                 :            : 
    2505                 :            :                 /* Unlock (attempt to) existing memory allocation. */
    2506                 :            :         case VMCS_SM_CMD_UNLOCK:
    2507                 :            :                 {
    2508                 :            :                         struct vmcs_sm_ioctl_lock_unlock ioparam;
    2509                 :            : 
    2510                 :            :                         /* Get parameter data. */
    2511                 :          0 :                         if (copy_from_user
    2512                 :            :                             (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
    2513                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2514                 :            :                                                 __func__, cmdnr);
    2515                 :            :                                 ret = -EFAULT;
    2516                 :          0 :                                 goto out;
    2517                 :            :                         }
    2518                 :            : 
    2519                 :          0 :                         ret = vc_sm_ioctl_unlock(file_data, &ioparam, 0, 1, 0);
    2520                 :            : 
    2521                 :            :                         /* Done. */
    2522                 :          0 :                         goto out;
    2523                 :            :                 }
    2524                 :            :                 break;
    2525                 :            : 
    2526                 :            :                 /* Resize (attempt to) existing memory allocation. */
    2527                 :            :         case VMCS_SM_CMD_RESIZE:
    2528                 :            :                 {
    2529                 :            :                         struct vmcs_sm_ioctl_resize ioparam;
    2530                 :            : 
    2531                 :            :                         /* Get parameter data. */
    2532                 :          0 :                         if (copy_from_user
    2533                 :            :                             (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
    2534                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2535                 :            :                                                 __func__, cmdnr);
    2536                 :            :                                 ret = -EFAULT;
    2537                 :          0 :                                 goto out;
    2538                 :            :                         }
    2539                 :            : 
    2540                 :          0 :                         ret = vc_sm_ioctl_resize(file_data, &ioparam);
    2541                 :            : 
    2542                 :            :                         /* Copy result back to user. */
    2543                 :          0 :                         if (copy_to_user((void *)arg, &ioparam, sizeof(ioparam))
    2544                 :            :                             != 0) {
    2545                 :          0 :                                 pr_err("[%s]: failed to copy-to-user for cmd %x\n",
    2546                 :            :                                      __func__, cmdnr);
    2547                 :            :                                 ret = -EFAULT;
    2548                 :            :                         }
    2549                 :            :                         goto out;
    2550                 :            :                 }
    2551                 :            :                 break;
    2552                 :            : 
    2553                 :            :                 /* Terminate existing memory allocation.
    2554                 :            :                  */
    2555                 :            :         case VMCS_SM_CMD_FREE:
    2556                 :            :                 {
    2557                 :            :                         struct vmcs_sm_ioctl_free ioparam;
    2558                 :            : 
    2559                 :            :                         /* Get parameter data.
    2560                 :            :                          */
    2561                 :          0 :                         if (copy_from_user
    2562                 :            :                             (&ioparam, (void *)arg, sizeof(ioparam)) != 0) {
    2563                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2564                 :            :                                                 __func__, cmdnr);
    2565                 :            :                                 ret = -EFAULT;
    2566                 :          0 :                                 goto out;
    2567                 :            :                         }
    2568                 :            : 
    2569                 :          0 :                         ret = vc_sm_ioctl_free(file_data, &ioparam);
    2570                 :            : 
    2571                 :            :                         /* Done.
    2572                 :            :                          */
    2573                 :          0 :                         goto out;
    2574                 :            :                 }
    2575                 :            :                 break;
    2576                 :            : 
    2577                 :            :                 /* Walk allocation on videocore, information shows up in the
    2578                 :            :                  ** videocore log.
    2579                 :            :                  */
    2580                 :            :         case VMCS_SM_CMD_VC_WALK_ALLOC:
    2581                 :            :                 {
    2582                 :            :                         pr_debug("[%s]: invoking walk alloc\n", __func__);
    2583                 :            : 
    2584                 :          0 :                         if (vc_vchi_sm_walk_alloc(sm_state->sm_handle) != 0)
    2585                 :          0 :                                 pr_err("[%s]: failed to walk-alloc on videocore\n",
    2586                 :            :                                      __func__);
    2587                 :            : 
    2588                 :            :                         /* Done.
    2589                 :            :                          */
    2590                 :            :                         goto out;
    2591                 :            :                 }
    2592                 :            :                 break;
    2593                 :            :                 /* Walk mapping table on host, information shows up in the
    2594                 :            :                  ** kernel log.
    2595                 :            :                  */
    2596                 :            :         case VMCS_SM_CMD_HOST_WALK_MAP:
    2597                 :            :                 {
    2598                 :            :                         /* Use pid of -1 to tell to walk the whole map. */
    2599                 :          0 :                         vmcs_sm_host_walk_map_per_pid(-1);
    2600                 :            : 
    2601                 :            :                         /* Done. */
    2602                 :          0 :                         goto out;
    2603                 :            :                 }
    2604                 :            :                 break;
    2605                 :            : 
    2606                 :            :                 /* Walk mapping table per process on host.  */
    2607                 :            :         case VMCS_SM_CMD_HOST_WALK_PID_ALLOC:
    2608                 :            :                 {
    2609                 :            :                         struct vmcs_sm_ioctl_walk ioparam;
    2610                 :            : 
    2611                 :            :                         /* Get parameter data.  */
    2612                 :          0 :                         if (copy_from_user(&ioparam,
    2613                 :            :                                            (void *)arg, sizeof(ioparam)) != 0) {
    2614                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2615                 :            :                                                 __func__, cmdnr);
    2616                 :            :                                 ret = -EFAULT;
    2617                 :          0 :                                 goto out;
    2618                 :            :                         }
    2619                 :            : 
    2620                 :          0 :                         vmcs_sm_host_walk_alloc(file_data);
    2621                 :            : 
    2622                 :            :                         /* Done. */
    2623                 :          0 :                         goto out;
    2624                 :            :                 }
    2625                 :            :                 break;
    2626                 :            : 
    2627                 :            :                 /* Walk allocation per process on host.  */
    2628                 :            :         case VMCS_SM_CMD_HOST_WALK_PID_MAP:
    2629                 :            :                 {
    2630                 :            :                         struct vmcs_sm_ioctl_walk ioparam;
    2631                 :            : 
    2632                 :            :                         /* Get parameter data. */
    2633                 :          0 :                         if (copy_from_user(&ioparam,
    2634                 :            :                                            (void *)arg, sizeof(ioparam)) != 0) {
    2635                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2636                 :            :                                                 __func__, cmdnr);
    2637                 :            :                                 ret = -EFAULT;
    2638                 :          0 :                                 goto out;
    2639                 :            :                         }
    2640                 :            : 
    2641                 :          0 :                         vmcs_sm_host_walk_map_per_pid(ioparam.pid);
    2642                 :            : 
    2643                 :            :                         /* Done. */
    2644                 :          0 :                         goto out;
    2645                 :            :                 }
    2646                 :            :                 break;
    2647                 :            : 
    2648                 :            :                 /* Gets the size of the memory associated with a user handle. */
    2649                 :            :         case VMCS_SM_CMD_SIZE_USR_HANDLE:
    2650                 :            :                 {
    2651                 :            :                         struct vmcs_sm_ioctl_size ioparam;
    2652                 :            : 
    2653                 :            :                         /* Get parameter data. */
    2654                 :          0 :                         if (copy_from_user(&ioparam,
    2655                 :            :                                            (void *)arg, sizeof(ioparam)) != 0) {
    2656                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2657                 :            :                                                 __func__, cmdnr);
    2658                 :            :                                 ret = -EFAULT;
    2659                 :          0 :                                 goto out;
    2660                 :            :                         }
    2661                 :            : 
    2662                 :            :                         /* Locate resource from GUID. */
    2663                 :          0 :                         resource =
    2664                 :          0 :                             vmcs_sm_acquire_resource(file_data, ioparam.handle);
    2665                 :          0 :                         if (resource != NULL) {
    2666                 :          0 :                                 ioparam.size = resource->res_size;
    2667                 :          0 :                                 vmcs_sm_release_resource(resource, 0);
    2668                 :            :                         } else {
    2669                 :          0 :                                 ioparam.size = 0;
    2670                 :            :                         }
    2671                 :            : 
    2672                 :          0 :                         if (copy_to_user((void *)arg,
    2673                 :            :                                          &ioparam, sizeof(ioparam)) != 0) {
    2674                 :          0 :                                 pr_err("[%s]: failed to copy-to-user for cmd %x\n",
    2675                 :            :                                      __func__, cmdnr);
    2676                 :            :                                 ret = -EFAULT;
    2677                 :            :                         }
    2678                 :            : 
    2679                 :            :                         /* Done. */
    2680                 :            :                         goto out;
    2681                 :            :                 }
    2682                 :            :                 break;
    2683                 :            : 
    2684                 :            :                 /* Verify we are dealing with a valid resource. */
    2685                 :            :         case VMCS_SM_CMD_CHK_USR_HANDLE:
    2686                 :            :                 {
    2687                 :            :                         struct vmcs_sm_ioctl_chk ioparam;
    2688                 :            : 
    2689                 :            :                         /* Get parameter data. */
    2690                 :          0 :                         if (copy_from_user(&ioparam,
    2691                 :            :                                            (void *)arg, sizeof(ioparam)) != 0) {
    2692                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2693                 :            :                                                 __func__, cmdnr);
    2694                 :            : 
    2695                 :            :                                 ret = -EFAULT;
    2696                 :          0 :                                 goto out;
    2697                 :            :                         }
    2698                 :            : 
    2699                 :            :                         /* Locate resource from GUID. */
    2700                 :          0 :                         resource =
    2701                 :          0 :                             vmcs_sm_acquire_resource(file_data, ioparam.handle);
    2702                 :          0 :                         if (resource == NULL)
    2703                 :            :                                 ret = -EINVAL;
    2704                 :            :                         /*
    2705                 :            :                          * If the resource is cacheable, return additional
    2706                 :            :                          * information that may be needed to flush the cache.
    2707                 :            :                          */
    2708                 :          0 :                         else if ((resource->res_cached == VMCS_SM_CACHE_HOST) ||
    2709                 :            :                                  (resource->res_cached == VMCS_SM_CACHE_BOTH)) {
    2710                 :          0 :                                 ioparam.addr =
    2711                 :          0 :                                     vmcs_sm_usr_address_from_pid_and_usr_handle
    2712                 :          0 :                                     (current->tgid, ioparam.handle);
    2713                 :          0 :                                 ioparam.size = resource->res_size;
    2714                 :          0 :                                 ioparam.cache = resource->res_cached;
    2715                 :            :                         } else {
    2716                 :          0 :                                 ioparam.addr = 0;
    2717                 :          0 :                                 ioparam.size = 0;
    2718                 :          0 :                                 ioparam.cache = resource->res_cached;
    2719                 :            :                         }
    2720                 :            : 
    2721                 :          0 :                         if (resource)
    2722                 :          0 :                                 vmcs_sm_release_resource(resource, 0);
    2723                 :            : 
    2724                 :          0 :                         if (copy_to_user((void *)arg,
    2725                 :            :                                          &ioparam, sizeof(ioparam)) != 0) {
    2726                 :          0 :                                 pr_err("[%s]: failed to copy-to-user for cmd %x\n",
    2727                 :            :                                                 __func__, cmdnr);
    2728                 :            :                                 ret = -EFAULT;
    2729                 :            :                         }
    2730                 :            : 
    2731                 :            :                         /* Done. */
    2732                 :            :                         goto out;
    2733                 :            :                 }
    2734                 :            :                 break;
    2735                 :            : 
    2736                 :            :                 /*
    2737                 :            :                  * Maps a user handle given the process and the virtual address.
    2738                 :            :                  */
    2739                 :            :         case VMCS_SM_CMD_MAPPED_USR_HANDLE:
    2740                 :            :                 {
    2741                 :            :                         struct vmcs_sm_ioctl_map ioparam;
    2742                 :            : 
    2743                 :            :                         /* Get parameter data. */
    2744                 :          0 :                         if (copy_from_user(&ioparam,
    2745                 :            :                                            (void *)arg, sizeof(ioparam)) != 0) {
    2746                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2747                 :            :                                                 __func__, cmdnr);
    2748                 :            : 
    2749                 :            :                                 ret = -EFAULT;
    2750                 :          0 :                                 goto out;
    2751                 :            :                         }
    2752                 :            : 
    2753                 :          0 :                         ioparam.handle =
    2754                 :          0 :                             vmcs_sm_usr_handle_from_pid_and_address(
    2755                 :            :                                             ioparam.pid, ioparam.addr);
    2756                 :            : 
    2757                 :          0 :                         resource =
    2758                 :            :                             vmcs_sm_acquire_resource(file_data, ioparam.handle);
    2759                 :          0 :                         if ((resource != NULL)
    2760                 :          0 :                             && ((resource->res_cached == VMCS_SM_CACHE_HOST)
    2761                 :          0 :                                 || (resource->res_cached ==
    2762                 :            :                                     VMCS_SM_CACHE_BOTH))) {
    2763                 :          0 :                                 ioparam.size = resource->res_size;
    2764                 :            :                         } else {
    2765                 :          0 :                                 ioparam.size = 0;
    2766                 :            :                         }
    2767                 :            : 
    2768                 :          0 :                         if (resource)
    2769                 :          0 :                                 vmcs_sm_release_resource(resource, 0);
    2770                 :            : 
    2771                 :          0 :                         if (copy_to_user((void *)arg,
    2772                 :            :                                          &ioparam, sizeof(ioparam)) != 0) {
    2773                 :          0 :                                 pr_err("[%s]: failed to copy-to-user for cmd %x\n",
    2774                 :            :                                      __func__, cmdnr);
    2775                 :            :                                 ret = -EFAULT;
    2776                 :            :                         }
    2777                 :            : 
    2778                 :            :                         /* Done. */
    2779                 :            :                         goto out;
    2780                 :            :                 }
    2781                 :            :                 break;
    2782                 :            : 
    2783                 :            :                 /*
    2784                 :            :                  * Maps a videocore handle given process and virtual address.
    2785                 :            :                  */
    2786                 :            :         case VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR:
    2787                 :            :                 {
    2788                 :            :                         struct vmcs_sm_ioctl_map ioparam;
    2789                 :            : 
    2790                 :            :                         /* Get parameter data. */
    2791                 :          0 :                         if (copy_from_user(&ioparam,
    2792                 :            :                                            (void *)arg, sizeof(ioparam)) != 0) {
    2793                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2794                 :            :                                                 __func__, cmdnr);
    2795                 :            :                                 ret = -EFAULT;
    2796                 :          0 :                                 goto out;
    2797                 :            :                         }
    2798                 :            : 
    2799                 :          0 :                         ioparam.handle = vmcs_sm_vc_handle_from_pid_and_address(
    2800                 :            :                                             ioparam.pid, ioparam.addr);
    2801                 :            : 
    2802                 :          0 :                         if (copy_to_user((void *)arg,
    2803                 :            :                                          &ioparam, sizeof(ioparam)) != 0) {
    2804                 :          0 :                                 pr_err("[%s]: failed to copy-to-user for cmd %x\n",
    2805                 :            :                                      __func__, cmdnr);
    2806                 :            : 
    2807                 :            :                                 ret = -EFAULT;
    2808                 :            :                         }
    2809                 :            : 
    2810                 :            :                         /* Done. */
    2811                 :            :                         goto out;
    2812                 :            :                 }
    2813                 :            :                 break;
    2814                 :            : 
    2815                 :            :                 /* Maps a videocore handle given process and user handle. */
    2816                 :            :         case VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL:
    2817                 :            :                 {
    2818                 :            :                         struct vmcs_sm_ioctl_map ioparam;
    2819                 :            : 
    2820                 :            :                         /* Get parameter data. */
    2821                 :          0 :                         if (copy_from_user(&ioparam,
    2822                 :            :                                            (void *)arg, sizeof(ioparam)) != 0) {
    2823                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2824                 :            :                                                 __func__, cmdnr);
    2825                 :            :                                 ret = -EFAULT;
    2826                 :          0 :                                 goto out;
    2827                 :            :                         }
    2828                 :            : 
    2829                 :            :                         /* Locate resource from GUID. */
    2830                 :          0 :                         resource =
    2831                 :          0 :                             vmcs_sm_acquire_resource(file_data, ioparam.handle);
    2832                 :          0 :                         if (resource != NULL) {
    2833                 :          0 :                                 ioparam.handle = resource->res_handle;
    2834                 :          0 :                                 vmcs_sm_release_resource(resource, 0);
    2835                 :            :                         } else {
    2836                 :          0 :                                 ioparam.handle = 0;
    2837                 :            :                         }
    2838                 :            : 
    2839                 :          0 :                         if (copy_to_user((void *)arg,
    2840                 :            :                                          &ioparam, sizeof(ioparam)) != 0) {
    2841                 :          0 :                                 pr_err("[%s]: failed to copy-to-user for cmd %x\n",
    2842                 :            :                                      __func__, cmdnr);
    2843                 :            : 
    2844                 :            :                                 ret = -EFAULT;
    2845                 :            :                         }
    2846                 :            : 
    2847                 :            :                         /* Done. */
    2848                 :            :                         goto out;
    2849                 :            :                 }
    2850                 :            :                 break;
    2851                 :            : 
    2852                 :            :                 /*
    2853                 :            :                  * Maps a videocore address given process and videocore handle.
    2854                 :            :                  */
    2855                 :            :         case VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL:
    2856                 :            :                 {
    2857                 :            :                         struct vmcs_sm_ioctl_map ioparam;
    2858                 :            : 
    2859                 :            :                         /* Get parameter data. */
    2860                 :          0 :                         if (copy_from_user(&ioparam,
    2861                 :            :                                            (void *)arg, sizeof(ioparam)) != 0) {
    2862                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2863                 :            :                                                 __func__, cmdnr);
    2864                 :            : 
    2865                 :            :                                 ret = -EFAULT;
    2866                 :          0 :                                 goto out;
    2867                 :            :                         }
    2868                 :            : 
    2869                 :            :                         /* Locate resource from GUID. */
    2870                 :          0 :                         resource =
    2871                 :          0 :                             vmcs_sm_acquire_resource(file_data, ioparam.handle);
    2872                 :          0 :                         if (resource != NULL) {
    2873                 :          0 :                                 ioparam.addr =
    2874                 :          0 :                                         (unsigned int)resource->res_base_mem;
    2875                 :          0 :                                 vmcs_sm_release_resource(resource, 0);
    2876                 :            :                         } else {
    2877                 :          0 :                                 ioparam.addr = 0;
    2878                 :            :                         }
    2879                 :            : 
    2880                 :          0 :                         if (copy_to_user((void *)arg,
    2881                 :            :                                          &ioparam, sizeof(ioparam)) != 0) {
    2882                 :          0 :                                 pr_err("[%s]: failed to copy-to-user for cmd %x\n",
    2883                 :            :                                      __func__, cmdnr);
    2884                 :            :                                 ret = -EFAULT;
    2885                 :            :                         }
    2886                 :            : 
    2887                 :            :                         /* Done. */
    2888                 :            :                         goto out;
    2889                 :            :                 }
    2890                 :            :                 break;
    2891                 :            : 
    2892                 :            :                 /* Maps a user address given process and vc handle. */
    2893                 :            :         case VMCS_SM_CMD_MAPPED_USR_ADDRESS:
    2894                 :            :                 {
    2895                 :            :                         struct vmcs_sm_ioctl_map ioparam;
    2896                 :            : 
    2897                 :            :                         /* Get parameter data. */
    2898                 :          0 :                         if (copy_from_user(&ioparam,
    2899                 :            :                                            (void *)arg, sizeof(ioparam)) != 0) {
    2900                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2901                 :            :                                                 __func__, cmdnr);
    2902                 :            :                                 ret = -EFAULT;
    2903                 :          0 :                                 goto out;
    2904                 :            :                         }
    2905                 :            : 
    2906                 :            :                         /*
    2907                 :            :                          * Return the address information from the mapping,
    2908                 :            :                          * 0 (ie NULL) if it cannot locate the actual mapping.
    2909                 :            :                          */
    2910                 :          0 :                         ioparam.addr =
    2911                 :          0 :                             vmcs_sm_usr_address_from_pid_and_usr_handle
    2912                 :            :                             (ioparam.pid, ioparam.handle);
    2913                 :            : 
    2914                 :          0 :                         if (copy_to_user((void *)arg,
    2915                 :            :                                          &ioparam, sizeof(ioparam)) != 0) {
    2916                 :          0 :                                 pr_err("[%s]: failed to copy-to-user for cmd %x\n",
    2917                 :            :                                      __func__, cmdnr);
    2918                 :            :                                 ret = -EFAULT;
    2919                 :            :                         }
    2920                 :            : 
    2921                 :            :                         /* Done. */
    2922                 :            :                         goto out;
    2923                 :            :                 }
    2924                 :            :                 break;
    2925                 :            : 
    2926                 :            :                 /* Flush the cache for a given mapping. */
    2927                 :            :         case VMCS_SM_CMD_FLUSH:
    2928                 :            :                 {
    2929                 :            :                         struct vmcs_sm_ioctl_cache ioparam;
    2930                 :            : 
    2931                 :            :                         /* Get parameter data. */
    2932                 :          0 :                         if (copy_from_user(&ioparam,
    2933                 :            :                                            (void *)arg, sizeof(ioparam)) != 0) {
    2934                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2935                 :            :                                                 __func__, cmdnr);
    2936                 :            :                                 ret = -EFAULT;
    2937                 :          0 :                                 goto out;
    2938                 :            :                         }
    2939                 :            : 
    2940                 :            :                         /* Locate resource from GUID. */
    2941                 :          0 :                         resource =
    2942                 :          0 :                             vmcs_sm_acquire_resource(file_data, ioparam.handle);
    2943                 :          0 :                         if (resource == NULL) {
    2944                 :            :                                 ret = -EINVAL;
    2945                 :            :                                 goto out;
    2946                 :            :                         }
    2947                 :            : 
    2948                 :          0 :                         ret = clean_invalid_resource_walk((void __user*) ioparam.addr,
    2949                 :          0 :                                         ioparam.size, VCSM_CACHE_OP_FLUSH, ioparam.handle,
    2950                 :            :                                         resource);
    2951                 :          0 :                         vmcs_sm_release_resource(resource, 0);
    2952                 :          0 :                         if (ret)
    2953                 :            :                                 goto out;
    2954                 :            :                 }
    2955                 :          0 :                 break;
    2956                 :            : 
    2957                 :            :                 /* Invalidate the cache for a given mapping. */
    2958                 :            :         case VMCS_SM_CMD_INVALID:
    2959                 :            :                 {
    2960                 :            :                         struct vmcs_sm_ioctl_cache ioparam;
    2961                 :            : 
    2962                 :            :                         /* Get parameter data. */
    2963                 :          0 :                         if (copy_from_user(&ioparam,
    2964                 :            :                                            (void *)arg, sizeof(ioparam)) != 0) {
    2965                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2966                 :            :                                                 __func__, cmdnr);
    2967                 :            :                                 ret = -EFAULT;
    2968                 :          0 :                                 goto out;
    2969                 :            :                         }
    2970                 :            : 
    2971                 :            :                         /* Locate resource from GUID. */
    2972                 :          0 :                         resource =
    2973                 :          0 :                             vmcs_sm_acquire_resource(file_data, ioparam.handle);
    2974                 :          0 :                         if (resource == NULL) {
    2975                 :            :                                 ret = -EINVAL;
    2976                 :            :                                 goto out;
    2977                 :            :                         }
    2978                 :            : 
    2979                 :          0 :                         ret = clean_invalid_resource_walk((void __user*) ioparam.addr,
    2980                 :          0 :                                         ioparam.size, VCSM_CACHE_OP_INV, ioparam.handle, resource);
    2981                 :          0 :                         vmcs_sm_release_resource(resource, 0);
    2982                 :          0 :                         if (ret)
    2983                 :            :                                 goto out;
    2984                 :            :                 }
    2985                 :          0 :                 break;
    2986                 :            : 
    2987                 :            :         /* Flush/Invalidate the cache for a given mapping. */
    2988                 :            :         case VMCS_SM_CMD_CLEAN_INVALID:
    2989                 :            :                 {
    2990                 :            :                         int i;
    2991                 :            :                         struct vmcs_sm_ioctl_clean_invalid ioparam;
    2992                 :            : 
    2993                 :            :                         /* Get parameter data. */
    2994                 :          0 :                         if (copy_from_user(&ioparam,
    2995                 :            :                                            (void *)arg, sizeof(ioparam)) != 0) {
    2996                 :          0 :                                 pr_err("[%s]: failed to copy-from-user for cmd %x\n",
    2997                 :            :                                                 __func__, cmdnr);
    2998                 :            :                                 ret = -EFAULT;
    2999                 :          0 :                                 goto out;
    3000                 :            :                         }
    3001                 :          0 :                         for (i = 0; i < sizeof(ioparam.s) / sizeof(*ioparam.s); i++) {
    3002                 :          0 :                                 if (ioparam.s[i].cmd == VCSM_CACHE_OP_NOP)
    3003                 :            :                                         break;
    3004                 :            : 
    3005                 :            :                                 /* Locate resource from GUID. */
    3006                 :          0 :                                 resource =
    3007                 :          0 :                                         vmcs_sm_acquire_resource(file_data, ioparam.s[i].handle);
    3008                 :          0 :                                 if (resource == NULL) {
    3009                 :            :                                         ret = -EINVAL;
    3010                 :            :                                         goto out;
    3011                 :            :                                 }
    3012                 :            : 
    3013                 :          0 :                                 ret = clean_invalid_resource_walk(
    3014                 :          0 :                                                 (void __user*) ioparam.s[i].addr, ioparam.s[i].size,
    3015                 :          0 :                                                 ioparam.s[i].cmd, ioparam.s[i].handle, resource);
    3016                 :          0 :                                 vmcs_sm_release_resource(resource, 0);
    3017                 :          0 :                                 if (ret)
    3018                 :            :                                         goto out;
    3019                 :            :                         }
    3020                 :            :                 }
    3021                 :          0 :                 break;
    3022                 :            :         /*
    3023                 :            :          * Flush/Invalidate the cache for a given mapping.
    3024                 :            :          * Blocks must be pinned (i.e. accessed) before this call.
    3025                 :            :          */
    3026                 :            :         case VMCS_SM_CMD_CLEAN_INVALID2:
    3027                 :            :                 {
    3028                 :            :                                 int i;
    3029                 :            :                                 struct vmcs_sm_ioctl_clean_invalid2 ioparam;
    3030                 :            :                                 struct vmcs_sm_ioctl_clean_invalid_block *block = NULL;
    3031                 :            : 
    3032                 :            :                                 /* Get parameter data. */
    3033                 :          0 :                                 if (copy_from_user(&ioparam,
    3034                 :            :                                                    (void *)arg, sizeof(ioparam)) != 0) {
    3035                 :          0 :                                         pr_err("[%s]: failed to copy-from-user header for cmd %x\n",
    3036                 :            :                                                         __func__, cmdnr);
    3037                 :            :                                         ret = -EFAULT;
    3038                 :          0 :                                         goto out;
    3039                 :            :                                 }
    3040                 :          0 :                                 block = kmalloc(ioparam.op_count *
    3041                 :            :                                                 sizeof(struct vmcs_sm_ioctl_clean_invalid_block),
    3042                 :            :                                                 GFP_KERNEL);
    3043                 :          0 :                                 if (!block) {
    3044                 :            :                                         ret = -EFAULT;
    3045                 :            :                                         goto out;
    3046                 :            :                                 }
    3047                 :          0 :                                 if (copy_from_user(block,
    3048                 :          0 :                                                    (void *)(arg + sizeof(ioparam)), ioparam.op_count * sizeof(struct vmcs_sm_ioctl_clean_invalid_block)) != 0) {
    3049                 :          0 :                                         pr_err("[%s]: failed to copy-from-user payload for cmd %x\n",
    3050                 :            :                                                         __func__, cmdnr);
    3051                 :            :                                         ret = -EFAULT;
    3052                 :          0 :                                         goto out;
    3053                 :            :                                 }
    3054                 :            : 
    3055                 :          0 :                                 for (i = 0; i < ioparam.op_count; i++) {
    3056                 :          0 :                                         const struct vmcs_sm_ioctl_clean_invalid_block * const op = block + i;
    3057                 :            : 
    3058                 :          0 :                                         if (op->invalidate_mode == VCSM_CACHE_OP_NOP)
    3059                 :          0 :                                                 continue;
    3060                 :            : 
    3061                 :          0 :                                         ret = clean_invalid_contiguous_mem_2d(
    3062                 :          0 :                                                         (void __user*) op->start_address, op->block_count,
    3063                 :            :                                                         op->block_size, op->inter_block_stride,
    3064                 :            :                                                         op->invalidate_mode);
    3065                 :          0 :                                         if (ret)
    3066                 :            :                                                 break;
    3067                 :            :                                 }
    3068                 :          0 :                                 kfree(block);
    3069                 :            :                         }
    3070                 :          0 :                 break;
    3071                 :            : 
    3072                 :            :         default:
    3073                 :            :                 {
    3074                 :            :                         ret = -EINVAL;
    3075                 :            :                         goto out;
    3076                 :            :                 }
    3077                 :            :                 break;
    3078                 :            :         }
    3079                 :            : 
    3080                 :            : out:
    3081                 :          0 :         return ret;
    3082                 :            : }
    3083                 :            : 
    3084                 :            : /* Device operations that we managed in this driver. */
    3085                 :            : static const struct file_operations vmcs_sm_ops = {
    3086                 :            :         .owner = THIS_MODULE,
    3087                 :            :         .unlocked_ioctl = vc_sm_ioctl,
    3088                 :            :         .open = vc_sm_open,
    3089                 :            :         .release = vc_sm_release,
    3090                 :            :         .mmap = vc_sm_mmap,
    3091                 :            : };
    3092                 :            : 
    3093                 :            : /* Creation of device. */
    3094                 :          2 : static int vc_sm_create_sharedmemory(void)
    3095                 :            : {
    3096                 :            :         int ret;
    3097                 :            : 
    3098                 :          2 :         if (sm_state == NULL) {
    3099                 :            :                 ret = -ENOMEM;
    3100                 :            :                 goto out;
    3101                 :            :         }
    3102                 :            : 
    3103                 :            :         /* Create a device class for creating dev nodes. */
    3104                 :          2 :         sm_state->sm_class = class_create(THIS_MODULE, "vc-sm");
    3105                 :          2 :         if (IS_ERR(sm_state->sm_class)) {
    3106                 :          0 :                 pr_err("[%s]: unable to create device class\n", __func__);
    3107                 :          0 :                 ret = PTR_ERR(sm_state->sm_class);
    3108                 :          0 :                 goto out;
    3109                 :            :         }
    3110                 :            : 
    3111                 :            :         /* Create a character driver. */
    3112                 :          2 :         ret = alloc_chrdev_region(&sm_state->sm_devid,
    3113                 :            :                                   DEVICE_MINOR, 1, DEVICE_NAME);
    3114                 :          2 :         if (ret != 0) {
    3115                 :          0 :                 pr_err("[%s]: unable to allocate device number\n", __func__);
    3116                 :          0 :                 goto out_dev_class_destroy;
    3117                 :            :         }
    3118                 :            : 
    3119                 :          2 :         cdev_init(&sm_state->sm_cdev, &vmcs_sm_ops);
    3120                 :          2 :         ret = cdev_add(&sm_state->sm_cdev, sm_state->sm_devid, 1);
    3121                 :          2 :         if (ret != 0) {
    3122                 :          0 :                 pr_err("[%s]: unable to register device\n", __func__);
    3123                 :          0 :                 goto out_chrdev_unreg;
    3124                 :            :         }
    3125                 :            : 
    3126                 :            :         /* Create a device node. */
    3127                 :          2 :         sm_state->sm_dev = device_create(sm_state->sm_class,
    3128                 :            :                                          NULL,
    3129                 :          2 :                                          MKDEV(MAJOR(sm_state->sm_devid),
    3130                 :            :                                                DEVICE_MINOR), NULL,
    3131                 :            :                                          DEVICE_NAME);
    3132                 :          2 :         if (IS_ERR(sm_state->sm_dev)) {
    3133                 :          0 :                 pr_err("[%s]: unable to create device node\n", __func__);
    3134                 :          0 :                 ret = PTR_ERR(sm_state->sm_dev);
    3135                 :            :                 goto out_chrdev_del;
    3136                 :            :         }
    3137                 :            : 
    3138                 :            :         goto out;
    3139                 :            : 
    3140                 :            : out_chrdev_del:
    3141                 :          0 :         cdev_del(&sm_state->sm_cdev);
    3142                 :            : out_chrdev_unreg:
    3143                 :          0 :         unregister_chrdev_region(sm_state->sm_devid, 1);
    3144                 :            : out_dev_class_destroy:
    3145                 :          0 :         class_destroy(sm_state->sm_class);
    3146                 :          0 :         sm_state->sm_class = NULL;
    3147                 :            : out:
    3148                 :          2 :         return ret;
    3149                 :            : }
    3150                 :            : 
    3151                 :            : /* Termination of the device. */
    3152                 :          0 : static int vc_sm_remove_sharedmemory(void)
    3153                 :            : {
    3154                 :            :         int ret;
    3155                 :            : 
    3156                 :          0 :         if (sm_state == NULL) {
    3157                 :            :                 /* Nothing to do. */
    3158                 :            :                 ret = 0;
    3159                 :            :                 goto out;
    3160                 :            :         }
    3161                 :            : 
    3162                 :            :         /* Remove the sharedmemory character driver. */
    3163                 :          0 :         cdev_del(&sm_state->sm_cdev);
    3164                 :            : 
    3165                 :            :         /* Unregister region. */
    3166                 :          0 :         unregister_chrdev_region(sm_state->sm_devid, 1);
    3167                 :            : 
    3168                 :            :         ret = 0;
    3169                 :          0 :         goto out;
    3170                 :            : 
    3171                 :            : out:
    3172                 :          0 :         return ret;
    3173                 :            : }
    3174                 :            : 
    3175                 :            : /* Videocore connected.  */
    3176                 :          2 : static void vc_sm_connected_init(void)
    3177                 :            : {
    3178                 :            :         int ret;
    3179                 :            :         VCHI_INSTANCE_T vchi_instance;
    3180                 :            : 
    3181                 :          2 :         pr_info("[%s]: start\n", __func__);
    3182                 :            : 
    3183                 :            :         /*
    3184                 :            :          * Initialize and create a VCHI connection for the shared memory service
    3185                 :            :          * running on videocore.
    3186                 :            :          */
    3187                 :          2 :         ret = vchi_initialise(&vchi_instance);
    3188                 :          2 :         if (ret != 0) {
    3189                 :          0 :                 pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n",
    3190                 :            :                         __func__, ret);
    3191                 :            : 
    3192                 :            :                 ret = -EIO;
    3193                 :          0 :                 goto err_free_mem;
    3194                 :            :         }
    3195                 :            : 
    3196                 :          2 :         ret = vchi_connect(vchi_instance);
    3197                 :          2 :         if (ret != 0) {
    3198                 :          0 :                 pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
    3199                 :            :                         __func__, ret);
    3200                 :            : 
    3201                 :            :                 ret = -EIO;
    3202                 :          0 :                 goto err_free_mem;
    3203                 :            :         }
    3204                 :            : 
    3205                 :            :         /* Initialize an instance of the shared memory service. */
    3206                 :          2 :         sm_state->sm_handle =
    3207                 :          2 :             vc_vchi_sm_init(vchi_instance);
    3208                 :          2 :         if (sm_state->sm_handle == NULL) {
    3209                 :          0 :                 pr_err("[%s]: failed to initialize shared memory service\n",
    3210                 :            :                         __func__);
    3211                 :            : 
    3212                 :            :                 ret = -EPERM;
    3213                 :          0 :                 goto err_free_mem;
    3214                 :            :         }
    3215                 :            : 
    3216                 :            :         /* Create a debug fs directory entry (root). */
    3217                 :          2 :         sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL);
    3218                 :          2 :         if (!sm_state->dir_root) {
    3219                 :          0 :                 pr_err("[%s]: failed to create \'%s\' directory entry\n",
    3220                 :            :                         __func__, VC_SM_DIR_ROOT_NAME);
    3221                 :            : 
    3222                 :            :                 ret = -EPERM;
    3223                 :          0 :                 goto err_stop_sm_service;
    3224                 :            :         }
    3225                 :            : 
    3226                 :          2 :         sm_state->dir_state.show = &vc_sm_global_state_show;
    3227                 :          2 :         sm_state->dir_state.dir_entry = debugfs_create_file(VC_SM_STATE,
    3228                 :          2 :                         0444, sm_state->dir_root, &sm_state->dir_state,
    3229                 :            :                         &vc_sm_debug_fs_fops);
    3230                 :            : 
    3231                 :          2 :         sm_state->dir_stats.show = &vc_sm_global_statistics_show;
    3232                 :          2 :         sm_state->dir_stats.dir_entry = debugfs_create_file(VC_SM_STATS,
    3233                 :          2 :                         0444, sm_state->dir_root, &sm_state->dir_stats,
    3234                 :            :                         &vc_sm_debug_fs_fops);
    3235                 :            : 
    3236                 :            :         /* Create the proc entry children. */
    3237                 :          2 :         sm_state->dir_alloc = debugfs_create_dir(VC_SM_DIR_ALLOC_NAME,
    3238                 :          2 :                         sm_state->dir_root);
    3239                 :            : 
    3240                 :            :         /* Create a shared memory device. */
    3241                 :          2 :         ret = vc_sm_create_sharedmemory();
    3242                 :          2 :         if (ret != 0) {
    3243                 :          0 :                 pr_err("[%s]: failed to create shared memory device\n",
    3244                 :            :                         __func__);
    3245                 :          0 :                 goto err_remove_debugfs;
    3246                 :            :         }
    3247                 :            : 
    3248                 :          2 :         INIT_LIST_HEAD(&sm_state->map_list);
    3249                 :          2 :         INIT_LIST_HEAD(&sm_state->resource_list);
    3250                 :            : 
    3251                 :          2 :         sm_state->data_knl = vc_sm_create_priv_data(0);
    3252                 :          2 :         if (sm_state->data_knl == NULL) {
    3253                 :          0 :                 pr_err("[%s]: failed to create kernel private data tracker\n",
    3254                 :            :                         __func__);
    3255                 :            :                 goto err_remove_shared_memory;
    3256                 :            :         }
    3257                 :            : 
    3258                 :            :         /* Done! */
    3259                 :          2 :         sm_inited = 1;
    3260                 :          2 :         goto out;
    3261                 :            : 
    3262                 :            : err_remove_shared_memory:
    3263                 :          0 :         vc_sm_remove_sharedmemory();
    3264                 :            : err_remove_debugfs:
    3265                 :          0 :         debugfs_remove_recursive(sm_state->dir_root);
    3266                 :            : err_stop_sm_service:
    3267                 :          0 :         vc_vchi_sm_stop(&sm_state->sm_handle);
    3268                 :            : err_free_mem:
    3269                 :          0 :         kfree(sm_state);
    3270                 :            : out:
    3271                 :          2 :         pr_info("[%s]: end - returning %d\n", __func__, ret);
    3272                 :          2 : }
    3273                 :            : 
    3274                 :            : /* Driver loading. */
    3275                 :          3 : static int bcm2835_vcsm_probe(struct platform_device *pdev)
    3276                 :            : {
    3277                 :          3 :         pr_info("vc-sm: Videocore shared memory driver\n");
    3278                 :            : 
    3279                 :          3 :         sm_state = kzalloc(sizeof(*sm_state), GFP_KERNEL);
    3280                 :          3 :         if (!sm_state)
    3281                 :            :                 return -ENOMEM;
    3282                 :          3 :         sm_state->pdev = pdev;
    3283                 :          3 :         mutex_init(&sm_state->lock);
    3284                 :          3 :         mutex_init(&sm_state->map_lock);
    3285                 :            : 
    3286                 :          3 :         vchiq_add_connected_callback(vc_sm_connected_init);
    3287                 :          3 :         return 0;
    3288                 :            : }
    3289                 :            : 
    3290                 :            : /* Driver unloading. */
    3291                 :          0 : static int bcm2835_vcsm_remove(struct platform_device *pdev)
    3292                 :            : {
    3293                 :            :         pr_debug("[%s]: start\n", __func__);
    3294                 :          0 :         if (sm_inited) {
    3295                 :            :                 /* Remove shared memory device. */
    3296                 :          0 :                 vc_sm_remove_sharedmemory();
    3297                 :            : 
    3298                 :            :                 /* Remove all proc entries. */
    3299                 :          0 :                 debugfs_remove_recursive(sm_state->dir_root);
    3300                 :            : 
    3301                 :            :                 /* Stop the videocore shared memory service. */
    3302                 :          0 :                 vc_vchi_sm_stop(&sm_state->sm_handle);
    3303                 :            : 
    3304                 :            :                 /* Free the memory for the state structure. */
    3305                 :            :                 mutex_destroy(&(sm_state->map_lock));
    3306                 :          0 :                 kfree(sm_state);
    3307                 :            :         }
    3308                 :            : 
    3309                 :            :         pr_debug("[%s]: end\n", __func__);
    3310                 :          0 :         return 0;
    3311                 :            : }
    3312                 :            : 
    3313                 :            : #if defined(__KERNEL__)
    3314                 :            : /* Allocate a shared memory handle and block. */
    3315                 :          0 : int vc_sm_alloc(struct vc_sm_alloc_t *alloc, int *handle)
    3316                 :            : {
    3317                 :          0 :         struct vmcs_sm_ioctl_alloc ioparam = { 0 };
    3318                 :            :         int ret;
    3319                 :            :         struct sm_resource_t *resource;
    3320                 :            : 
    3321                 :            :         /* Validate we can work with this device. */
    3322                 :          0 :         if (sm_state == NULL || alloc == NULL || handle == NULL) {
    3323                 :          0 :                 pr_err("[%s]: invalid input\n", __func__);
    3324                 :          0 :                 return -EPERM;
    3325                 :            :         }
    3326                 :            : 
    3327                 :          0 :         ioparam.size = alloc->base_unit;
    3328                 :          0 :         ioparam.num = alloc->num_unit;
    3329                 :          0 :         ioparam.cached =
    3330                 :          0 :             alloc->type == VC_SM_ALLOC_CACHED ? VMCS_SM_CACHE_VC : 0;
    3331                 :            : 
    3332                 :          0 :         ret = vc_sm_ioctl_alloc(sm_state->data_knl, &ioparam);
    3333                 :            : 
    3334                 :          0 :         if (ret == 0) {
    3335                 :          0 :                 resource =
    3336                 :          0 :                     vmcs_sm_acquire_resource(sm_state->data_knl,
    3337                 :            :                                              ioparam.handle);
    3338                 :          0 :                 if (resource) {
    3339                 :          0 :                         resource->pid = 0;
    3340                 :          0 :                         vmcs_sm_release_resource(resource, 0);
    3341                 :            : 
    3342                 :            :                         /* Assign valid handle at this time. */
    3343                 :          0 :                         *handle = ioparam.handle;
    3344                 :            :                 } else {
    3345                 :            :                         ret = -ENOMEM;
    3346                 :            :                 }
    3347                 :            :         }
    3348                 :            : 
    3349                 :          0 :         return ret;
    3350                 :            : }
    3351                 :            : EXPORT_SYMBOL_GPL(vc_sm_alloc);
    3352                 :            : 
    3353                 :            : /* Get an internal resource handle mapped from the external one. */
    3354                 :          0 : int vc_sm_int_handle(int handle)
    3355                 :            : {
    3356                 :            :         struct sm_resource_t *resource;
    3357                 :            :         int ret = 0;
    3358                 :            : 
    3359                 :            :         /* Validate we can work with this device. */
    3360                 :          0 :         if (sm_state == NULL || handle == 0) {
    3361                 :          0 :                 pr_err("[%s]: invalid input\n", __func__);
    3362                 :          0 :                 return 0;
    3363                 :            :         }
    3364                 :            : 
    3365                 :            :         /* Locate resource from GUID. */
    3366                 :          0 :         resource = vmcs_sm_acquire_resource(sm_state->data_knl, handle);
    3367                 :          0 :         if (resource) {
    3368                 :          0 :                 ret = resource->res_handle;
    3369                 :          0 :                 vmcs_sm_release_resource(resource, 0);
    3370                 :            :         }
    3371                 :            : 
    3372                 :          0 :         return ret;
    3373                 :            : }
    3374                 :            : EXPORT_SYMBOL_GPL(vc_sm_int_handle);
    3375                 :            : 
    3376                 :            : /* Free a previously allocated shared memory handle and block. */
    3377                 :          0 : int vc_sm_free(int handle)
    3378                 :            : {
    3379                 :          0 :         struct vmcs_sm_ioctl_free ioparam = { handle };
    3380                 :            : 
    3381                 :            :         /* Validate we can work with this device. */
    3382                 :          0 :         if (sm_state == NULL || handle == 0) {
    3383                 :          0 :                 pr_err("[%s]: invalid input\n", __func__);
    3384                 :          0 :                 return -EPERM;
    3385                 :            :         }
    3386                 :            : 
    3387                 :          0 :         return vc_sm_ioctl_free(sm_state->data_knl, &ioparam);
    3388                 :            : }
    3389                 :            : EXPORT_SYMBOL_GPL(vc_sm_free);
    3390                 :            : 
    3391                 :            : /* Lock a memory handle for use by kernel. */
    3392                 :          0 : int vc_sm_lock(int handle, enum vc_sm_lock_cache_mode mode,
    3393                 :            :                unsigned long *data)
    3394                 :            : {
    3395                 :            :         struct vmcs_sm_ioctl_lock_unlock ioparam;
    3396                 :            :         int ret;
    3397                 :            : 
    3398                 :            :         /* Validate we can work with this device. */
    3399                 :          0 :         if (sm_state == NULL || handle == 0 || data == NULL) {
    3400                 :          0 :                 pr_err("[%s]: invalid input\n", __func__);
    3401                 :          0 :                 return -EPERM;
    3402                 :            :         }
    3403                 :            : 
    3404                 :          0 :         *data = 0;
    3405                 :            : 
    3406                 :          0 :         ioparam.handle = handle;
    3407                 :          0 :         ret = vc_sm_ioctl_lock(sm_state->data_knl,
    3408                 :            :                                &ioparam,
    3409                 :            :                                1,
    3410                 :            :                                ((mode ==
    3411                 :            :                                  VC_SM_LOCK_CACHED) ? VMCS_SM_CACHE_HOST :
    3412                 :            :                                 VMCS_SM_CACHE_NONE), 0);
    3413                 :            : 
    3414                 :          0 :         *data = ioparam.addr;
    3415                 :          0 :         return ret;
    3416                 :            : }
    3417                 :            : EXPORT_SYMBOL_GPL(vc_sm_lock);
    3418                 :            : 
    3419                 :            : /* Unlock a memory handle in use by kernel. */
    3420                 :          0 : int vc_sm_unlock(int handle, int flush, int no_vc_unlock)
    3421                 :            : {
    3422                 :            :         struct vmcs_sm_ioctl_lock_unlock ioparam;
    3423                 :            : 
    3424                 :            :         /* Validate we can work with this device. */
    3425                 :          0 :         if (sm_state == NULL || handle == 0) {
    3426                 :          0 :                 pr_err("[%s]: invalid input\n", __func__);
    3427                 :          0 :                 return -EPERM;
    3428                 :            :         }
    3429                 :            : 
    3430                 :          0 :         ioparam.handle = handle;
    3431                 :          0 :         return vc_sm_ioctl_unlock(sm_state->data_knl,
    3432                 :            :                                   &ioparam, flush, 0, no_vc_unlock);
    3433                 :            : }
    3434                 :            : EXPORT_SYMBOL_GPL(vc_sm_unlock);
    3435                 :            : 
    3436                 :            : /* Map a shared memory region for use by kernel. */
    3437                 :          0 : int vc_sm_map(int handle, unsigned int sm_addr,
    3438                 :            :               enum vc_sm_lock_cache_mode mode, unsigned long *data)
    3439                 :            : {
    3440                 :            :         struct vmcs_sm_ioctl_lock_unlock ioparam;
    3441                 :            :         int ret;
    3442                 :            : 
    3443                 :            :         /* Validate we can work with this device. */
    3444                 :          0 :         if (sm_state == NULL || handle == 0 || data == NULL || sm_addr == 0) {
    3445                 :          0 :                 pr_err("[%s]: invalid input\n", __func__);
    3446                 :          0 :                 return -EPERM;
    3447                 :            :         }
    3448                 :            : 
    3449                 :          0 :         *data = 0;
    3450                 :            : 
    3451                 :          0 :         ioparam.handle = handle;
    3452                 :          0 :         ret = vc_sm_ioctl_lock(sm_state->data_knl,
    3453                 :            :                                &ioparam,
    3454                 :            :                                1,
    3455                 :            :                                ((mode ==
    3456                 :            :                                  VC_SM_LOCK_CACHED) ? VMCS_SM_CACHE_HOST :
    3457                 :            :                                 VMCS_SM_CACHE_NONE), sm_addr);
    3458                 :            : 
    3459                 :          0 :         *data = ioparam.addr;
    3460                 :          0 :         return ret;
    3461                 :            : }
    3462                 :            : EXPORT_SYMBOL_GPL(vc_sm_map);
    3463                 :            : 
    3464                 :            : /* Import a dmabuf to be shared with VC. */
    3465                 :          0 : int vc_sm_import_dmabuf(struct dma_buf *dmabuf, int *handle)
    3466                 :            : {
    3467                 :          0 :         struct vmcs_sm_ioctl_import_dmabuf ioparam = { 0 };
    3468                 :            :         int ret;
    3469                 :            :         struct sm_resource_t *resource;
    3470                 :            : 
    3471                 :            :         /* Validate we can work with this device. */
    3472                 :          0 :         if (!sm_state || !dmabuf || !handle) {
    3473                 :          0 :                 pr_err("[%s]: invalid input\n", __func__);
    3474                 :          0 :                 return -EPERM;
    3475                 :            :         }
    3476                 :            : 
    3477                 :            :         ioparam.cached = 0;
    3478                 :          0 :         strcpy(ioparam.name, "KRNL DMABUF");
    3479                 :            : 
    3480                 :          0 :         ret = vc_sm_ioctl_import_dmabuf(sm_state->data_knl, &ioparam, dmabuf);
    3481                 :            : 
    3482                 :          0 :         if (!ret) {
    3483                 :          0 :                 resource = vmcs_sm_acquire_resource(sm_state->data_knl,
    3484                 :            :                                                     ioparam.handle);
    3485                 :          0 :                 if (resource) {
    3486                 :          0 :                         resource->pid = 0;
    3487                 :          0 :                         vmcs_sm_release_resource(resource, 0);
    3488                 :            : 
    3489                 :            :                         /* Assign valid handle at this time.*/
    3490                 :          0 :                         *handle = ioparam.handle;
    3491                 :            :                 } else {
    3492                 :            :                         ret = -ENOMEM;
    3493                 :            :                 }
    3494                 :            :         }
    3495                 :            : 
    3496                 :          0 :         return ret;
    3497                 :            : }
    3498                 :            : EXPORT_SYMBOL_GPL(vc_sm_import_dmabuf);
    3499                 :            : #endif
    3500                 :            : 
    3501                 :            : /*
    3502                 :            :  *   Register the driver with device tree
    3503                 :            :  */
    3504                 :            : 
    3505                 :            : static const struct of_device_id bcm2835_vcsm_of_match[] = {
    3506                 :            :         {.compatible = "raspberrypi,bcm2835-vcsm",},
    3507                 :            :         { /* sentinel */ },
    3508                 :            : };
    3509                 :            : 
    3510                 :            : MODULE_DEVICE_TABLE(of, bcm2835_vcsm_of_match);
    3511                 :            : 
    3512                 :            : static struct platform_driver bcm2835_vcsm_driver = {
    3513                 :            :         .probe = bcm2835_vcsm_probe,
    3514                 :            :         .remove = bcm2835_vcsm_remove,
    3515                 :            :         .driver = {
    3516                 :            :                    .name = DRIVER_NAME,
    3517                 :            :                    .owner = THIS_MODULE,
    3518                 :            :                    .of_match_table = bcm2835_vcsm_of_match,
    3519                 :            :                    },
    3520                 :            : };
    3521                 :            : 
    3522                 :          3 : module_platform_driver(bcm2835_vcsm_driver);
    3523                 :            : 
    3524                 :            : MODULE_AUTHOR("Broadcom");
    3525                 :            : MODULE_DESCRIPTION("VideoCore SharedMemory Driver");
    3526                 :            : MODULE_LICENSE("GPL v2");
    

Generated by: LCOV version 1.14