123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565 |
- /* arch/arm/mach-msm/smd_rpcrouter.c
- *
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2013, The Linux Foundation. All rights reserved.
- * Author: San Mehat <san@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
- /* TODO: handle cases where smd_write() will tempfail due to full fifo */
- /* TODO: thread priority? schedule a work to bump it? */
- /* TODO: maybe make server_list_lock a mutex */
- /* TODO: pool fragments to avoid kmalloc/kfree churn */
- #include <linux/slab.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/string.h>
- #include <linux/errno.h>
- #include <linux/cdev.h>
- #include <linux/init.h>
- #include <linux/device.h>
- #include <linux/types.h>
- #include <linux/delay.h>
- #include <linux/fs.h>
- #include <linux/err.h>
- #include <linux/sched.h>
- #include <linux/poll.h>
- #include <linux/wakelock.h>
- #include <asm/uaccess.h>
- #include <asm/byteorder.h>
- #include <linux/platform_device.h>
- #include <linux/uaccess.h>
- #include <linux/debugfs.h>
- #include <linux/reboot.h>
- #include <asm/byteorder.h>
- #include <mach/msm_smd.h>
- #include <mach/smem_log.h>
- #include <mach/subsystem_notif.h>
- #include "smd_rpcrouter.h"
- #include "modem_notifier.h"
- #include "smd_rpc_sym.h"
- #include "smd_private.h"
- enum {
- SMEM_LOG = 1U << 0,
- RTR_DBG = 1U << 1,
- R2R_MSG = 1U << 2,
- R2R_RAW = 1U << 3,
- RPC_MSG = 1U << 4,
- NTFY_MSG = 1U << 5,
- RAW_PMR = 1U << 6,
- RAW_PMW = 1U << 7,
- R2R_RAW_HDR = 1U << 8,
- };
- static int msm_rpc_connect_timeout_ms;
- module_param_named(connect_timeout, msm_rpc_connect_timeout_ms,
- int, S_IRUGO | S_IWUSR | S_IWGRP);
- static int smd_rpcrouter_debug_mask;
- module_param_named(debug_mask, smd_rpcrouter_debug_mask,
- int, S_IRUGO | S_IWUSR | S_IWGRP);
- #define DIAG(x...) printk(KERN_ERR "[RR] ERROR " x)
- #if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
- #define D(x...) do { \
- if (smd_rpcrouter_debug_mask & RTR_DBG) \
- printk(KERN_ERR x); \
- } while (0)
- #define RR(x...) do { \
- if (smd_rpcrouter_debug_mask & R2R_MSG) \
- printk(KERN_ERR "[RR] "x); \
- } while (0)
- #define RAW(x...) do { \
- if (smd_rpcrouter_debug_mask & R2R_RAW) \
- printk(KERN_ERR "[RAW] "x); \
- } while (0)
- #define RAW_HDR(x...) do { \
- if (smd_rpcrouter_debug_mask & R2R_RAW_HDR) \
- printk(KERN_ERR "[HDR] "x); \
- } while (0)
- #define RAW_PMR(x...) do { \
- if (smd_rpcrouter_debug_mask & RAW_PMR) \
- printk(KERN_ERR "[PMR] "x); \
- } while (0)
- #define RAW_PMR_NOMASK(x...) do { \
- printk(KERN_ERR "[PMR] "x); \
- } while (0)
- #define RAW_PMW(x...) do { \
- if (smd_rpcrouter_debug_mask & RAW_PMW) \
- printk(KERN_ERR "[PMW] "x); \
- } while (0)
- #define RAW_PMW_NOMASK(x...) do { \
- printk(KERN_ERR "[PMW] "x); \
- } while (0)
- #define IO(x...) do { \
- if (smd_rpcrouter_debug_mask & RPC_MSG) \
- printk(KERN_ERR "[RPC] "x); \
- } while (0)
- #define NTFY(x...) do { \
- if (smd_rpcrouter_debug_mask & NTFY_MSG) \
- printk(KERN_ERR "[NOTIFY] "x); \
- } while (0)
- #else
- #define D(x...) do { } while (0)
- #define RR(x...) do { } while (0)
- #define RAW(x...) do { } while (0)
- #define RAW_HDR(x...) do { } while (0)
- #define RAW_PMR(x...) do { } while (0)
- #define RAW_PMR_NO_MASK(x...) do { } while (0)
- #define RAW_PMW(x...) do { } while (0)
- #define RAW_PMW_NO_MASK(x...) do { } while (0)
- #define IO(x...) do { } while (0)
- #define NTFY(x...) do { } while (0)
- #endif
- static LIST_HEAD(local_endpoints);
- static LIST_HEAD(remote_endpoints);
- static LIST_HEAD(server_list);
- static wait_queue_head_t newserver_wait;
- static wait_queue_head_t subsystem_restart_wait;
- static DEFINE_SPINLOCK(local_endpoints_lock);
- static DEFINE_SPINLOCK(remote_endpoints_lock);
- static DEFINE_SPINLOCK(server_list_lock);
- static LIST_HEAD(rpc_board_dev_list);
- static DEFINE_SPINLOCK(rpc_board_dev_list_lock);
- static struct workqueue_struct *rpcrouter_workqueue;
- static atomic_t next_xid = ATOMIC_INIT(1);
- static atomic_t pm_mid = ATOMIC_INIT(1);
- static void do_read_data(struct work_struct *work);
- static void do_create_pdevs(struct work_struct *work);
- static void do_create_rpcrouter_pdev(struct work_struct *work);
- static int msm_rpcrouter_close(void);
- static DECLARE_WORK(work_create_pdevs, do_create_pdevs);
- static DECLARE_WORK(work_create_rpcrouter_pdev, do_create_rpcrouter_pdev);
- #define RR_STATE_IDLE 0
- #define RR_STATE_HEADER 1
- #define RR_STATE_BODY 2
- #define RR_STATE_ERROR 3
- /* State for remote ep following restart */
- #define RESTART_QUOTA_ABORT 1
- struct rr_context {
- struct rr_packet *pkt;
- uint8_t *ptr;
- uint32_t state; /* current assembly state */
- uint32_t count; /* bytes needed in this state */
- };
- struct rr_context the_rr_context;
- struct rpc_board_dev_info {
- struct list_head list;
- struct rpc_board_dev *dev;
- };
- static struct platform_device rpcrouter_pdev = {
- .name = "oncrpc_router",
- .id = -1,
- };
- struct rpcrouter_xprt_info {
- struct list_head list;
- struct rpcrouter_xprt *xprt;
- int remote_pid;
- uint32_t initialized;
- wait_queue_head_t read_wait;
- struct wake_lock wakelock;
- spinlock_t lock;
- uint32_t need_len;
- struct work_struct read_data;
- struct workqueue_struct *workqueue;
- int abort_data_read;
- unsigned char r2r_buf[RPCROUTER_MSGSIZE_MAX];
- };
- static LIST_HEAD(xprt_info_list);
- static DEFINE_MUTEX(xprt_info_list_lock);
- DECLARE_COMPLETION(rpc_remote_router_up);
- static atomic_t pending_close_count = ATOMIC_INIT(0);
- static int msm_rpc_reboot_call(struct notifier_block *this,
- unsigned long code, void *_cmd)
- {
- switch (code) {
- case SYS_RESTART:
- case SYS_HALT:
- case SYS_POWER_OFF:
- msm_rpcrouter_close();
- break;
- }
- return NOTIFY_DONE;
- }
- static struct notifier_block msm_rpc_reboot_notifier = {
- .notifier_call = msm_rpc_reboot_call,
- .priority = 100
- };
- /*
- * Search for transport (xprt) that matches the provided PID.
- *
- * Note: The calling function must ensure that the mutex
- * xprt_info_list_lock is locked when this function
- * is called.
- *
- * @remote_pid Remote PID for the transport
- *
- * @returns Pointer to transport or NULL if not found
- */
- static struct rpcrouter_xprt_info *rpcrouter_get_xprt_info(uint32_t remote_pid)
- {
- struct rpcrouter_xprt_info *xprt_info;
- list_for_each_entry(xprt_info, &xprt_info_list, list) {
- if (xprt_info->remote_pid == remote_pid)
- return xprt_info;
- }
- return NULL;
- }
- static int rpcrouter_send_control_msg(struct rpcrouter_xprt_info *xprt_info,
- union rr_control_msg *msg)
- {
- struct rr_header hdr;
- unsigned long flags = 0;
- int need;
- if (xprt_info->remote_pid == RPCROUTER_PID_LOCAL)
- return 0;
- if (!(msg->cmd == RPCROUTER_CTRL_CMD_HELLO) &&
- !xprt_info->initialized) {
- printk(KERN_ERR "rpcrouter_send_control_msg(): Warning, "
- "router not initialized\n");
- return -EINVAL;
- }
- hdr.version = RPCROUTER_VERSION;
- hdr.type = msg->cmd;
- hdr.src_pid = RPCROUTER_PID_LOCAL;
- hdr.src_cid = RPCROUTER_ROUTER_ADDRESS;
- hdr.confirm_rx = 0;
- hdr.size = sizeof(*msg);
- hdr.dst_pid = xprt_info->remote_pid;
- hdr.dst_cid = RPCROUTER_ROUTER_ADDRESS;
- /* TODO: what if channel is full? */
- need = sizeof(hdr) + hdr.size;
- spin_lock_irqsave(&xprt_info->lock, flags);
- while (xprt_info->xprt->write_avail() < need) {
- spin_unlock_irqrestore(&xprt_info->lock, flags);
- msleep(250);
- spin_lock_irqsave(&xprt_info->lock, flags);
- }
- xprt_info->xprt->write(&hdr, sizeof(hdr), HEADER);
- xprt_info->xprt->write(msg, hdr.size, PAYLOAD);
- spin_unlock_irqrestore(&xprt_info->lock, flags);
- return 0;
- }
- static void modem_reset_cleanup(struct rpcrouter_xprt_info *xprt_info)
- {
- struct msm_rpc_endpoint *ept;
- struct rr_remote_endpoint *r_ept;
- struct rr_packet *pkt, *tmp_pkt;
- struct rr_fragment *frag, *next;
- struct msm_rpc_reply *reply, *reply_tmp;
- unsigned long flags;
- if (!xprt_info) {
- pr_err("%s: Invalid xprt_info\n", __func__);
- return;
- }
- spin_lock_irqsave(&local_endpoints_lock, flags);
- /* remove all partial packets received */
- list_for_each_entry(ept, &local_endpoints, list) {
- RR("%s EPT DST PID %x, remote_pid:%d\n", __func__,
- ept->dst_pid, xprt_info->remote_pid);
- if (xprt_info->remote_pid != ept->dst_pid)
- continue;
- D("calling teardown cb %p\n", ept->cb_restart_teardown);
- if (ept->cb_restart_teardown)
- ept->cb_restart_teardown(ept->client_data);
- ept->do_setup_notif = 1;
- /* remove replies */
- spin_lock(&ept->reply_q_lock);
- list_for_each_entry_safe(reply, reply_tmp,
- &ept->reply_pend_q, list) {
- list_del(&reply->list);
- kfree(reply);
- }
- list_for_each_entry_safe(reply, reply_tmp,
- &ept->reply_avail_q, list) {
- list_del(&reply->list);
- kfree(reply);
- }
- ept->reply_cnt = 0;
- spin_unlock(&ept->reply_q_lock);
- /* Set restart state for local ep */
- RR("EPT:0x%p, State %d RESTART_PEND_NTFY_SVR "
- "PROG:0x%08x VERS:0x%08x\n",
- ept, ept->restart_state,
- be32_to_cpu(ept->dst_prog),
- be32_to_cpu(ept->dst_vers));
- spin_lock(&ept->restart_lock);
- ept->restart_state = RESTART_PEND_NTFY_SVR;
- /* remove incomplete packets */
- spin_lock(&ept->incomplete_lock);
- list_for_each_entry_safe(pkt, tmp_pkt,
- &ept->incomplete, list) {
- list_del(&pkt->list);
- frag = pkt->first;
- while (frag != NULL) {
- next = frag->next;
- kfree(frag);
- frag = next;
- }
- kfree(pkt);
- }
- spin_unlock(&ept->incomplete_lock);
- /* remove all completed packets waiting to be read */
- spin_lock(&ept->read_q_lock);
- list_for_each_entry_safe(pkt, tmp_pkt, &ept->read_q,
- list) {
- list_del(&pkt->list);
- frag = pkt->first;
- while (frag != NULL) {
- next = frag->next;
- kfree(frag);
- frag = next;
- }
- kfree(pkt);
- }
- spin_unlock(&ept->read_q_lock);
- spin_unlock(&ept->restart_lock);
- wake_up(&ept->wait_q);
- }
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
- /* Unblock endpoints waiting for quota ack*/
- spin_lock_irqsave(&remote_endpoints_lock, flags);
- list_for_each_entry(r_ept, &remote_endpoints, list) {
- spin_lock(&r_ept->quota_lock);
- r_ept->quota_restart_state = RESTART_QUOTA_ABORT;
- RR("Set STATE_PENDING PID:0x%08x CID:0x%08x \n", r_ept->pid,
- r_ept->cid);
- spin_unlock(&r_ept->quota_lock);
- wake_up(&r_ept->quota_wait);
- }
- spin_unlock_irqrestore(&remote_endpoints_lock, flags);
- }
- static void modem_reset_startup(struct rpcrouter_xprt_info *xprt_info)
- {
- struct msm_rpc_endpoint *ept;
- unsigned long flags;
- spin_lock_irqsave(&local_endpoints_lock, flags);
- /* notify all endpoints that we are coming back up */
- list_for_each_entry(ept, &local_endpoints, list) {
- RR("%s EPT DST PID %x, remote_pid:%d\n", __func__,
- ept->dst_pid, xprt_info->remote_pid);
- if (xprt_info->remote_pid != ept->dst_pid)
- continue;
- D("calling setup cb %d:%p\n", ept->do_setup_notif,
- ept->cb_restart_setup);
- if (ept->do_setup_notif && ept->cb_restart_setup)
- ept->cb_restart_setup(ept->client_data);
- ept->do_setup_notif = 0;
- }
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
- }
- /*
- * Blocks and waits for endpoint if a reset is in progress.
- *
- * @returns
- * ENETRESET Reset is in progress and a notification needed
- * ERESTARTSYS Signal occurred
- * 0 Reset is not in progress
- */
- static int wait_for_restart_and_notify(struct msm_rpc_endpoint *ept)
- {
- unsigned long flags;
- int ret = 0;
- DEFINE_WAIT(__wait);
- for (;;) {
- prepare_to_wait(&ept->restart_wait, &__wait,
- TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&ept->restart_lock, flags);
- if (ept->restart_state == RESTART_NORMAL) {
- spin_unlock_irqrestore(&ept->restart_lock, flags);
- break;
- } else if (ept->restart_state & RESTART_PEND_NTFY) {
- ept->restart_state &= ~RESTART_PEND_NTFY;
- spin_unlock_irqrestore(&ept->restart_lock, flags);
- ret = -ENETRESET;
- break;
- }
- if (signal_pending(current) &&
- ((!(ept->flags & MSM_RPC_UNINTERRUPTIBLE)))) {
- spin_unlock_irqrestore(&ept->restart_lock, flags);
- ret = -ERESTARTSYS;
- break;
- }
- spin_unlock_irqrestore(&ept->restart_lock, flags);
- schedule();
- }
- finish_wait(&ept->restart_wait, &__wait);
- return ret;
- }
- static struct rr_server *rpcrouter_create_server(uint32_t pid,
- uint32_t cid,
- uint32_t prog,
- uint32_t ver)
- {
- struct rr_server *server;
- unsigned long flags;
- int rc;
- server = kmalloc(sizeof(struct rr_server), GFP_KERNEL);
- if (!server)
- return ERR_PTR(-ENOMEM);
- memset(server, 0, sizeof(struct rr_server));
- server->pid = pid;
- server->cid = cid;
- server->prog = prog;
- server->vers = ver;
- spin_lock_irqsave(&server_list_lock, flags);
- list_add_tail(&server->list, &server_list);
- spin_unlock_irqrestore(&server_list_lock, flags);
- rc = msm_rpcrouter_create_server_cdev(server);
- if (rc < 0)
- goto out_fail;
- return server;
- out_fail:
- spin_lock_irqsave(&server_list_lock, flags);
- list_del(&server->list);
- spin_unlock_irqrestore(&server_list_lock, flags);
- kfree(server);
- return ERR_PTR(rc);
- }
- static void rpcrouter_destroy_server(struct rr_server *server)
- {
- unsigned long flags;
- spin_lock_irqsave(&server_list_lock, flags);
- list_del(&server->list);
- spin_unlock_irqrestore(&server_list_lock, flags);
- device_destroy(msm_rpcrouter_class, server->device_number);
- kfree(server);
- }
- int msm_rpc_add_board_dev(struct rpc_board_dev *devices, int num)
- {
- unsigned long flags;
- struct rpc_board_dev_info *board_info;
- int i;
- for (i = 0; i < num; i++) {
- board_info = kzalloc(sizeof(struct rpc_board_dev_info),
- GFP_KERNEL);
- if (!board_info)
- return -ENOMEM;
- board_info->dev = &devices[i];
- D("%s: adding program %x\n", __func__, board_info->dev->prog);
- spin_lock_irqsave(&rpc_board_dev_list_lock, flags);
- list_add_tail(&board_info->list, &rpc_board_dev_list);
- spin_unlock_irqrestore(&rpc_board_dev_list_lock, flags);
- }
- return 0;
- }
- EXPORT_SYMBOL(msm_rpc_add_board_dev);
- static void rpcrouter_register_board_dev(struct rr_server *server)
- {
- struct rpc_board_dev_info *board_info;
- unsigned long flags;
- int rc;
- spin_lock_irqsave(&rpc_board_dev_list_lock, flags);
- list_for_each_entry(board_info, &rpc_board_dev_list, list) {
- if (server->prog == board_info->dev->prog) {
- D("%s: registering device %x\n",
- __func__, board_info->dev->prog);
- list_del(&board_info->list);
- spin_unlock_irqrestore(&rpc_board_dev_list_lock, flags);
- rc = platform_device_register(&board_info->dev->pdev);
- if (rc)
- pr_err("%s: board dev register failed %d\n",
- __func__, rc);
- kfree(board_info);
- return;
- }
- }
- spin_unlock_irqrestore(&rpc_board_dev_list_lock, flags);
- }
- static struct rr_server *rpcrouter_lookup_server(uint32_t prog, uint32_t ver)
- {
- struct rr_server *server;
- unsigned long flags;
- spin_lock_irqsave(&server_list_lock, flags);
- list_for_each_entry(server, &server_list, list) {
- if (server->prog == prog
- && server->vers == ver) {
- spin_unlock_irqrestore(&server_list_lock, flags);
- return server;
- }
- }
- spin_unlock_irqrestore(&server_list_lock, flags);
- return NULL;
- }
- static struct rr_server *rpcrouter_lookup_server_by_dev(dev_t dev)
- {
- struct rr_server *server;
- unsigned long flags;
- spin_lock_irqsave(&server_list_lock, flags);
- list_for_each_entry(server, &server_list, list) {
- if (server->device_number == dev) {
- spin_unlock_irqrestore(&server_list_lock, flags);
- return server;
- }
- }
- spin_unlock_irqrestore(&server_list_lock, flags);
- return NULL;
- }
- struct msm_rpc_endpoint *msm_rpcrouter_create_local_endpoint(dev_t dev)
- {
- struct msm_rpc_endpoint *ept;
- unsigned long flags;
- ept = kmalloc(sizeof(struct msm_rpc_endpoint), GFP_KERNEL);
- if (!ept)
- return NULL;
- memset(ept, 0, sizeof(struct msm_rpc_endpoint));
- ept->cid = (uint32_t) ept;
- ept->pid = RPCROUTER_PID_LOCAL;
- ept->dev = dev;
- if ((dev != msm_rpcrouter_devno) && (dev != MKDEV(0, 0))) {
- struct rr_server *srv;
- /*
- * This is a userspace client which opened
- * a program/ver devicenode. Bind the client
- * to that destination
- */
- srv = rpcrouter_lookup_server_by_dev(dev);
- /* TODO: bug? really? */
- BUG_ON(!srv);
- ept->dst_pid = srv->pid;
- ept->dst_cid = srv->cid;
- ept->dst_prog = cpu_to_be32(srv->prog);
- ept->dst_vers = cpu_to_be32(srv->vers);
- } else {
- /* mark not connected */
- ept->dst_pid = 0xffffffff;
- }
- init_waitqueue_head(&ept->wait_q);
- INIT_LIST_HEAD(&ept->read_q);
- spin_lock_init(&ept->read_q_lock);
- INIT_LIST_HEAD(&ept->reply_avail_q);
- INIT_LIST_HEAD(&ept->reply_pend_q);
- spin_lock_init(&ept->reply_q_lock);
- spin_lock_init(&ept->restart_lock);
- init_waitqueue_head(&ept->restart_wait);
- ept->restart_state = RESTART_NORMAL;
- wake_lock_init(&ept->read_q_wake_lock, WAKE_LOCK_SUSPEND, "rpc_read");
- wake_lock_init(&ept->reply_q_wake_lock, WAKE_LOCK_SUSPEND, "rpc_reply");
- INIT_LIST_HEAD(&ept->incomplete);
- spin_lock_init(&ept->incomplete_lock);
- spin_lock_irqsave(&local_endpoints_lock, flags);
- list_add_tail(&ept->list, &local_endpoints);
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
- return ept;
- }
- int msm_rpcrouter_destroy_local_endpoint(struct msm_rpc_endpoint *ept)
- {
- int rc;
- union rr_control_msg msg = { 0 };
- struct msm_rpc_reply *reply, *reply_tmp;
- unsigned long flags;
- struct rpcrouter_xprt_info *xprt_info;
- /* Endpoint with dst_pid = 0xffffffff corresponds to that of
- ** router port. So don't send a REMOVE CLIENT message while
- ** destroying it.*/
- spin_lock_irqsave(&local_endpoints_lock, flags);
- list_del(&ept->list);
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
- if (ept->dst_pid != 0xffffffff) {
- msg.cmd = RPCROUTER_CTRL_CMD_REMOVE_CLIENT;
- msg.cli.pid = ept->pid;
- msg.cli.cid = ept->cid;
- RR("x REMOVE_CLIENT id=%d:%08x\n", ept->pid, ept->cid);
- mutex_lock(&xprt_info_list_lock);
- list_for_each_entry(xprt_info, &xprt_info_list, list) {
- rc = rpcrouter_send_control_msg(xprt_info, &msg);
- if (rc < 0) {
- mutex_unlock(&xprt_info_list_lock);
- return rc;
- }
- }
- mutex_unlock(&xprt_info_list_lock);
- }
- /* Free replies */
- spin_lock_irqsave(&ept->reply_q_lock, flags);
- list_for_each_entry_safe(reply, reply_tmp, &ept->reply_pend_q, list) {
- list_del(&reply->list);
- kfree(reply);
- }
- list_for_each_entry_safe(reply, reply_tmp, &ept->reply_avail_q, list) {
- list_del(&reply->list);
- kfree(reply);
- }
- spin_unlock_irqrestore(&ept->reply_q_lock, flags);
- wake_lock_destroy(&ept->read_q_wake_lock);
- wake_lock_destroy(&ept->reply_q_wake_lock);
- kfree(ept);
- return 0;
- }
- static int rpcrouter_create_remote_endpoint(uint32_t pid, uint32_t cid)
- {
- struct rr_remote_endpoint *new_c;
- unsigned long flags;
- new_c = kmalloc(sizeof(struct rr_remote_endpoint), GFP_KERNEL);
- if (!new_c)
- return -ENOMEM;
- memset(new_c, 0, sizeof(struct rr_remote_endpoint));
- new_c->cid = cid;
- new_c->pid = pid;
- init_waitqueue_head(&new_c->quota_wait);
- spin_lock_init(&new_c->quota_lock);
- spin_lock_irqsave(&remote_endpoints_lock, flags);
- list_add_tail(&new_c->list, &remote_endpoints);
- new_c->quota_restart_state = RESTART_NORMAL;
- spin_unlock_irqrestore(&remote_endpoints_lock, flags);
- return 0;
- }
- static struct msm_rpc_endpoint *rpcrouter_lookup_local_endpoint(uint32_t cid)
- {
- struct msm_rpc_endpoint *ept;
- list_for_each_entry(ept, &local_endpoints, list) {
- if (ept->cid == cid)
- return ept;
- }
- return NULL;
- }
- static struct rr_remote_endpoint *rpcrouter_lookup_remote_endpoint(uint32_t pid,
- uint32_t cid)
- {
- struct rr_remote_endpoint *ept;
- unsigned long flags;
- spin_lock_irqsave(&remote_endpoints_lock, flags);
- list_for_each_entry(ept, &remote_endpoints, list) {
- if ((ept->pid == pid) && (ept->cid == cid)) {
- spin_unlock_irqrestore(&remote_endpoints_lock, flags);
- return ept;
- }
- }
- spin_unlock_irqrestore(&remote_endpoints_lock, flags);
- return NULL;
- }
- static void handle_server_restart(struct rr_server *server,
- uint32_t pid, uint32_t cid,
- uint32_t prog, uint32_t vers)
- {
- struct rr_remote_endpoint *r_ept;
- struct msm_rpc_endpoint *ept;
- unsigned long flags;
- r_ept = rpcrouter_lookup_remote_endpoint(pid, cid);
- if (r_ept && (r_ept->quota_restart_state !=
- RESTART_NORMAL)) {
- spin_lock_irqsave(&r_ept->quota_lock, flags);
- r_ept->tx_quota_cntr = 0;
- r_ept->quota_restart_state =
- RESTART_NORMAL;
- spin_unlock_irqrestore(&r_ept->quota_lock, flags);
- D(KERN_INFO "rpcrouter: Remote EPT Reset %0x\n",
- (unsigned int)r_ept);
- wake_up(&r_ept->quota_wait);
- }
- spin_lock_irqsave(&local_endpoints_lock, flags);
- list_for_each_entry(ept, &local_endpoints, list) {
- if ((be32_to_cpu(ept->dst_prog) == prog) &&
- (be32_to_cpu(ept->dst_vers) == vers) &&
- (ept->restart_state & RESTART_PEND_SVR)) {
- spin_lock(&ept->restart_lock);
- ept->restart_state &= ~RESTART_PEND_SVR;
- spin_unlock(&ept->restart_lock);
- D("rpcrouter: Local EPT Reset %08x:%08x \n",
- prog, vers);
- wake_up(&ept->restart_wait);
- wake_up(&ept->wait_q);
- }
- }
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
- }
- static int process_control_msg(struct rpcrouter_xprt_info *xprt_info,
- union rr_control_msg *msg, int len)
- {
- union rr_control_msg ctl = { 0 };
- struct rr_server *server;
- struct rr_remote_endpoint *r_ept;
- int rc = 0;
- unsigned long flags;
- static int first = 1;
- if (len != sizeof(*msg)) {
- RR(KERN_ERR "rpcrouter: r2r msg size %d != %d\n",
- len, sizeof(*msg));
- return -EINVAL;
- }
- switch (msg->cmd) {
- case RPCROUTER_CTRL_CMD_HELLO:
- RR("o HELLO PID %d\n", xprt_info->remote_pid);
- memset(&ctl, 0, sizeof(ctl));
- ctl.cmd = RPCROUTER_CTRL_CMD_HELLO;
- rpcrouter_send_control_msg(xprt_info, &ctl);
- xprt_info->initialized = 1;
- /* Send list of servers one at a time */
- ctl.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER;
- /* TODO: long time to hold a spinlock... */
- spin_lock_irqsave(&server_list_lock, flags);
- list_for_each_entry(server, &server_list, list) {
- if (server->pid != RPCROUTER_PID_LOCAL)
- continue;
- ctl.srv.pid = server->pid;
- ctl.srv.cid = server->cid;
- ctl.srv.prog = server->prog;
- ctl.srv.vers = server->vers;
- RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
- server->pid, server->cid,
- server->prog, server->vers);
- rpcrouter_send_control_msg(xprt_info, &ctl);
- }
- spin_unlock_irqrestore(&server_list_lock, flags);
- if (first) {
- first = 0;
- queue_work(rpcrouter_workqueue,
- &work_create_rpcrouter_pdev);
- }
- break;
- case RPCROUTER_CTRL_CMD_RESUME_TX:
- RR("o RESUME_TX id=%d:%08x\n", msg->cli.pid, msg->cli.cid);
- r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.pid,
- msg->cli.cid);
- if (!r_ept) {
- printk(KERN_ERR
- "rpcrouter: Unable to resume client\n");
- break;
- }
- spin_lock_irqsave(&r_ept->quota_lock, flags);
- r_ept->tx_quota_cntr = 0;
- spin_unlock_irqrestore(&r_ept->quota_lock, flags);
- wake_up(&r_ept->quota_wait);
- break;
- case RPCROUTER_CTRL_CMD_NEW_SERVER:
- if (msg->srv.vers == 0) {
- pr_err(
- "rpcrouter: Server create rejected, version = 0, "
- "program = %08x\n", msg->srv.prog);
- break;
- }
- RR("o NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
- msg->srv.pid, msg->srv.cid, msg->srv.prog, msg->srv.vers);
- server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers);
- if (!server) {
- server = rpcrouter_create_server(
- msg->srv.pid, msg->srv.cid,
- msg->srv.prog, msg->srv.vers);
- if (!server)
- return -ENOMEM;
- /*
- * XXX: Verify that its okay to add the
- * client to our remote client list
- * if we get a NEW_SERVER notification
- */
- if (!rpcrouter_lookup_remote_endpoint(msg->srv.pid,
- msg->srv.cid)) {
- rc = rpcrouter_create_remote_endpoint(
- msg->srv.pid, msg->srv.cid);
- if (rc < 0)
- printk(KERN_ERR
- "rpcrouter:Client create"
- "error (%d)\n", rc);
- }
- rpcrouter_register_board_dev(server);
- schedule_work(&work_create_pdevs);
- wake_up(&newserver_wait);
- } else {
- if ((server->pid == msg->srv.pid) &&
- (server->cid == msg->srv.cid)) {
- handle_server_restart(server,
- msg->srv.pid,
- msg->srv.cid,
- msg->srv.prog,
- msg->srv.vers);
- } else {
- server->pid = msg->srv.pid;
- server->cid = msg->srv.cid;
- }
- }
- break;
- case RPCROUTER_CTRL_CMD_REMOVE_SERVER:
- RR("o REMOVE_SERVER prog=%08x:%d\n",
- msg->srv.prog, msg->srv.vers);
- server = rpcrouter_lookup_server(msg->srv.prog, msg->srv.vers);
- if (server)
- rpcrouter_destroy_server(server);
- break;
- case RPCROUTER_CTRL_CMD_REMOVE_CLIENT:
- RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.pid, msg->cli.cid);
- if (msg->cli.pid == RPCROUTER_PID_LOCAL) {
- printk(KERN_ERR
- "rpcrouter: Denying remote removal of "
- "local client\n");
- break;
- }
- r_ept = rpcrouter_lookup_remote_endpoint(msg->cli.pid,
- msg->cli.cid);
- if (r_ept) {
- spin_lock_irqsave(&remote_endpoints_lock, flags);
- list_del(&r_ept->list);
- spin_unlock_irqrestore(&remote_endpoints_lock, flags);
- kfree(r_ept);
- }
- /* Notify local clients of this event */
- printk(KERN_ERR "rpcrouter: LOCAL NOTIFICATION NOT IMP\n");
- rc = -ENOSYS;
- break;
- case RPCROUTER_CTRL_CMD_PING:
- /* No action needed for ping messages received */
- RR("o PING\n");
- break;
- default:
- RR("o UNKNOWN(%08x)\n", msg->cmd);
- rc = -ENOSYS;
- }
- return rc;
- }
- static void do_create_rpcrouter_pdev(struct work_struct *work)
- {
- D("%s: modem rpc router up\n", __func__);
- platform_device_register(&rpcrouter_pdev);
- complete_all(&rpc_remote_router_up);
- }
- static void do_create_pdevs(struct work_struct *work)
- {
- unsigned long flags;
- struct rr_server *server;
- /* TODO: race if destroyed while being registered */
- spin_lock_irqsave(&server_list_lock, flags);
- list_for_each_entry(server, &server_list, list) {
- if (server->pid != RPCROUTER_PID_LOCAL) {
- if (server->pdev_name[0] == 0) {
- sprintf(server->pdev_name, "rs%.8x",
- server->prog);
- spin_unlock_irqrestore(&server_list_lock,
- flags);
- msm_rpcrouter_create_server_pdev(server);
- schedule_work(&work_create_pdevs);
- return;
- }
- }
- }
- spin_unlock_irqrestore(&server_list_lock, flags);
- }
- static void *rr_malloc(unsigned sz)
- {
- void *ptr = kmalloc(sz, GFP_KERNEL);
- if (ptr)
- return ptr;
- printk(KERN_ERR "rpcrouter: kmalloc of %d failed, retrying...\n", sz);
- do {
- ptr = kmalloc(sz, GFP_KERNEL);
- } while (!ptr);
- return ptr;
- }
- static int rr_read(struct rpcrouter_xprt_info *xprt_info,
- void *data, uint32_t len)
- {
- int rc;
- unsigned long flags;
- while (!xprt_info->abort_data_read) {
- spin_lock_irqsave(&xprt_info->lock, flags);
- if (xprt_info->xprt->read_avail() >= len) {
- rc = xprt_info->xprt->read(data, len);
- spin_unlock_irqrestore(&xprt_info->lock, flags);
- if (rc == len && !xprt_info->abort_data_read)
- return 0;
- else
- return -EIO;
- }
- xprt_info->need_len = len;
- wake_unlock(&xprt_info->wakelock);
- spin_unlock_irqrestore(&xprt_info->lock, flags);
- wait_event(xprt_info->read_wait,
- xprt_info->xprt->read_avail() >= len
- || xprt_info->abort_data_read);
- }
- return -EIO;
- }
- #if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
- static char *type_to_str(int i)
- {
- switch (i) {
- case RPCROUTER_CTRL_CMD_DATA:
- return "data ";
- case RPCROUTER_CTRL_CMD_HELLO:
- return "hello ";
- case RPCROUTER_CTRL_CMD_BYE:
- return "bye ";
- case RPCROUTER_CTRL_CMD_NEW_SERVER:
- return "new_srvr";
- case RPCROUTER_CTRL_CMD_REMOVE_SERVER:
- return "rmv_srvr";
- case RPCROUTER_CTRL_CMD_REMOVE_CLIENT:
- return "rmv_clnt";
- case RPCROUTER_CTRL_CMD_RESUME_TX:
- return "resum_tx";
- case RPCROUTER_CTRL_CMD_EXIT:
- return "cmd_exit";
- default:
- return "invalid";
- }
- }
- #endif
- static void do_read_data(struct work_struct *work)
- {
- struct rr_header hdr;
- struct rr_packet *pkt;
- struct rr_fragment *frag;
- struct msm_rpc_endpoint *ept;
- #if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
- struct rpc_request_hdr *rq;
- #endif
- uint32_t pm, mid;
- unsigned long flags;
- struct rpcrouter_xprt_info *xprt_info =
- container_of(work,
- struct rpcrouter_xprt_info,
- read_data);
- if (rr_read(xprt_info, &hdr, sizeof(hdr)))
- goto fail_io;
- RR("- ver=%d type=%d src=%d:%08x crx=%d siz=%d dst=%d:%08x\n",
- hdr.version, hdr.type, hdr.src_pid, hdr.src_cid,
- hdr.confirm_rx, hdr.size, hdr.dst_pid, hdr.dst_cid);
- RAW_HDR("[r rr_h] "
- "ver=%i,type=%s,src_pid=%08x,src_cid=%08x,"
- "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
- hdr.version, type_to_str(hdr.type), hdr.src_pid, hdr.src_cid,
- hdr.confirm_rx, hdr.size, hdr.dst_pid, hdr.dst_cid);
- if (hdr.version != RPCROUTER_VERSION) {
- DIAG("version %d != %d\n", hdr.version, RPCROUTER_VERSION);
- goto fail_data;
- }
- if (hdr.size > RPCROUTER_MSGSIZE_MAX) {
- DIAG("msg size %d > max %d\n", hdr.size, RPCROUTER_MSGSIZE_MAX);
- goto fail_data;
- }
- if (hdr.dst_cid == RPCROUTER_ROUTER_ADDRESS) {
- if (xprt_info->remote_pid == -1) {
- xprt_info->remote_pid = hdr.src_pid;
- /* do restart notification */
- modem_reset_startup(xprt_info);
- }
- if (rr_read(xprt_info, xprt_info->r2r_buf, hdr.size))
- goto fail_io;
- process_control_msg(xprt_info,
- (void *) xprt_info->r2r_buf, hdr.size);
- goto done;
- }
- if (hdr.size < sizeof(pm)) {
- DIAG("runt packet (no pacmark)\n");
- goto fail_data;
- }
- if (rr_read(xprt_info, &pm, sizeof(pm)))
- goto fail_io;
- hdr.size -= sizeof(pm);
- frag = rr_malloc(sizeof(*frag));
- frag->next = NULL;
- frag->length = hdr.size;
- if (rr_read(xprt_info, frag->data, hdr.size)) {
- kfree(frag);
- goto fail_io;
- }
- #if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
- if ((smd_rpcrouter_debug_mask & RAW_PMR) &&
- ((pm >> 30 & 0x1) || (pm >> 31 & 0x1))) {
- uint32_t xid = 0;
- if (pm >> 30 & 0x1) {
- rq = (struct rpc_request_hdr *) frag->data;
- xid = ntohl(rq->xid);
- }
- if ((pm >> 31 & 0x1) || (pm >> 30 & 0x1))
- RAW_PMR_NOMASK("xid:0x%03x first=%i,last=%i,mid=%3i,"
- "len=%3i,dst_cid=%08x\n",
- xid,
- pm >> 30 & 0x1,
- pm >> 31 & 0x1,
- pm >> 16 & 0xFF,
- pm & 0xFFFF, hdr.dst_cid);
- }
- if (smd_rpcrouter_debug_mask & SMEM_LOG) {
- rq = (struct rpc_request_hdr *) frag->data;
- if (rq->xid == 0)
- smem_log_event(SMEM_LOG_PROC_ID_APPS |
- RPC_ROUTER_LOG_EVENT_MID_READ,
- PACMARK_MID(pm),
- hdr.dst_cid,
- hdr.src_cid);
- else
- smem_log_event(SMEM_LOG_PROC_ID_APPS |
- RPC_ROUTER_LOG_EVENT_MSG_READ,
- ntohl(rq->xid),
- hdr.dst_cid,
- hdr.src_cid);
- }
- #endif
- spin_lock_irqsave(&local_endpoints_lock, flags);
- ept = rpcrouter_lookup_local_endpoint(hdr.dst_cid);
- if (!ept) {
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
- DIAG("no local ept for cid %08x\n", hdr.dst_cid);
- kfree(frag);
- goto done;
- }
- /* See if there is already a partial packet that matches our mid
- * and if so, append this fragment to that packet.
- */
- mid = PACMARK_MID(pm);
- spin_lock(&ept->incomplete_lock);
- list_for_each_entry(pkt, &ept->incomplete, list) {
- if (pkt->mid == mid) {
- pkt->last->next = frag;
- pkt->last = frag;
- pkt->length += frag->length;
- if (PACMARK_LAST(pm)) {
- list_del(&pkt->list);
- spin_unlock(&ept->incomplete_lock);
- goto packet_complete;
- }
- spin_unlock(&ept->incomplete_lock);
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
- goto done;
- }
- }
- spin_unlock(&ept->incomplete_lock);
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
- /* This mid is new -- create a packet for it, and put it on
- * the incomplete list if this fragment is not a last fragment,
- * otherwise put it on the read queue.
- */
- pkt = rr_malloc(sizeof(struct rr_packet));
- pkt->first = frag;
- pkt->last = frag;
- memcpy(&pkt->hdr, &hdr, sizeof(hdr));
- pkt->mid = mid;
- pkt->length = frag->length;
- spin_lock_irqsave(&local_endpoints_lock, flags);
- ept = rpcrouter_lookup_local_endpoint(hdr.dst_cid);
- if (!ept) {
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
- DIAG("no local ept for cid %08x\n", hdr.dst_cid);
- kfree(frag);
- kfree(pkt);
- goto done;
- }
- if (!PACMARK_LAST(pm)) {
- spin_lock(&ept->incomplete_lock);
- list_add_tail(&pkt->list, &ept->incomplete);
- spin_unlock(&ept->incomplete_lock);
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
- goto done;
- }
- packet_complete:
- spin_lock(&ept->read_q_lock);
- D("%s: take read lock on ept %p\n", __func__, ept);
- wake_lock(&ept->read_q_wake_lock);
- list_add_tail(&pkt->list, &ept->read_q);
- wake_up(&ept->wait_q);
- spin_unlock(&ept->read_q_lock);
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
- done:
- if (hdr.confirm_rx) {
- union rr_control_msg msg = { 0 };
- msg.cmd = RPCROUTER_CTRL_CMD_RESUME_TX;
- msg.cli.pid = hdr.dst_pid;
- msg.cli.cid = hdr.dst_cid;
- RR("x RESUME_TX id=%d:%08x\n", msg.cli.pid, msg.cli.cid);
- rpcrouter_send_control_msg(xprt_info, &msg);
- #if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
- if (smd_rpcrouter_debug_mask & SMEM_LOG)
- smem_log_event(SMEM_LOG_PROC_ID_APPS |
- RPC_ROUTER_LOG_EVENT_MSG_CFM_SNT,
- RPCROUTER_PID_LOCAL,
- hdr.dst_cid,
- hdr.src_cid);
- #endif
- }
- /* don't requeue if we should be shutting down */
- if (!xprt_info->abort_data_read) {
- queue_work(xprt_info->workqueue, &xprt_info->read_data);
- return;
- }
- D("rpc_router terminating for '%s'\n",
- xprt_info->xprt->name);
- fail_io:
- fail_data:
- D(KERN_ERR "rpc_router has died for '%s'\n",
- xprt_info->xprt->name);
- }
- void msm_rpc_setup_req(struct rpc_request_hdr *hdr, uint32_t prog,
- uint32_t vers, uint32_t proc)
- {
- memset(hdr, 0, sizeof(struct rpc_request_hdr));
- hdr->xid = cpu_to_be32(atomic_add_return(1, &next_xid));
- hdr->rpc_vers = cpu_to_be32(2);
- hdr->prog = cpu_to_be32(prog);
- hdr->vers = cpu_to_be32(vers);
- hdr->procedure = cpu_to_be32(proc);
- }
- EXPORT_SYMBOL(msm_rpc_setup_req);
- struct msm_rpc_endpoint *msm_rpc_open(void)
- {
- struct msm_rpc_endpoint *ept;
- ept = msm_rpcrouter_create_local_endpoint(MKDEV(0, 0));
- if (ept == NULL)
- return ERR_PTR(-ENOMEM);
- return ept;
- }
- void msm_rpc_read_wakeup(struct msm_rpc_endpoint *ept)
- {
- ept->forced_wakeup = 1;
- wake_up(&ept->wait_q);
- }
- int msm_rpc_close(struct msm_rpc_endpoint *ept)
- {
- if (!ept)
- return -EINVAL;
- return msm_rpcrouter_destroy_local_endpoint(ept);
- }
- EXPORT_SYMBOL(msm_rpc_close);
- static int msm_rpc_write_pkt(
- struct rr_header *hdr,
- struct msm_rpc_endpoint *ept,
- struct rr_remote_endpoint *r_ept,
- void *buffer,
- int count,
- int first,
- int last,
- uint32_t mid
- )
- {
- #if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
- struct rpc_request_hdr *rq = buffer;
- uint32_t event_id;
- #endif
- uint32_t pacmark;
- unsigned long flags = 0;
- int rc;
- struct rpcrouter_xprt_info *xprt_info;
- int needed;
- DEFINE_WAIT(__wait);
- /* Create routing header */
- hdr->type = RPCROUTER_CTRL_CMD_DATA;
- hdr->version = RPCROUTER_VERSION;
- hdr->src_pid = ept->pid;
- hdr->src_cid = ept->cid;
- hdr->confirm_rx = 0;
- hdr->size = count + sizeof(uint32_t);
- rc = wait_for_restart_and_notify(ept);
- if (rc)
- return rc;
- if (r_ept) {
- for (;;) {
- prepare_to_wait(&r_ept->quota_wait, &__wait,
- TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&r_ept->quota_lock, flags);
- if ((r_ept->tx_quota_cntr <
- RPCROUTER_DEFAULT_RX_QUOTA) ||
- (r_ept->quota_restart_state != RESTART_NORMAL))
- break;
- if (signal_pending(current) &&
- (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE)))
- break;
- spin_unlock_irqrestore(&r_ept->quota_lock, flags);
- schedule();
- }
- finish_wait(&r_ept->quota_wait, &__wait);
- if (r_ept->quota_restart_state != RESTART_NORMAL) {
- spin_lock(&ept->restart_lock);
- ept->restart_state &= ~RESTART_PEND_NTFY;
- spin_unlock(&ept->restart_lock);
- spin_unlock_irqrestore(&r_ept->quota_lock, flags);
- return -ENETRESET;
- }
- if (signal_pending(current) &&
- (!(ept->flags & MSM_RPC_UNINTERRUPTIBLE))) {
- spin_unlock_irqrestore(&r_ept->quota_lock, flags);
- return -ERESTARTSYS;
- }
- r_ept->tx_quota_cntr++;
- if (r_ept->tx_quota_cntr == RPCROUTER_DEFAULT_RX_QUOTA) {
- hdr->confirm_rx = 1;
- #if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
- if (smd_rpcrouter_debug_mask & SMEM_LOG) {
- event_id = (rq->xid == 0) ?
- RPC_ROUTER_LOG_EVENT_MID_CFM_REQ :
- RPC_ROUTER_LOG_EVENT_MSG_CFM_REQ;
- smem_log_event(SMEM_LOG_PROC_ID_APPS | event_id,
- hdr->dst_pid,
- hdr->dst_cid,
- hdr->src_cid);
- }
- #endif
- }
- }
- pacmark = PACMARK(count, mid, first, last);
- if (r_ept)
- spin_unlock_irqrestore(&r_ept->quota_lock, flags);
- mutex_lock(&xprt_info_list_lock);
- xprt_info = rpcrouter_get_xprt_info(hdr->dst_pid);
- if (!xprt_info) {
- mutex_unlock(&xprt_info_list_lock);
- return -ENETRESET;
- }
- spin_lock_irqsave(&xprt_info->lock, flags);
- mutex_unlock(&xprt_info_list_lock);
- spin_lock(&ept->restart_lock);
- if (ept->restart_state != RESTART_NORMAL) {
- ept->restart_state &= ~RESTART_PEND_NTFY;
- spin_unlock(&ept->restart_lock);
- spin_unlock_irqrestore(&xprt_info->lock, flags);
- return -ENETRESET;
- }
- needed = sizeof(*hdr) + hdr->size;
- while ((ept->restart_state == RESTART_NORMAL) &&
- (xprt_info->xprt->write_avail() < needed)) {
- spin_unlock(&ept->restart_lock);
- spin_unlock_irqrestore(&xprt_info->lock, flags);
- msleep(250);
- /* refresh xprt pointer to ensure that it hasn't
- * been deleted since our last retrieval */
- mutex_lock(&xprt_info_list_lock);
- xprt_info = rpcrouter_get_xprt_info(hdr->dst_pid);
- if (!xprt_info) {
- mutex_unlock(&xprt_info_list_lock);
- return -ENETRESET;
- }
- spin_lock_irqsave(&xprt_info->lock, flags);
- mutex_unlock(&xprt_info_list_lock);
- spin_lock(&ept->restart_lock);
- }
- if (ept->restart_state != RESTART_NORMAL) {
- ept->restart_state &= ~RESTART_PEND_NTFY;
- spin_unlock(&ept->restart_lock);
- spin_unlock_irqrestore(&xprt_info->lock, flags);
- return -ENETRESET;
- }
- /* TODO: deal with full fifo */
- xprt_info->xprt->write(hdr, sizeof(*hdr), HEADER);
- RAW_HDR("[w rr_h] "
- "ver=%i,type=%s,src_pid=%08x,src_cid=%08x,"
- "confirm_rx=%i,size=%3i,dst_pid=%08x,dst_cid=%08x\n",
- hdr->version, type_to_str(hdr->type),
- hdr->src_pid, hdr->src_cid,
- hdr->confirm_rx, hdr->size, hdr->dst_pid, hdr->dst_cid);
- xprt_info->xprt->write(&pacmark, sizeof(pacmark), PACKMARK);
- #if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
- if ((smd_rpcrouter_debug_mask & RAW_PMW) &&
- ((pacmark >> 30 & 0x1) || (pacmark >> 31 & 0x1))) {
- uint32_t xid = 0;
- if (pacmark >> 30 & 0x1)
- xid = ntohl(rq->xid);
- if ((pacmark >> 31 & 0x1) || (pacmark >> 30 & 0x1))
- RAW_PMW_NOMASK("xid:0x%03x first=%i,last=%i,mid=%3i,"
- "len=%3i,src_cid=%x\n",
- xid,
- pacmark >> 30 & 0x1,
- pacmark >> 31 & 0x1,
- pacmark >> 16 & 0xFF,
- pacmark & 0xFFFF, hdr->src_cid);
- }
- #endif
- xprt_info->xprt->write(buffer, count, PAYLOAD);
- spin_unlock(&ept->restart_lock);
- spin_unlock_irqrestore(&xprt_info->lock, flags);
- #if defined(CONFIG_MSM_ONCRPCROUTER_DEBUG)
- if (smd_rpcrouter_debug_mask & SMEM_LOG) {
- if (rq->xid == 0)
- smem_log_event(SMEM_LOG_PROC_ID_APPS |
- RPC_ROUTER_LOG_EVENT_MID_WRITTEN,
- PACMARK_MID(pacmark),
- hdr->dst_cid,
- hdr->src_cid);
- else
- smem_log_event(SMEM_LOG_PROC_ID_APPS |
- RPC_ROUTER_LOG_EVENT_MSG_WRITTEN,
- ntohl(rq->xid),
- hdr->dst_cid,
- hdr->src_cid);
- }
- #endif
- return needed;
- }
- static struct msm_rpc_reply *get_pend_reply(struct msm_rpc_endpoint *ept,
- uint32_t xid)
- {
- unsigned long flags;
- struct msm_rpc_reply *reply;
- spin_lock_irqsave(&ept->reply_q_lock, flags);
- list_for_each_entry(reply, &ept->reply_pend_q, list) {
- if (reply->xid == xid) {
- list_del(&reply->list);
- spin_unlock_irqrestore(&ept->reply_q_lock, flags);
- return reply;
- }
- }
- spin_unlock_irqrestore(&ept->reply_q_lock, flags);
- return NULL;
- }
- void get_requesting_client(struct msm_rpc_endpoint *ept, uint32_t xid,
- struct msm_rpc_client_info *clnt_info)
- {
- unsigned long flags;
- struct msm_rpc_reply *reply;
- if (!clnt_info)
- return;
- spin_lock_irqsave(&ept->reply_q_lock, flags);
- list_for_each_entry(reply, &ept->reply_pend_q, list) {
- if (reply->xid == xid) {
- clnt_info->pid = reply->pid;
- clnt_info->cid = reply->cid;
- clnt_info->prog = reply->prog;
- clnt_info->vers = reply->vers;
- spin_unlock_irqrestore(&ept->reply_q_lock, flags);
- return;
- }
- }
- spin_unlock_irqrestore(&ept->reply_q_lock, flags);
- return;
- }
- static void set_avail_reply(struct msm_rpc_endpoint *ept,
- struct msm_rpc_reply *reply)
- {
- unsigned long flags;
- spin_lock_irqsave(&ept->reply_q_lock, flags);
- list_add_tail(&reply->list, &ept->reply_avail_q);
- spin_unlock_irqrestore(&ept->reply_q_lock, flags);
- }
- static struct msm_rpc_reply *get_avail_reply(struct msm_rpc_endpoint *ept)
- {
- struct msm_rpc_reply *reply;
- unsigned long flags;
- if (list_empty(&ept->reply_avail_q)) {
- if (ept->reply_cnt >= RPCROUTER_PEND_REPLIES_MAX) {
- printk(KERN_ERR
- "exceeding max replies of %d \n",
- RPCROUTER_PEND_REPLIES_MAX);
- return 0;
- }
- reply = kmalloc(sizeof(struct msm_rpc_reply), GFP_KERNEL);
- if (!reply)
- return 0;
- D("Adding reply 0x%08x \n", (unsigned int)reply);
- memset(reply, 0, sizeof(struct msm_rpc_reply));
- spin_lock_irqsave(&ept->reply_q_lock, flags);
- ept->reply_cnt++;
- spin_unlock_irqrestore(&ept->reply_q_lock, flags);
- } else {
- spin_lock_irqsave(&ept->reply_q_lock, flags);
- reply = list_first_entry(&ept->reply_avail_q,
- struct msm_rpc_reply,
- list);
- list_del(&reply->list);
- spin_unlock_irqrestore(&ept->reply_q_lock, flags);
- }
- return reply;
- }
- static void set_pend_reply(struct msm_rpc_endpoint *ept,
- struct msm_rpc_reply *reply)
- {
- unsigned long flags;
- spin_lock_irqsave(&ept->reply_q_lock, flags);
- D("%s: take reply lock on ept %p\n", __func__, ept);
- wake_lock(&ept->reply_q_wake_lock);
- list_add_tail(&reply->list, &ept->reply_pend_q);
- spin_unlock_irqrestore(&ept->reply_q_lock, flags);
- }
- int msm_rpc_write(struct msm_rpc_endpoint *ept, void *buffer, int count)
- {
- struct rr_header hdr;
- struct rpc_request_hdr *rq = buffer;
- struct rr_remote_endpoint *r_ept;
- struct msm_rpc_reply *reply = NULL;
- int max_tx;
- int tx_cnt;
- char *tx_buf;
- int rc;
- int first_pkt = 1;
- uint32_t mid;
- unsigned long flags;
- /* snoop the RPC packet and enforce permissions */
- /* has to have at least the xid and type fields */
- if (count < (sizeof(uint32_t) * 2)) {
- printk(KERN_ERR "rr_write: rejecting runt packet\n");
- return -EINVAL;
- }
- if (rq->type == 0) {
- /* RPC CALL */
- if (count < (sizeof(uint32_t) * 6)) {
- printk(KERN_ERR
- "rr_write: rejecting runt call packet\n");
- return -EINVAL;
- }
- if (ept->dst_pid == 0xffffffff) {
- printk(KERN_ERR "rr_write: not connected\n");
- return -ENOTCONN;
- }
- if ((ept->dst_prog != rq->prog) ||
- ((be32_to_cpu(ept->dst_vers) & 0x0fff0000) !=
- (be32_to_cpu(rq->vers) & 0x0fff0000))) {
- printk(KERN_ERR
- "rr_write: cannot write to %08x:%08x "
- "(bound to %08x:%08x)\n",
- be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
- be32_to_cpu(ept->dst_prog),
- be32_to_cpu(ept->dst_vers));
- return -EINVAL;
- }
- hdr.dst_pid = ept->dst_pid;
- hdr.dst_cid = ept->dst_cid;
- IO("CALL to %08x:%d @ %d:%08x (%d bytes)\n",
- be32_to_cpu(rq->prog), be32_to_cpu(rq->vers),
- ept->dst_pid, ept->dst_cid, count);
- } else {
- /* RPC REPLY */
- reply = get_pend_reply(ept, rq->xid);
- if (!reply) {
- printk(KERN_ERR
- "rr_write: rejecting, reply not found \n");
- return -EINVAL;
- }
- hdr.dst_pid = reply->pid;
- hdr.dst_cid = reply->cid;
- IO("REPLY to xid=%d @ %d:%08x (%d bytes)\n",
- be32_to_cpu(rq->xid), hdr.dst_pid, hdr.dst_cid, count);
- }
- r_ept = rpcrouter_lookup_remote_endpoint(hdr.dst_pid, hdr.dst_cid);
- if ((!r_ept) && (hdr.dst_pid != RPCROUTER_PID_LOCAL)) {
- printk(KERN_ERR
- "msm_rpc_write(): No route to ept "
- "[PID %x CID %x]\n", hdr.dst_pid, hdr.dst_cid);
- count = -EHOSTUNREACH;
- goto write_release_lock;
- }
- tx_cnt = count;
- tx_buf = buffer;
- mid = atomic_add_return(1, &pm_mid) & 0xFF;
- /* The modem's router can only take 500 bytes of data. The
- first 8 bytes it uses on the modem side for addressing,
- the next 4 bytes are for the pacmark header. */
- max_tx = RPCROUTER_MSGSIZE_MAX - 8 - sizeof(uint32_t);
- IO("Writing %d bytes, max pkt size is %d\n",
- tx_cnt, max_tx);
- while (tx_cnt > 0) {
- if (tx_cnt > max_tx) {
- rc = msm_rpc_write_pkt(&hdr, ept, r_ept,
- tx_buf, max_tx,
- first_pkt, 0, mid);
- if (rc < 0) {
- count = rc;
- goto write_release_lock;
- }
- IO("Wrote %d bytes First %d, Last 0 mid %d\n",
- rc, first_pkt, mid);
- tx_cnt -= max_tx;
- tx_buf += max_tx;
- } else {
- rc = msm_rpc_write_pkt(&hdr, ept, r_ept,
- tx_buf, tx_cnt,
- first_pkt, 1, mid);
- if (rc < 0) {
- count = rc;
- goto write_release_lock;
- }
- IO("Wrote %d bytes First %d Last 1 mid %d\n",
- rc, first_pkt, mid);
- break;
- }
- first_pkt = 0;
- }
- write_release_lock:
- /* if reply, release wakelock after writing to the transport */
- if (rq->type != 0) {
- /* Upon failure, add reply tag to the pending list.
- ** Else add reply tag to the avail/free list. */
- if (count < 0)
- set_pend_reply(ept, reply);
- else
- set_avail_reply(ept, reply);
- spin_lock_irqsave(&ept->reply_q_lock, flags);
- if (list_empty(&ept->reply_pend_q)) {
- D("%s: release reply lock on ept %p\n", __func__, ept);
- wake_unlock(&ept->reply_q_wake_lock);
- }
- spin_unlock_irqrestore(&ept->reply_q_lock, flags);
- }
- return count;
- }
- EXPORT_SYMBOL(msm_rpc_write);
- /*
- * NOTE: It is the responsibility of the caller to kfree buffer
- */
- int msm_rpc_read(struct msm_rpc_endpoint *ept, void **buffer,
- unsigned user_len, long timeout)
- {
- struct rr_fragment *frag, *next;
- char *buf;
- int rc;
- rc = __msm_rpc_read(ept, &frag, user_len, timeout);
- if (rc <= 0)
- return rc;
- /* single-fragment messages conveniently can be
- * returned as-is (the buffer is at the front)
- */
- if (frag->next == 0) {
- *buffer = (void*) frag;
- return rc;
- }
- /* multi-fragment messages, we have to do it the
- * hard way, which is rather disgusting right now
- */
- buf = rr_malloc(rc);
- *buffer = buf;
- while (frag != NULL) {
- memcpy(buf, frag->data, frag->length);
- next = frag->next;
- buf += frag->length;
- kfree(frag);
- frag = next;
- }
- return rc;
- }
- EXPORT_SYMBOL(msm_rpc_read);
- int msm_rpc_call(struct msm_rpc_endpoint *ept, uint32_t proc,
- void *_request, int request_size,
- long timeout)
- {
- return msm_rpc_call_reply(ept, proc,
- _request, request_size,
- NULL, 0, timeout);
- }
- EXPORT_SYMBOL(msm_rpc_call);
- int msm_rpc_call_reply(struct msm_rpc_endpoint *ept, uint32_t proc,
- void *_request, int request_size,
- void *_reply, int reply_size,
- long timeout)
- {
- struct rpc_request_hdr *req = _request;
- struct rpc_reply_hdr *reply;
- int rc;
- if (request_size < sizeof(*req))
- return -ETOOSMALL;
- if (ept->dst_pid == 0xffffffff)
- return -ENOTCONN;
- memset(req, 0, sizeof(*req));
- req->xid = cpu_to_be32(atomic_add_return(1, &next_xid));
- req->rpc_vers = cpu_to_be32(2);
- req->prog = ept->dst_prog;
- req->vers = ept->dst_vers;
- req->procedure = cpu_to_be32(proc);
- rc = msm_rpc_write(ept, req, request_size);
- if (rc < 0)
- return rc;
- for (;;) {
- rc = msm_rpc_read(ept, (void*) &reply, -1, timeout);
- if (rc < 0)
- return rc;
- if (rc < (3 * sizeof(uint32_t))) {
- rc = -EIO;
- break;
- }
- /* we should not get CALL packets -- ignore them */
- if (reply->type == 0) {
- kfree(reply);
- continue;
- }
- /* If an earlier call timed out, we could get the (no
- * longer wanted) reply for it. Ignore replies that
- * we don't expect
- */
- if (reply->xid != req->xid) {
- kfree(reply);
- continue;
- }
- if (reply->reply_stat != 0) {
- rc = -EPERM;
- break;
- }
- if (reply->data.acc_hdr.accept_stat != 0) {
- rc = -EINVAL;
- break;
- }
- if (_reply == NULL) {
- rc = 0;
- break;
- }
- if (rc > reply_size) {
- rc = -ENOMEM;
- } else {
- memcpy(_reply, reply, rc);
- }
- break;
- }
- kfree(reply);
- return rc;
- }
- EXPORT_SYMBOL(msm_rpc_call_reply);
- static inline int ept_packet_available(struct msm_rpc_endpoint *ept)
- {
- unsigned long flags;
- int ret;
- spin_lock_irqsave(&ept->read_q_lock, flags);
- ret = !list_empty(&ept->read_q);
- spin_unlock_irqrestore(&ept->read_q_lock, flags);
- return ret;
- }
- int __msm_rpc_read(struct msm_rpc_endpoint *ept,
- struct rr_fragment **frag_ret,
- unsigned len, long timeout)
- {
- struct rr_packet *pkt;
- struct rpc_request_hdr *rq;
- struct msm_rpc_reply *reply;
- unsigned long flags;
- int rc;
- rc = wait_for_restart_and_notify(ept);
- if (rc)
- return rc;
- IO("READ on ept %p\n", ept);
- if (ept->flags & MSM_RPC_UNINTERRUPTIBLE) {
- if (timeout < 0) {
- wait_event(ept->wait_q, (ept_packet_available(ept) ||
- ept->forced_wakeup ||
- ept->restart_state));
- if (!msm_rpc_clear_netreset(ept))
- return -ENETRESET;
- } else {
- rc = wait_event_timeout(
- ept->wait_q,
- (ept_packet_available(ept) ||
- ept->forced_wakeup ||
- ept->restart_state),
- timeout);
- if (!msm_rpc_clear_netreset(ept))
- return -ENETRESET;
- if (rc == 0)
- return -ETIMEDOUT;
- }
- } else {
- if (timeout < 0) {
- rc = wait_event_interruptible(
- ept->wait_q, (ept_packet_available(ept) ||
- ept->forced_wakeup ||
- ept->restart_state));
- if (!msm_rpc_clear_netreset(ept))
- return -ENETRESET;
- if (rc < 0)
- return rc;
- } else {
- rc = wait_event_interruptible_timeout(
- ept->wait_q,
- (ept_packet_available(ept) ||
- ept->forced_wakeup ||
- ept->restart_state),
- timeout);
- if (!msm_rpc_clear_netreset(ept))
- return -ENETRESET;
- if (rc == 0)
- return -ETIMEDOUT;
- }
- }
- if (ept->forced_wakeup) {
- ept->forced_wakeup = 0;
- return 0;
- }
- spin_lock_irqsave(&ept->read_q_lock, flags);
- if (list_empty(&ept->read_q)) {
- spin_unlock_irqrestore(&ept->read_q_lock, flags);
- return -EAGAIN;
- }
- pkt = list_first_entry(&ept->read_q, struct rr_packet, list);
- if (pkt->length > len) {
- spin_unlock_irqrestore(&ept->read_q_lock, flags);
- return -ETOOSMALL;
- }
- list_del(&pkt->list);
- spin_unlock_irqrestore(&ept->read_q_lock, flags);
- rc = pkt->length;
- *frag_ret = pkt->first;
- rq = (void*) pkt->first->data;
- if ((rc >= (sizeof(uint32_t) * 3)) && (rq->type == 0)) {
- /* RPC CALL */
- reply = get_avail_reply(ept);
- if (!reply) {
- rc = -ENOMEM;
- goto read_release_lock;
- }
- reply->cid = pkt->hdr.src_cid;
- reply->pid = pkt->hdr.src_pid;
- reply->xid = rq->xid;
- reply->prog = rq->prog;
- reply->vers = rq->vers;
- set_pend_reply(ept, reply);
- }
- kfree(pkt);
- IO("READ on ept %p (%d bytes)\n", ept, rc);
- read_release_lock:
- /* release read wakelock after taking reply wakelock */
- spin_lock_irqsave(&ept->read_q_lock, flags);
- if (list_empty(&ept->read_q)) {
- D("%s: release read lock on ept %p\n", __func__, ept);
- wake_unlock(&ept->read_q_wake_lock);
- }
- spin_unlock_irqrestore(&ept->read_q_lock, flags);
- return rc;
- }
- int msm_rpc_is_compatible_version(uint32_t server_version,
- uint32_t client_version)
- {
- if ((server_version & RPC_VERSION_MODE_MASK) !=
- (client_version & RPC_VERSION_MODE_MASK))
- return 0;
- if (server_version & RPC_VERSION_MODE_MASK)
- return server_version == client_version;
- return ((server_version & RPC_VERSION_MAJOR_MASK) ==
- (client_version & RPC_VERSION_MAJOR_MASK)) &&
- ((server_version & RPC_VERSION_MINOR_MASK) >=
- (client_version & RPC_VERSION_MINOR_MASK));
- }
- EXPORT_SYMBOL(msm_rpc_is_compatible_version);
- static struct rr_server *msm_rpc_get_server(uint32_t prog, uint32_t vers,
- uint32_t accept_compatible,
- uint32_t *found_prog)
- {
- struct rr_server *server;
- unsigned long flags;
- if (found_prog == NULL)
- return NULL;
- *found_prog = 0;
- spin_lock_irqsave(&server_list_lock, flags);
- list_for_each_entry(server, &server_list, list) {
- if (server->prog == prog) {
- *found_prog = 1;
- spin_unlock_irqrestore(&server_list_lock, flags);
- if (accept_compatible) {
- if (msm_rpc_is_compatible_version(server->vers,
- vers)) {
- return server;
- } else {
- return NULL;
- }
- } else if (server->vers == vers) {
- return server;
- } else
- return NULL;
- }
- }
- spin_unlock_irqrestore(&server_list_lock, flags);
- return NULL;
- }
- static struct msm_rpc_endpoint *__msm_rpc_connect(uint32_t prog, uint32_t vers,
- uint32_t accept_compatible,
- unsigned flags)
- {
- struct msm_rpc_endpoint *ept;
- struct rr_server *server;
- uint32_t found_prog;
- int rc = 0;
- DEFINE_WAIT(__wait);
- for (;;) {
- prepare_to_wait(&newserver_wait, &__wait,
- TASK_INTERRUPTIBLE);
- server = msm_rpc_get_server(prog, vers, accept_compatible,
- &found_prog);
- if (server)
- break;
- if (found_prog) {
- pr_info("%s: server not found %x:%x\n",
- __func__, prog, vers);
- rc = -EHOSTUNREACH;
- break;
- }
- if (msm_rpc_connect_timeout_ms == 0) {
- rc = -EHOSTUNREACH;
- break;
- }
- if (signal_pending(current)) {
- rc = -ERESTARTSYS;
- break;
- }
- rc = schedule_timeout(
- msecs_to_jiffies(msm_rpc_connect_timeout_ms));
- if (!rc) {
- rc = -ETIMEDOUT;
- break;
- }
- }
- finish_wait(&newserver_wait, &__wait);
- if (!server)
- return ERR_PTR(rc);
- if (accept_compatible && (server->vers != vers)) {
- D("RPC Using new version 0x%08x(0x%08x) prog 0x%08x",
- vers, server->vers, prog);
- D(" ... Continuing\n");
- }
- ept = msm_rpc_open();
- if (IS_ERR(ept))
- return ept;
- ept->flags = flags;
- ept->dst_pid = server->pid;
- ept->dst_cid = server->cid;
- ept->dst_prog = cpu_to_be32(prog);
- ept->dst_vers = cpu_to_be32(server->vers);
- return ept;
- }
- struct msm_rpc_endpoint *msm_rpc_connect_compatible(uint32_t prog,
- uint32_t vers, unsigned flags)
- {
- return __msm_rpc_connect(prog, vers, 1, flags);
- }
- EXPORT_SYMBOL(msm_rpc_connect_compatible);
- struct msm_rpc_endpoint *msm_rpc_connect(uint32_t prog,
- uint32_t vers, unsigned flags)
- {
- return __msm_rpc_connect(prog, vers, 0, flags);
- }
- EXPORT_SYMBOL(msm_rpc_connect);
- /* TODO: permission check? */
- int msm_rpc_register_server(struct msm_rpc_endpoint *ept,
- uint32_t prog, uint32_t vers)
- {
- int rc;
- union rr_control_msg msg = { 0 };
- struct rr_server *server;
- struct rpcrouter_xprt_info *xprt_info;
- server = rpcrouter_create_server(ept->pid, ept->cid,
- prog, vers);
- if (!server)
- return -ENODEV;
- msg.srv.cmd = RPCROUTER_CTRL_CMD_NEW_SERVER;
- msg.srv.pid = ept->pid;
- msg.srv.cid = ept->cid;
- msg.srv.prog = prog;
- msg.srv.vers = vers;
- RR("x NEW_SERVER id=%d:%08x prog=%08x:%08x\n",
- ept->pid, ept->cid, prog, vers);
- mutex_lock(&xprt_info_list_lock);
- list_for_each_entry(xprt_info, &xprt_info_list, list) {
- rc = rpcrouter_send_control_msg(xprt_info, &msg);
- if (rc < 0) {
- mutex_unlock(&xprt_info_list_lock);
- return rc;
- }
- }
- mutex_unlock(&xprt_info_list_lock);
- return 0;
- }
- int msm_rpc_clear_netreset(struct msm_rpc_endpoint *ept)
- {
- unsigned long flags;
- int rc = 1;
- spin_lock_irqsave(&ept->restart_lock, flags);
- if (ept->restart_state != RESTART_NORMAL) {
- ept->restart_state &= ~RESTART_PEND_NTFY;
- rc = 0;
- }
- spin_unlock_irqrestore(&ept->restart_lock, flags);
- return rc;
- }
- /* TODO: permission check -- disallow unreg of somebody else's server */
- int msm_rpc_unregister_server(struct msm_rpc_endpoint *ept,
- uint32_t prog, uint32_t vers)
- {
- struct rr_server *server;
- server = rpcrouter_lookup_server(prog, vers);
- if (!server)
- return -ENOENT;
- rpcrouter_destroy_server(server);
- return 0;
- }
- int msm_rpc_get_curr_pkt_size(struct msm_rpc_endpoint *ept)
- {
- unsigned long flags;
- struct rr_packet *pkt;
- int rc = 0;
- if (!ept)
- return -EINVAL;
- if (!msm_rpc_clear_netreset(ept))
- return -ENETRESET;
- spin_lock_irqsave(&ept->read_q_lock, flags);
- if (!list_empty(&ept->read_q)) {
- pkt = list_first_entry(&ept->read_q, struct rr_packet, list);
- rc = pkt->length;
- }
- spin_unlock_irqrestore(&ept->read_q_lock, flags);
- return rc;
- }
- static int msm_rpcrouter_close(void)
- {
- struct rpcrouter_xprt_info *xprt_info;
- union rr_control_msg ctl = { 0 };
- ctl.cmd = RPCROUTER_CTRL_CMD_BYE;
- mutex_lock(&xprt_info_list_lock);
- while (!list_empty(&xprt_info_list)) {
- xprt_info = list_first_entry(&xprt_info_list,
- struct rpcrouter_xprt_info, list);
- modem_reset_cleanup(xprt_info);
- xprt_info->abort_data_read = 1;
- wake_up(&xprt_info->read_wait);
- rpcrouter_send_control_msg(xprt_info, &ctl);
- xprt_info->xprt->close();
- list_del(&xprt_info->list);
- mutex_unlock(&xprt_info_list_lock);
- flush_workqueue(xprt_info->workqueue);
- destroy_workqueue(xprt_info->workqueue);
- wake_lock_destroy(&xprt_info->wakelock);
- /*free memory*/
- xprt_info->xprt->priv = 0;
- kfree(xprt_info);
- mutex_lock(&xprt_info_list_lock);
- }
- mutex_unlock(&xprt_info_list_lock);
- return 0;
- }
- #if defined(CONFIG_DEBUG_FS)
- static int dump_servers(char *buf, int max)
- {
- int i = 0;
- unsigned long flags;
- struct rr_server *svr;
- const char *sym;
- spin_lock_irqsave(&server_list_lock, flags);
- list_for_each_entry(svr, &server_list, list) {
- i += scnprintf(buf + i, max - i, "pdev_name: %s\n",
- svr->pdev_name);
- i += scnprintf(buf + i, max - i, "pid: 0x%08x\n", svr->pid);
- i += scnprintf(buf + i, max - i, "cid: 0x%08x\n", svr->cid);
- i += scnprintf(buf + i, max - i, "prog: 0x%08x", svr->prog);
- sym = smd_rpc_get_sym(svr->prog);
- if (sym)
- i += scnprintf(buf + i, max - i, " (%s)\n", sym);
- else
- i += scnprintf(buf + i, max - i, "\n");
- i += scnprintf(buf + i, max - i, "vers: 0x%08x\n", svr->vers);
- i += scnprintf(buf + i, max - i, "\n");
- }
- spin_unlock_irqrestore(&server_list_lock, flags);
- return i;
- }
- static int dump_remote_endpoints(char *buf, int max)
- {
- int i = 0;
- unsigned long flags;
- struct rr_remote_endpoint *ept;
- spin_lock_irqsave(&remote_endpoints_lock, flags);
- list_for_each_entry(ept, &remote_endpoints, list) {
- i += scnprintf(buf + i, max - i, "pid: 0x%08x\n", ept->pid);
- i += scnprintf(buf + i, max - i, "cid: 0x%08x\n", ept->cid);
- i += scnprintf(buf + i, max - i, "tx_quota_cntr: %i\n",
- ept->tx_quota_cntr);
- i += scnprintf(buf + i, max - i, "quota_restart_state: %i\n",
- ept->quota_restart_state);
- i += scnprintf(buf + i, max - i, "\n");
- }
- spin_unlock_irqrestore(&remote_endpoints_lock, flags);
- return i;
- }
- static int dump_msm_rpc_endpoint(char *buf, int max)
- {
- int i = 0;
- unsigned long flags;
- struct msm_rpc_reply *reply;
- struct msm_rpc_endpoint *ept;
- struct rr_packet *pkt;
- const char *sym;
- spin_lock_irqsave(&local_endpoints_lock, flags);
- list_for_each_entry(ept, &local_endpoints, list) {
- i += scnprintf(buf + i, max - i, "pid: 0x%08x\n", ept->pid);
- i += scnprintf(buf + i, max - i, "cid: 0x%08x\n", ept->cid);
- i += scnprintf(buf + i, max - i, "dst_pid: 0x%08x\n",
- ept->dst_pid);
- i += scnprintf(buf + i, max - i, "dst_cid: 0x%08x\n",
- ept->dst_cid);
- i += scnprintf(buf + i, max - i, "dst_prog: 0x%08x",
- be32_to_cpu(ept->dst_prog));
- sym = smd_rpc_get_sym(be32_to_cpu(ept->dst_prog));
- if (sym)
- i += scnprintf(buf + i, max - i, " (%s)\n", sym);
- else
- i += scnprintf(buf + i, max - i, "\n");
- i += scnprintf(buf + i, max - i, "dst_vers: 0x%08x\n",
- be32_to_cpu(ept->dst_vers));
- i += scnprintf(buf + i, max - i, "reply_cnt: %i\n",
- ept->reply_cnt);
- i += scnprintf(buf + i, max - i, "restart_state: %i\n",
- ept->restart_state);
- i += scnprintf(buf + i, max - i, "outstanding xids:\n");
- spin_lock(&ept->reply_q_lock);
- list_for_each_entry(reply, &ept->reply_pend_q, list)
- i += scnprintf(buf + i, max - i, " xid = %u\n",
- ntohl(reply->xid));
- spin_unlock(&ept->reply_q_lock);
- i += scnprintf(buf + i, max - i, "complete unread packets:\n");
- spin_lock(&ept->read_q_lock);
- list_for_each_entry(pkt, &ept->read_q, list) {
- i += scnprintf(buf + i, max - i, " mid = %i\n",
- pkt->mid);
- i += scnprintf(buf + i, max - i, " length = %i\n",
- pkt->length);
- }
- spin_unlock(&ept->read_q_lock);
- i += scnprintf(buf + i, max - i, "\n");
- }
- spin_unlock_irqrestore(&local_endpoints_lock, flags);
- return i;
- }
- #define DEBUG_BUFMAX 4096
- static char debug_buffer[DEBUG_BUFMAX];
- static ssize_t debug_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
- {
- int (*fill)(char *buf, int max) = file->private_data;
- int bsize = fill(debug_buffer, DEBUG_BUFMAX);
- return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
- }
- static int debug_open(struct inode *inode, struct file *file)
- {
- file->private_data = inode->i_private;
- return 0;
- }
- static const struct file_operations debug_ops = {
- .read = debug_read,
- .open = debug_open,
- };
- static void debug_create(const char *name, mode_t mode,
- struct dentry *dent,
- int (*fill)(char *buf, int max))
- {
- debugfs_create_file(name, mode, dent, fill, &debug_ops);
- }
- static void debugfs_init(void)
- {
- struct dentry *dent;
- dent = debugfs_create_dir("smd_rpcrouter", 0);
- if (IS_ERR(dent))
- return;
- debug_create("dump_msm_rpc_endpoints", 0444, dent,
- dump_msm_rpc_endpoint);
- debug_create("dump_remote_endpoints", 0444, dent,
- dump_remote_endpoints);
- debug_create("dump_servers", 0444, dent,
- dump_servers);
- }
- #else
- static void debugfs_init(void) {}
- #endif
- static int msm_rpcrouter_add_xprt(struct rpcrouter_xprt *xprt)
- {
- struct rpcrouter_xprt_info *xprt_info;
- D("Registering xprt %s to RPC Router\n", xprt->name);
- xprt_info = kmalloc(sizeof(struct rpcrouter_xprt_info), GFP_KERNEL);
- if (!xprt_info)
- return -ENOMEM;
- xprt_info->xprt = xprt;
- xprt_info->initialized = 0;
- xprt_info->remote_pid = -1;
- init_waitqueue_head(&xprt_info->read_wait);
- spin_lock_init(&xprt_info->lock);
- wake_lock_init(&xprt_info->wakelock,
- WAKE_LOCK_SUSPEND, xprt->name);
- xprt_info->need_len = 0;
- xprt_info->abort_data_read = 0;
- INIT_WORK(&xprt_info->read_data, do_read_data);
- INIT_LIST_HEAD(&xprt_info->list);
- xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
- if (!xprt_info->workqueue) {
- kfree(xprt_info);
- return -ENOMEM;
- }
- if (!strcmp(xprt->name, "rpcrouter_loopback_xprt")) {
- xprt_info->remote_pid = RPCROUTER_PID_LOCAL;
- xprt_info->initialized = 1;
- } else {
- smsm_change_state(SMSM_APPS_STATE, 0, SMSM_RPCINIT);
- }
- mutex_lock(&xprt_info_list_lock);
- list_add_tail(&xprt_info->list, &xprt_info_list);
- mutex_unlock(&xprt_info_list_lock);
- queue_work(xprt_info->workqueue, &xprt_info->read_data);
- xprt->priv = xprt_info;
- return 0;
- }
- static void msm_rpcrouter_remove_xprt(struct rpcrouter_xprt *xprt)
- {
- struct rpcrouter_xprt_info *xprt_info;
- unsigned long flags;
- if (xprt && xprt->priv) {
- xprt_info = xprt->priv;
- /* abort rr_read thread */
- xprt_info->abort_data_read = 1;
- wake_up(&xprt_info->read_wait);
- /* remove xprt from available xprts */
- mutex_lock(&xprt_info_list_lock);
- spin_lock_irqsave(&xprt_info->lock, flags);
- list_del(&xprt_info->list);
- /* unlock the spinlock last to avoid a race
- * condition with rpcrouter_get_xprt_info
- * in msm_rpc_write_pkt in which the
- * xprt is returned from rpcrouter_get_xprt_info
- * and then deleted here. */
- mutex_unlock(&xprt_info_list_lock);
- spin_unlock_irqrestore(&xprt_info->lock, flags);
- /* cleanup workqueues and wakelocks */
- flush_workqueue(xprt_info->workqueue);
- destroy_workqueue(xprt_info->workqueue);
- wake_lock_destroy(&xprt_info->wakelock);
- /* free memory */
- xprt->priv = 0;
- kfree(xprt_info);
- }
- }
- struct rpcrouter_xprt_work {
- struct rpcrouter_xprt *xprt;
- struct work_struct work;
- };
- static void xprt_open_worker(struct work_struct *work)
- {
- struct rpcrouter_xprt_work *xprt_work =
- container_of(work, struct rpcrouter_xprt_work, work);
- msm_rpcrouter_add_xprt(xprt_work->xprt);
- kfree(xprt_work);
- }
- static void xprt_close_worker(struct work_struct *work)
- {
- struct rpcrouter_xprt_work *xprt_work =
- container_of(work, struct rpcrouter_xprt_work, work);
- modem_reset_cleanup(xprt_work->xprt->priv);
- msm_rpcrouter_remove_xprt(xprt_work->xprt);
- if (atomic_dec_return(&pending_close_count) == 0)
- wake_up(&subsystem_restart_wait);
- kfree(xprt_work);
- }
- void msm_rpcrouter_xprt_notify(struct rpcrouter_xprt *xprt, unsigned event)
- {
- struct rpcrouter_xprt_info *xprt_info;
- struct rpcrouter_xprt_work *xprt_work;
- unsigned long flags;
- /* Workqueue is created in init function which works for all existing
- * clients. If this fails in the future, then it will need to be
- * created earlier. */
- BUG_ON(!rpcrouter_workqueue);
- switch (event) {
- case RPCROUTER_XPRT_EVENT_OPEN:
- D("open event for '%s'\n", xprt->name);
- xprt_work = kmalloc(sizeof(struct rpcrouter_xprt_work),
- GFP_ATOMIC);
- xprt_work->xprt = xprt;
- INIT_WORK(&xprt_work->work, xprt_open_worker);
- queue_work(rpcrouter_workqueue, &xprt_work->work);
- break;
- case RPCROUTER_XPRT_EVENT_CLOSE:
- D("close event for '%s'\n", xprt->name);
- atomic_inc(&pending_close_count);
- xprt_work = kmalloc(sizeof(struct rpcrouter_xprt_work),
- GFP_ATOMIC);
- xprt_work->xprt = xprt;
- INIT_WORK(&xprt_work->work, xprt_close_worker);
- queue_work(rpcrouter_workqueue, &xprt_work->work);
- break;
- }
- xprt_info = xprt->priv;
- if (xprt_info) {
- spin_lock_irqsave(&xprt_info->lock, flags);
- /* Check read_avail even for OPEN event to handle missed
- DATA events while processing the OPEN event*/
- if (xprt->read_avail() >= xprt_info->need_len)
- wake_lock(&xprt_info->wakelock);
- wake_up(&xprt_info->read_wait);
- spin_unlock_irqrestore(&xprt_info->lock, flags);
- }
- }
- static int modem_restart_notifier_cb(struct notifier_block *this,
- unsigned long code,
- void *data);
- static struct notifier_block nb = {
- .notifier_call = modem_restart_notifier_cb,
- };
- static int modem_restart_notifier_cb(struct notifier_block *this,
- unsigned long code,
- void *data)
- {
- switch (code) {
- case SUBSYS_BEFORE_SHUTDOWN:
- D("%s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
- break;
- case SUBSYS_BEFORE_POWERUP:
- D("%s: waiting for RPC restart to complete\n", __func__);
- wait_event(subsystem_restart_wait,
- atomic_read(&pending_close_count) == 0);
- D("%s: finished restart wait\n", __func__);
- break;
- default:
- break;
- }
- return NOTIFY_DONE;
- }
- static void *restart_notifier_handle;
- static __init int modem_restart_late_init(void)
- {
- restart_notifier_handle = subsys_notif_register_notifier("modem", &nb);
- return 0;
- }
- late_initcall(modem_restart_late_init);
- static int __init rpcrouter_init(void)
- {
- int ret;
- msm_rpc_connect_timeout_ms = 0;
- smd_rpcrouter_debug_mask |= SMEM_LOG;
- debugfs_init();
- ret = register_reboot_notifier(&msm_rpc_reboot_notifier);
- if (ret)
- pr_err("%s: Failed to register reboot notifier", __func__);
- /* Initialize what we need to start processing */
- rpcrouter_workqueue =
- create_singlethread_workqueue("rpcrouter");
- if (!rpcrouter_workqueue) {
- msm_rpcrouter_exit_devices();
- return -ENOMEM;
- }
- init_waitqueue_head(&newserver_wait);
- init_waitqueue_head(&subsystem_restart_wait);
- ret = msm_rpcrouter_init_devices();
- if (ret < 0)
- return ret;
- return ret;
- }
- module_init(rpcrouter_init);
- MODULE_DESCRIPTION("MSM RPC Router");
- MODULE_AUTHOR("San Mehat <san@android.com>");
- MODULE_LICENSE("GPL");
|