1/* 2 * Copyright (C) ST-Ericsson AB 2010 3 * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com 4 * Author: Amarnath Revanna / amarnath.bangalore.revanna@stericsson.com 5 * License terms: GNU General Public License (GPL) version 2 6 */ 7 8#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt 9 10#include <linux/init.h> 11#include <linux/module.h> 12#include <linux/netdevice.h> 13#include <mach/mbox-db5500.h> 14#include <net/caif/caif_shm.h> 15 16MODULE_LICENSE("GPL"); 17MODULE_DESCRIPTION("CAIF Shared Memory protocol driver"); 18 19#define MAX_SHM_INSTANCES 1 20 21enum { 22 MBX_ACC0, 23 MBX_ACC1, 24 MBX_DSP 25}; 26 27static struct shmdev_layer shmdev_lyr[MAX_SHM_INSTANCES]; 28 29static unsigned int shm_start; 30static unsigned int shm_size; 31 32module_param(shm_size, uint , 0440); 33MODULE_PARM_DESC(shm_total_size, "Start of SHM shared memory"); 34 35module_param(shm_start, uint , 0440); 36MODULE_PARM_DESC(shm_total_start, "Total Size of SHM shared memory"); 37 38static int shmdev_send_msg(u32 dev_id, u32 mbx_msg) 39{ 40 /* Always block until msg is written successfully */ 41 mbox_send(shmdev_lyr[dev_id].hmbx, mbx_msg, true); 42 return 0; 43} 44 45static int shmdev_mbx_setup(void *pshmdrv_cb, struct shmdev_layer *pshm_dev, 46 void *pshm_drv) 47{ 48 /* 49 * For UX5500, we have only 1 SHM instance which uses MBX0 50 * for communication with the peer modem 51 */ 52 pshm_dev->hmbx = mbox_setup(MBX_ACC0, pshmdrv_cb, pshm_drv); 53 54 if (!pshm_dev->hmbx) 55 return -ENODEV; 56 else 57 return 0; 58} 59 60static int __init caif_shmdev_init(void) 61{ 62 int i, result; 63 64 /* Loop is currently overkill, there is only one instance */ 65 for (i = 0; i < MAX_SHM_INSTANCES; i++) { 66 67 shmdev_lyr[i].shm_base_addr = shm_start; 68 shmdev_lyr[i].shm_total_sz = shm_size; 69 70 if (((char *)shmdev_lyr[i].shm_base_addr == NULL) 71 || (shmdev_lyr[i].shm_total_sz <= 0)) { 72 pr_warn("ERROR," 73 "Shared memory Address and/or Size incorrect" 74 ", Bailing out ...\n"); 75 result = -EINVAL; 76 goto clean; 77 } 78 79 pr_info("SHM AREA (instance %d) STARTS" 80 " AT %p\n", i, (char *)shmdev_lyr[i].shm_base_addr); 81 82 shmdev_lyr[i].shm_id = i; 83 shmdev_lyr[i].pshmdev_mbxsend = shmdev_send_msg; 84 shmdev_lyr[i].pshmdev_mbxsetup = shmdev_mbx_setup; 85 86 /* 87 * Finally, CAIF core module is called with details in place: 88 * 1. SHM base address 89 * 2. SHM size 90 * 3. MBX handle 91 */ 92 result = caif_shmcore_probe(&shmdev_lyr[i]); 93 if (result) { 94 pr_warn("ERROR[%d]," 95 "Could not probe SHM core (instance %d)" 96 " Bailing out ...\n", result, i); 97 goto clean; 98 } 99 } 100 101 return 0; 102 103clean: 104 /* 105 * For now, we assume that even if one instance of SHM fails, we bail 106 * out of the driver support completely. For this, we need to release 107 * any memory allocated and unregister any instance of SHM net device. 108 */ 109 for (i = 0; i < MAX_SHM_INSTANCES; i++) { 110 if (shmdev_lyr[i].pshm_netdev) 111 unregister_netdev(shmdev_lyr[i].pshm_netdev); 112 } 113 return result; 114} 115 116static void __exit caif_shmdev_exit(void) 117{ 118 int i; 119 120 for (i = 0; i < MAX_SHM_INSTANCES; i++) { 121 caif_shmcore_remove(shmdev_lyr[i].pshm_netdev); 122 kfree((void *)shmdev_lyr[i].shm_base_addr); 123 } 124 125} 126 127module_init(caif_shmdev_init); 128module_exit(caif_shmdev_exit); 129