1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341 |
- /* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * 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.
- */
- #include <linux/clk.h>
- #include <linux/device.h>
- #include <linux/dmapool.h>
- #include <linux/fs.h>
- #include <linux/genalloc.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/mm.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/platform_device.h>
- #include <linux/rbtree.h>
- #include <linux/uaccess.h>
- #include <mach/msm_bus.h>
- #include <mach/msm_bus_board.h>
- #include "ipa_i.h"
- #include "ipa_rm_i.h"
- #define IPA_SUMMING_THRESHOLD (0x10)
- #define IPA_PIPE_MEM_START_OFST (0x0)
- #define IPA_PIPE_MEM_SIZE (0x0)
- #define IPA_MOBILE_AP_MODE(x) (x == IPA_MODE_MOBILE_AP_ETH || \
- x == IPA_MODE_MOBILE_AP_WAN || \
- x == IPA_MODE_MOBILE_AP_WLAN)
- #define IPA_CNOC_CLK_RATE (75 * 1000 * 1000UL)
- #define IPA_V1_CLK_RATE (92.31 * 1000 * 1000UL)
- #define IPA_V1_1_CLK_RATE (100 * 1000 * 1000UL)
- #define IPA_DEFAULT_HEADER_LENGTH (8)
- #define IPA_DMA_POOL_SIZE (512)
- #define IPA_DMA_POOL_ALIGNMENT (4)
- #define IPA_DMA_POOL_BOUNDARY (1024)
- #define IPA_NUM_DESC_PER_SW_TX (2)
- #define IPA_ROUTING_RULE_BYTE_SIZE (4)
- #define IPA_BAM_CNFG_BITS_VAL (0x7FFFE004)
- #define IPA_AGGR_MAX_STR_LENGTH (10)
- #define IPA_AGGR_STR_IN_BYTES(str) \
- (strnlen((str), IPA_AGGR_MAX_STR_LENGTH - 1) + 1)
- static struct ipa_plat_drv_res ipa_res = {0, };
- static struct of_device_id ipa_plat_drv_match[] = {
- {
- .compatible = "qcom,ipa",
- },
- {
- }
- };
- static struct clk *ipa_clk_src;
- static struct clk *ipa_clk;
- static struct clk *sys_noc_ipa_axi_clk;
- static struct clk *ipa_cnoc_clk;
- static struct clk *ipa_inactivity_clk;
- static struct msm_bus_vectors ipa_init_vectors[] = {
- {
- .src = MSM_BUS_MASTER_IPA,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 0,
- .ib = 0,
- },
- {
- .src = MSM_BUS_MASTER_BAM_DMA,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 0,
- .ib = 0,
- },
- {
- .src = MSM_BUS_MASTER_BAM_DMA,
- .dst = MSM_BUS_SLAVE_OCIMEM,
- .ab = 0,
- .ib = 0,
- },
- };
- static struct msm_bus_vectors ipa_max_perf_vectors[] = {
- {
- .src = MSM_BUS_MASTER_IPA,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 50000000,
- .ib = 960000000,
- },
- {
- .src = MSM_BUS_MASTER_BAM_DMA,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 50000000,
- .ib = 960000000,
- },
- {
- .src = MSM_BUS_MASTER_BAM_DMA,
- .dst = MSM_BUS_SLAVE_OCIMEM,
- .ab = 50000000,
- .ib = 960000000,
- },
- };
- static struct msm_bus_paths ipa_usecases[] = {
- {
- ARRAY_SIZE(ipa_init_vectors),
- ipa_init_vectors,
- },
- {
- ARRAY_SIZE(ipa_max_perf_vectors),
- ipa_max_perf_vectors,
- },
- };
- static struct msm_bus_scale_pdata ipa_bus_client_pdata = {
- ipa_usecases,
- ARRAY_SIZE(ipa_usecases),
- .name = "ipa",
- };
- static uint32_t ipa_bus_hdl;
- static struct device *ipa_dev;
- struct ipa_context *ipa_ctx;
- static bool polling_mode;
- module_param(polling_mode, bool, 0644);
- MODULE_PARM_DESC(polling_mode,
- "1 - pure polling mode; 0 - interrupt+polling mode");
- static uint polling_delay_ms = 50;
- module_param(polling_delay_ms, uint, 0644);
- MODULE_PARM_DESC(polling_delay_ms, "set to desired delay between polls");
- static bool hdr_tbl_lcl = 1;
- module_param(hdr_tbl_lcl, bool, 0644);
- MODULE_PARM_DESC(hdr_tbl_lcl, "where hdr tbl resides 1-local; 0-system");
- static bool ip4_rt_tbl_lcl;
- module_param(ip4_rt_tbl_lcl, bool, 0644);
- MODULE_PARM_DESC(ip4_rt_tbl_lcl,
- "where ip4 rt tables reside 1-local; 0-system");
- static bool ip6_rt_tbl_lcl;
- module_param(ip6_rt_tbl_lcl, bool, 0644);
- MODULE_PARM_DESC(ip6_rt_tbl_lcl,
- "where ip6 rt tables reside 1-local; 0-system");
- static bool ip4_flt_tbl_lcl = 1;
- module_param(ip4_flt_tbl_lcl, bool, 0644);
- MODULE_PARM_DESC(ip4_flt_tbl_lcl,
- "where ip4 flt tables reside 1-local; 0-system");
- static bool ip6_flt_tbl_lcl = 1;
- module_param(ip6_flt_tbl_lcl, bool, 0644);
- MODULE_PARM_DESC(ip6_flt_tbl_lcl,
- "where ip6 flt tables reside 1-local; 0-system");
- static int ipa_load_pipe_connection(struct platform_device *pdev,
- enum a2_mux_pipe_direction pipe_dir,
- struct a2_mux_pipe_connection *pdata);
- static int ipa_update_connections_info(struct device_node *node,
- struct a2_mux_pipe_connection *pipe_connection);
- static void ipa_set_aggregation_params(void);
- static int ipa_open(struct inode *inode, struct file *filp)
- {
- struct ipa_context *ctx = NULL;
- IPADBG("ENTER\n");
- ctx = container_of(inode->i_cdev, struct ipa_context, cdev);
- filp->private_data = ctx;
- return 0;
- }
- static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
- {
- int retval = 0;
- u32 pyld_sz;
- u8 header[128] = { 0 };
- u8 *param = NULL;
- struct ipa_ioc_nat_alloc_mem nat_mem;
- struct ipa_ioc_v4_nat_init nat_init;
- struct ipa_ioc_v4_nat_del nat_del;
- struct ipa_ioc_rm_dependency rm_depend;
- size_t sz;
- int pre_entry;
- IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
- if (_IOC_TYPE(cmd) != IPA_IOC_MAGIC)
- return -ENOTTY;
- if (_IOC_NR(cmd) >= IPA_IOCTL_MAX)
- return -ENOTTY;
- ipa_inc_client_enable_clks();
- switch (cmd) {
- case IPA_IOC_ALLOC_NAT_MEM:
- if (copy_from_user((u8 *)&nat_mem, (u8 *)arg,
- sizeof(struct ipa_ioc_nat_alloc_mem))) {
- retval = -EFAULT;
- break;
- }
- /* null terminate the string */
- nat_mem.dev_name[IPA_RESOURCE_NAME_MAX - 1] = '\0';
- if (allocate_nat_device(&nat_mem)) {
- retval = -EFAULT;
- break;
- }
- if (copy_to_user((u8 *)arg, (u8 *)&nat_mem,
- sizeof(struct ipa_ioc_nat_alloc_mem))) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_V4_INIT_NAT:
- if (copy_from_user((u8 *)&nat_init, (u8 *)arg,
- sizeof(struct ipa_ioc_v4_nat_init))) {
- retval = -EFAULT;
- break;
- }
- if (ipa_nat_init_cmd(&nat_init)) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_NAT_DMA:
- if (copy_from_user(header, (u8 *)arg,
- sizeof(struct ipa_ioc_nat_dma_cmd))) {
- retval = -EFAULT;
- break;
- }
- pre_entry =
- ((struct ipa_ioc_nat_dma_cmd *)header)->entries;
- pyld_sz =
- sizeof(struct ipa_ioc_nat_dma_cmd) +
- pre_entry * sizeof(struct ipa_ioc_nat_dma_one);
- param = kzalloc(pyld_sz, GFP_KERNEL);
- if (!param) {
- retval = -ENOMEM;
- break;
- }
- if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- /* add check in case user-space module compromised */
- if (unlikely(((struct ipa_ioc_nat_dma_cmd *)param)->entries
- != pre_entry)) {
- IPAERR("current %d pre %d\n",
- ((struct ipa_ioc_nat_dma_cmd *)param)->entries,
- pre_entry);
- retval = -EFAULT;
- break;
- }
- if (ipa_nat_dma_cmd((struct ipa_ioc_nat_dma_cmd *)param)) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_V4_DEL_NAT:
- if (copy_from_user((u8 *)&nat_del, (u8 *)arg,
- sizeof(struct ipa_ioc_v4_nat_del))) {
- retval = -EFAULT;
- break;
- }
- if (ipa_nat_del_cmd(&nat_del)) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_ADD_HDR:
- if (copy_from_user(header, (u8 *)arg,
- sizeof(struct ipa_ioc_add_hdr))) {
- retval = -EFAULT;
- break;
- }
- pre_entry =
- ((struct ipa_ioc_add_hdr *)header)->num_hdrs;
- pyld_sz =
- sizeof(struct ipa_ioc_add_hdr) +
- pre_entry * sizeof(struct ipa_hdr_add);
- param = kzalloc(pyld_sz, GFP_KERNEL);
- if (!param) {
- retval = -ENOMEM;
- break;
- }
- if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- /* add check in case user-space module compromised */
- if (unlikely(((struct ipa_ioc_add_hdr *)param)->num_hdrs
- != pre_entry)) {
- IPAERR("current %d pre %d\n",
- ((struct ipa_ioc_add_hdr *)param)->num_hdrs,
- pre_entry);
- retval = -EFAULT;
- break;
- }
- if (ipa_add_hdr((struct ipa_ioc_add_hdr *)param)) {
- retval = -EFAULT;
- break;
- }
- if (copy_to_user((u8 *)arg, param, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_DEL_HDR:
- if (copy_from_user(header, (u8 *)arg,
- sizeof(struct ipa_ioc_del_hdr))) {
- retval = -EFAULT;
- break;
- }
- pre_entry =
- ((struct ipa_ioc_del_hdr *)header)->num_hdls;
- pyld_sz =
- sizeof(struct ipa_ioc_del_hdr) +
- pre_entry * sizeof(struct ipa_hdr_del);
- param = kzalloc(pyld_sz, GFP_KERNEL);
- if (!param) {
- retval = -ENOMEM;
- break;
- }
- if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- /* add check in case user-space module compromised */
- if (unlikely(((struct ipa_ioc_del_hdr *)param)->num_hdls
- != pre_entry)) {
- IPAERR("current %d pre %d\n",
- ((struct ipa_ioc_del_hdr *)param)->num_hdls,
- pre_entry);
- retval = -EFAULT;
- break;
- }
- if (ipa_del_hdr_by_user((struct ipa_ioc_del_hdr *)param,
- true)) {
- retval = -EFAULT;
- break;
- }
- if (copy_to_user((u8 *)arg, param, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_ADD_RT_RULE:
- if (copy_from_user(header, (u8 *)arg,
- sizeof(struct ipa_ioc_add_rt_rule))) {
- retval = -EFAULT;
- break;
- }
- pre_entry =
- ((struct ipa_ioc_add_rt_rule *)header)->num_rules;
- pyld_sz =
- sizeof(struct ipa_ioc_add_rt_rule) +
- pre_entry * sizeof(struct ipa_rt_rule_add);
- param = kzalloc(pyld_sz, GFP_KERNEL);
- if (!param) {
- retval = -ENOMEM;
- break;
- }
- if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- /* add check in case user-space module compromised */
- if (unlikely(((struct ipa_ioc_add_rt_rule *)param)->num_rules
- != pre_entry)) {
- IPAERR("current %d pre %d\n",
- ((struct ipa_ioc_add_rt_rule *)param)->num_rules,
- pre_entry);
- retval = -EFAULT;
- break;
- }
- if (ipa_add_rt_rule((struct ipa_ioc_add_rt_rule *)param)) {
- retval = -EFAULT;
- break;
- }
- if (copy_to_user((u8 *)arg, param, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_DEL_RT_RULE:
- if (copy_from_user(header, (u8 *)arg,
- sizeof(struct ipa_ioc_del_rt_rule))) {
- retval = -EFAULT;
- break;
- }
- pre_entry =
- ((struct ipa_ioc_del_rt_rule *)header)->num_hdls;
- pyld_sz =
- sizeof(struct ipa_ioc_del_rt_rule) +
- pre_entry * sizeof(struct ipa_rt_rule_del);
- param = kzalloc(pyld_sz, GFP_KERNEL);
- if (!param) {
- retval = -ENOMEM;
- break;
- }
- if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- /* add check in case user-space module compromised */
- if (unlikely(((struct ipa_ioc_del_rt_rule *)param)->num_hdls
- != pre_entry)) {
- IPAERR("current %d pre %d\n",
- ((struct ipa_ioc_del_rt_rule *)param)->num_hdls,
- pre_entry);
- retval = -EFAULT;
- break;
- }
- if (ipa_del_rt_rule((struct ipa_ioc_del_rt_rule *)param)) {
- retval = -EFAULT;
- break;
- }
- if (copy_to_user((u8 *)arg, param, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_ADD_FLT_RULE:
- if (copy_from_user(header, (u8 *)arg,
- sizeof(struct ipa_ioc_add_flt_rule))) {
- retval = -EFAULT;
- break;
- }
- pre_entry =
- ((struct ipa_ioc_add_flt_rule *)header)->num_rules;
- pyld_sz =
- sizeof(struct ipa_ioc_add_flt_rule) +
- pre_entry * sizeof(struct ipa_flt_rule_add);
- param = kzalloc(pyld_sz, GFP_KERNEL);
- if (!param) {
- retval = -ENOMEM;
- break;
- }
- if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- /* add check in case user-space module compromised */
- if (unlikely(((struct ipa_ioc_add_flt_rule *)param)->num_rules
- != pre_entry)) {
- IPAERR("current %d pre %d\n",
- ((struct ipa_ioc_add_flt_rule *)param)->num_rules,
- pre_entry);
- retval = -EFAULT;
- break;
- }
- if (ipa_add_flt_rule((struct ipa_ioc_add_flt_rule *)param)) {
- retval = -EFAULT;
- break;
- }
- if (copy_to_user((u8 *)arg, param, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_DEL_FLT_RULE:
- if (copy_from_user(header, (u8 *)arg,
- sizeof(struct ipa_ioc_del_flt_rule))) {
- retval = -EFAULT;
- break;
- }
- pre_entry =
- ((struct ipa_ioc_del_flt_rule *)header)->num_hdls;
- pyld_sz =
- sizeof(struct ipa_ioc_del_flt_rule) +
- pre_entry * sizeof(struct ipa_flt_rule_del);
- param = kzalloc(pyld_sz, GFP_KERNEL);
- if (!param) {
- retval = -ENOMEM;
- break;
- }
- if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- /* add check in case user-space module compromised */
- if (unlikely(((struct ipa_ioc_del_flt_rule *)param)->num_hdls
- != pre_entry)) {
- IPAERR("current %d pre %d\n",
- ((struct ipa_ioc_del_flt_rule *)param)->num_hdls,
- pre_entry);
- retval = -EFAULT;
- break;
- }
- if (ipa_del_flt_rule((struct ipa_ioc_del_flt_rule *)param)) {
- retval = -EFAULT;
- break;
- }
- if (copy_to_user((u8 *)arg, param, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_COMMIT_HDR:
- retval = ipa_commit_hdr();
- break;
- case IPA_IOC_RESET_HDR:
- retval = ipa_reset_hdr();
- break;
- case IPA_IOC_COMMIT_RT:
- retval = ipa_commit_rt(arg);
- break;
- case IPA_IOC_RESET_RT:
- retval = ipa_reset_rt(arg);
- break;
- case IPA_IOC_COMMIT_FLT:
- retval = ipa_commit_flt(arg);
- break;
- case IPA_IOC_RESET_FLT:
- retval = ipa_reset_flt(arg);
- break;
- case IPA_IOC_DUMP:
- ipa_dump();
- break;
- case IPA_IOC_GET_RT_TBL:
- if (copy_from_user(header, (u8 *)arg,
- sizeof(struct ipa_ioc_get_rt_tbl))) {
- retval = -EFAULT;
- break;
- }
- if (ipa_get_rt_tbl((struct ipa_ioc_get_rt_tbl *)header)) {
- retval = -EFAULT;
- break;
- }
- if (copy_to_user((u8 *)arg, header,
- sizeof(struct ipa_ioc_get_rt_tbl))) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_PUT_RT_TBL:
- retval = ipa_put_rt_tbl(arg);
- break;
- case IPA_IOC_GET_HDR:
- if (copy_from_user(header, (u8 *)arg,
- sizeof(struct ipa_ioc_get_hdr))) {
- retval = -EFAULT;
- break;
- }
- if (ipa_get_hdr((struct ipa_ioc_get_hdr *)header)) {
- retval = -EFAULT;
- break;
- }
- if (copy_to_user((u8 *)arg, header,
- sizeof(struct ipa_ioc_get_hdr))) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_PUT_HDR:
- retval = ipa_put_hdr(arg);
- break;
- case IPA_IOC_SET_FLT:
- retval = ipa_cfg_filter(arg);
- break;
- case IPA_IOC_COPY_HDR:
- if (copy_from_user(header, (u8 *)arg,
- sizeof(struct ipa_ioc_copy_hdr))) {
- retval = -EFAULT;
- break;
- }
- if (ipa_copy_hdr((struct ipa_ioc_copy_hdr *)header)) {
- retval = -EFAULT;
- break;
- }
- if (copy_to_user((u8 *)arg, header,
- sizeof(struct ipa_ioc_copy_hdr))) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_QUERY_INTF:
- if (copy_from_user(header, (u8 *)arg,
- sizeof(struct ipa_ioc_query_intf))) {
- retval = -EFAULT;
- break;
- }
- if (ipa_query_intf((struct ipa_ioc_query_intf *)header)) {
- retval = -1;
- break;
- }
- if (copy_to_user((u8 *)arg, header,
- sizeof(struct ipa_ioc_query_intf))) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_QUERY_INTF_TX_PROPS:
- sz = sizeof(struct ipa_ioc_query_intf_tx_props);
- if (copy_from_user(header, (u8 *)arg, sz)) {
- retval = -EFAULT;
- break;
- }
- if (((struct ipa_ioc_query_intf_tx_props *)
- header)->num_tx_props > IPA_NUM_PROPS_MAX) {
- retval = -EFAULT;
- break;
- }
- pre_entry =
- ((struct ipa_ioc_query_intf_tx_props *)
- header)->num_tx_props;
- pyld_sz = sz + pre_entry *
- sizeof(struct ipa_ioc_tx_intf_prop);
- param = kzalloc(pyld_sz, GFP_KERNEL);
- if (!param) {
- retval = -ENOMEM;
- break;
- }
- if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- /* add check in case user-space module compromised */
- if (unlikely(((struct ipa_ioc_query_intf_tx_props *)
- param)->num_tx_props
- != pre_entry)) {
- IPAERR("current %d pre %d\n",
- ((struct ipa_ioc_query_intf_tx_props *)
- param)->num_tx_props, pre_entry);
- retval = -EFAULT;
- break;
- }
- if (ipa_query_intf_tx_props(
- (struct ipa_ioc_query_intf_tx_props *)param)) {
- retval = -1;
- break;
- }
- if (copy_to_user((u8 *)arg, param, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_QUERY_INTF_RX_PROPS:
- sz = sizeof(struct ipa_ioc_query_intf_rx_props);
- if (copy_from_user(header, (u8 *)arg, sz)) {
- retval = -EFAULT;
- break;
- }
- if (((struct ipa_ioc_query_intf_rx_props *)
- header)->num_rx_props > IPA_NUM_PROPS_MAX) {
- retval = -EFAULT;
- break;
- }
- pre_entry =
- ((struct ipa_ioc_query_intf_rx_props *)
- header)->num_rx_props;
- pyld_sz = sz + pre_entry *
- sizeof(struct ipa_ioc_rx_intf_prop);
- param = kzalloc(pyld_sz, GFP_KERNEL);
- if (!param) {
- retval = -ENOMEM;
- break;
- }
- if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- /* add check in case user-space module compromised */
- if (unlikely(((struct ipa_ioc_query_intf_rx_props *)
- param)->num_rx_props != pre_entry)) {
- IPAERR("current %d pre %d\n",
- ((struct ipa_ioc_query_intf_rx_props *)
- param)->num_rx_props, pre_entry);
- retval = -EFAULT;
- break;
- }
- if (ipa_query_intf_rx_props(
- (struct ipa_ioc_query_intf_rx_props *)param)) {
- retval = -1;
- break;
- }
- if (copy_to_user((u8 *)arg, param, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_PULL_MSG:
- if (copy_from_user(header, (u8 *)arg,
- sizeof(struct ipa_msg_meta))) {
- retval = -EFAULT;
- break;
- }
- pre_entry =
- ((struct ipa_msg_meta *)header)->msg_len;
- pyld_sz = sizeof(struct ipa_msg_meta) +
- pre_entry;
- param = kzalloc(pyld_sz, GFP_KERNEL);
- if (!param) {
- retval = -ENOMEM;
- break;
- }
- if (copy_from_user(param, (u8 *)arg, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- /* add check in case user-space module compromised */
- if (unlikely(((struct ipa_msg_meta *)param)->msg_len
- != pre_entry)) {
- IPAERR("current %d pre %d\n",
- ((struct ipa_msg_meta *)param)->msg_len,
- pre_entry);
- retval = -EFAULT;
- break;
- }
- if (ipa_pull_msg((struct ipa_msg_meta *)param,
- (char *)param + sizeof(struct ipa_msg_meta),
- ((struct ipa_msg_meta *)param)->msg_len) !=
- ((struct ipa_msg_meta *)param)->msg_len) {
- retval = -1;
- break;
- }
- if (copy_to_user((u8 *)arg, param, pyld_sz)) {
- retval = -EFAULT;
- break;
- }
- break;
- case IPA_IOC_RM_ADD_DEPENDENCY:
- if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
- sizeof(struct ipa_ioc_rm_dependency))) {
- retval = -EFAULT;
- break;
- }
- retval = ipa_rm_add_dependency(rm_depend.resource_name,
- rm_depend.depends_on_name);
- break;
- case IPA_IOC_RM_DEL_DEPENDENCY:
- if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
- sizeof(struct ipa_ioc_rm_dependency))) {
- retval = -EFAULT;
- break;
- }
- retval = ipa_rm_delete_dependency(rm_depend.resource_name,
- rm_depend.depends_on_name);
- break;
- default: /* redundant, as cmd was checked against MAXNR */
- ipa_dec_client_disable_clks();
- return -ENOTTY;
- }
- kfree(param);
- ipa_dec_client_disable_clks();
- return retval;
- }
- /**
- * ipa_setup_dflt_rt_tables() - Setup default routing tables
- *
- * Return codes:
- * 0: success
- * -ENOMEM: failed to allocate memory
- * -EPERM: failed to add the tables
- */
- int ipa_setup_dflt_rt_tables(void)
- {
- struct ipa_ioc_add_rt_rule *rt_rule;
- struct ipa_rt_rule_add *rt_rule_entry;
- rt_rule =
- kzalloc(sizeof(struct ipa_ioc_add_rt_rule) + 1 *
- sizeof(struct ipa_rt_rule_add), GFP_KERNEL);
- if (!rt_rule) {
- IPAERR("fail to alloc mem\n");
- return -ENOMEM;
- }
- /* setup a default v4 route to point to A5 */
- rt_rule->num_rules = 1;
- rt_rule->commit = 1;
- rt_rule->ip = IPA_IP_v4;
- strlcpy(rt_rule->rt_tbl_name, IPA_DFLT_RT_TBL_NAME,
- IPA_RESOURCE_NAME_MAX);
- rt_rule_entry = &rt_rule->rules[0];
- rt_rule_entry->at_rear = 1;
- rt_rule_entry->rule.dst = IPA_CLIENT_A5_LAN_WAN_CONS;
- rt_rule_entry->rule.hdr_hdl = ipa_ctx->excp_hdr_hdl;
- if (ipa_add_rt_rule(rt_rule)) {
- IPAERR("fail to add dflt v4 rule\n");
- kfree(rt_rule);
- return -EPERM;
- }
- IPADBG("dflt v4 rt rule hdl=%x\n", rt_rule_entry->rt_rule_hdl);
- ipa_ctx->dflt_v4_rt_rule_hdl = rt_rule_entry->rt_rule_hdl;
- /* setup a default v6 route to point to A5 */
- rt_rule->ip = IPA_IP_v6;
- if (ipa_add_rt_rule(rt_rule)) {
- IPAERR("fail to add dflt v6 rule\n");
- kfree(rt_rule);
- return -EPERM;
- }
- IPADBG("dflt v6 rt rule hdl=%x\n", rt_rule_entry->rt_rule_hdl);
- ipa_ctx->dflt_v6_rt_rule_hdl = rt_rule_entry->rt_rule_hdl;
- /*
- * because these tables are the very first to be added, they will both
- * have the same index (0) which is essential for programming the
- * "route" end-point config
- */
- kfree(rt_rule);
- return 0;
- }
- static int ipa_setup_exception_path(void)
- {
- struct ipa_ioc_add_hdr *hdr;
- struct ipa_hdr_add *hdr_entry;
- struct ipa_route route = { 0 };
- int ret;
- /* install the basic exception header */
- hdr = kzalloc(sizeof(struct ipa_ioc_add_hdr) + 1 *
- sizeof(struct ipa_hdr_add), GFP_KERNEL);
- if (!hdr) {
- IPAERR("fail to alloc exception hdr\n");
- return -ENOMEM;
- }
- hdr->num_hdrs = 1;
- hdr->commit = 1;
- hdr_entry = &hdr->hdr[0];
- strlcpy(hdr_entry->name, IPA_DFLT_HDR_NAME, IPA_RESOURCE_NAME_MAX);
- /*
- * only single stream for MBIM supported and no exception packets
- * expected so set default header to zero
- * for IPA HW 1.1 and up the default header length is 8 (exception)
- */
- if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
- hdr_entry->hdr_len = 1;
- hdr_entry->hdr[0] = 0;
- } else {
- hdr_entry->hdr_len = IPA_DEFAULT_HEADER_LENGTH;
- }
- /*
- * SW does not know anything about default exception header so
- * we don't set it. IPA HW will use it as a template
- */
- if (ipa_add_hdr(hdr)) {
- IPAERR("fail to add exception hdr\n");
- ret = -EPERM;
- goto bail;
- }
- if (hdr_entry->status) {
- IPAERR("fail to add exception hdr\n");
- ret = -EPERM;
- goto bail;
- }
- ipa_ctx->excp_hdr_hdl = hdr_entry->hdr_hdl;
- /* exception packets goto LAN-WAN pipe from IPA to A5 */
- route.route_def_pipe = IPA_A5_LAN_WAN_IN;
- route.route_def_hdr_table = !ipa_ctx->hdr_tbl_lcl;
- if (ipa_cfg_route(&route)) {
- IPAERR("fail to add exception hdr\n");
- ret = -EPERM;
- goto bail;
- }
- ret = 0;
- bail:
- kfree(hdr);
- return ret;
- }
- static void ipa_poll_function(struct work_struct *work)
- {
- int ret;
- int tx_pipes[] = { IPA_A5_CMD, IPA_A5_LAN_WAN_OUT,
- IPA_A5_WLAN_AMPDU_OUT };
- int i;
- int num_tx_pipes;
- int cnt;
- num_tx_pipes = sizeof(tx_pipes) / sizeof(tx_pipes[0]);
- if (!IPA_MOBILE_AP_MODE(ipa_ctx->mode))
- num_tx_pipes--;
- do {
- cnt = 0;
- /* check all the system pipes for tx comp and rx avail */
- if (ipa_ctx->sys[IPA_A5_LAN_WAN_IN].ep->valid)
- cnt |= ipa_handle_rx_core(
- &ipa_ctx->sys[IPA_A5_LAN_WAN_IN],
- false, true);
- for (i = 0; i < num_tx_pipes; i++)
- if (ipa_ctx->sys[tx_pipes[i]].ep->valid)
- cnt |= ipa_handle_tx_core(
- &ipa_ctx->sys[tx_pipes[i]],
- false, true);
- } while (cnt);
- /* re-post the poll work */
- INIT_DELAYED_WORK(&ipa_ctx->poll_work, ipa_poll_function);
- ret = schedule_delayed_work_on(smp_processor_id(), &ipa_ctx->poll_work,
- msecs_to_jiffies(polling_delay_ms));
- return;
- }
- static int ipa_setup_a5_pipes(void)
- {
- struct ipa_sys_connect_params sys_in;
- int result = 0;
- /* CMD OUT (A5->IPA) */
- memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
- sys_in.client = IPA_CLIENT_A5_CMD_PROD;
- sys_in.desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
- sys_in.ipa_ep_cfg.mode.mode = IPA_DMA;
- sys_in.ipa_ep_cfg.mode.dst = IPA_CLIENT_A5_LAN_WAN_CONS;
- if (ipa_setup_sys_pipe(&sys_in, &ipa_ctx->clnt_hdl_cmd)) {
- IPAERR(":setup sys pipe failed.\n");
- result = -EPERM;
- goto fail_cmd;
- }
- /* Start polling, only if needed */
- if (ipa_ctx->polling_mode) {
- INIT_DELAYED_WORK(&ipa_ctx->poll_work, ipa_poll_function);
- result =
- schedule_delayed_work_on(smp_processor_id(),
- &ipa_ctx->poll_work,
- msecs_to_jiffies(polling_delay_ms));
- if (!result) {
- IPAERR(":schedule delayed work failed.\n");
- goto fail_schedule_delayed_work;
- }
- }
- if (ipa_setup_exception_path()) {
- IPAERR(":fail to setup excp path\n");
- result = -EPERM;
- goto fail_schedule_delayed_work;
- }
- if (ipa_ctx->ipa_hw_type != IPA_HW_v1_0) {
- if (ipa_setup_dflt_rt_tables()) {
- IPAERR(":fail to setup dflt routes\n");
- result = -EPERM;
- goto fail_schedule_delayed_work;
- }
- }
- /* LAN-WAN IN (IPA->A5) */
- memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
- sys_in.client = IPA_CLIENT_A5_LAN_WAN_CONS;
- sys_in.desc_fifo_sz = IPA_SYS_DESC_FIFO_SZ;
- sys_in.ipa_ep_cfg.hdr.hdr_a5_mux = 1;
- sys_in.ipa_ep_cfg.hdr.hdr_len = 8; /* size of A5 exception hdr */
- if (ipa_setup_sys_pipe(&sys_in, &ipa_ctx->clnt_hdl_data_in)) {
- IPAERR(":setup sys pipe failed.\n");
- result = -EPERM;
- goto fail_schedule_delayed_work;
- }
- /* LAN-WAN OUT (A5->IPA) */
- memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
- sys_in.client = IPA_CLIENT_A5_LAN_WAN_PROD;
- sys_in.desc_fifo_sz = IPA_SYS_TX_DATA_DESC_FIFO_SZ;
- sys_in.ipa_ep_cfg.mode.mode = IPA_BASIC;
- sys_in.ipa_ep_cfg.mode.dst = IPA_CLIENT_A5_LAN_WAN_CONS;
- if (ipa_setup_sys_pipe(&sys_in, &ipa_ctx->clnt_hdl_data_out)) {
- IPAERR(":setup sys pipe failed.\n");
- result = -EPERM;
- goto fail_data_out;
- }
- return 0;
- fail_data_out:
- ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_data_in);
- fail_schedule_delayed_work:
- if (ipa_ctx->dflt_v6_rt_rule_hdl)
- __ipa_del_rt_rule(ipa_ctx->dflt_v6_rt_rule_hdl);
- if (ipa_ctx->dflt_v4_rt_rule_hdl)
- __ipa_del_rt_rule(ipa_ctx->dflt_v4_rt_rule_hdl);
- if (ipa_ctx->excp_hdr_hdl)
- __ipa_del_hdr(ipa_ctx->excp_hdr_hdl, false);
- ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_cmd);
- fail_cmd:
- return result;
- }
- static void ipa_teardown_a5_pipes(void)
- {
- cancel_delayed_work(&ipa_ctx->poll_work);
- ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_data_out);
- ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_data_in);
- __ipa_del_rt_rule(ipa_ctx->dflt_v6_rt_rule_hdl);
- __ipa_del_rt_rule(ipa_ctx->dflt_v4_rt_rule_hdl);
- __ipa_del_hdr(ipa_ctx->excp_hdr_hdl, false);
- ipa_teardown_sys_pipe(ipa_ctx->clnt_hdl_cmd);
- }
- static int ipa_load_pipe_connection(struct platform_device *pdev,
- enum a2_mux_pipe_direction pipe_dir,
- struct a2_mux_pipe_connection *pdata)
- {
- struct device_node *node = pdev->dev.of_node;
- int rc = 0;
- if (!pdata || !pdev)
- goto err;
- /* retrieve device tree parameters */
- for_each_child_of_node(pdev->dev.of_node, node)
- {
- const char *str;
- rc = of_property_read_string(node, "label", &str);
- if (rc) {
- IPAERR("Cannot read string\n");
- goto err;
- }
- /* Check if connection type is supported */
- if (strncmp(str, "a2-to-ipa", 10)
- && strncmp(str, "ipa-to-a2", 10))
- goto err;
- if (strnstr(str, "a2-to-ipa", strnlen("a2-to-ipa", 10))
- && IPA_TO_A2 == pipe_dir)
- continue; /* skip to the next pipe */
- else if (strnstr(str, "ipa-to-a2", strnlen("ipa-to-a2", 10))
- && A2_TO_IPA == pipe_dir)
- continue; /* skip to the next pipe */
- rc = ipa_update_connections_info(node, pdata);
- if (rc)
- goto err;
- }
- return 0;
- err:
- IPAERR("%s: failed\n", __func__);
- return rc;
- }
- static int ipa_update_connections_info(struct device_node *node,
- struct a2_mux_pipe_connection *pipe_connection)
- {
- u32 rc;
- char *key;
- uint32_t val;
- enum ipa_pipe_mem_type mem_type;
- if (!pipe_connection || !node)
- return -EINVAL;
- key = "qcom,src-bam-physical-address";
- rc = of_property_read_u32(node, key, &val);
- if (rc)
- goto err;
- pipe_connection->src_phy_addr = val;
- key = "qcom,ipa-bam-mem-type";
- rc = of_property_read_u32(node, key, &mem_type);
- if (rc)
- goto err;
- pipe_connection->mem_type = mem_type;
- key = "qcom,src-bam-pipe-index";
- rc = of_property_read_u32(node, key, &val);
- if (rc)
- goto err;
- pipe_connection->src_pipe_index = val;
- key = "qcom,dst-bam-physical-address";
- rc = of_property_read_u32(node, key, &val);
- if (rc)
- goto err;
- pipe_connection->dst_phy_addr = val;
- key = "qcom,dst-bam-pipe-index";
- rc = of_property_read_u32(node, key, &val);
- if (rc)
- goto err;
- pipe_connection->dst_pipe_index = val;
- key = "qcom,data-fifo-offset";
- rc = of_property_read_u32(node, key, &val);
- if (rc)
- goto err;
- pipe_connection->data_fifo_base_offset = val;
- key = "qcom,data-fifo-size";
- rc = of_property_read_u32(node, key, &val);
- if (rc)
- goto err;
- pipe_connection->data_fifo_size = val;
- key = "qcom,descriptor-fifo-offset";
- rc = of_property_read_u32(node, key, &val);
- if (rc)
- goto err;
- pipe_connection->desc_fifo_base_offset = val;
- key = "qcom,descriptor-fifo-size";
- rc = of_property_read_u32(node, key, &val);
- if (rc)
- goto err;
- pipe_connection->desc_fifo_size = val;
- return 0;
- err:
- IPAERR("%s: Error in name %s key %s\n", __func__, node->full_name, key);
- return rc;
- }
- /**
- * ipa_get_a2_mux_pipe_info() - Exposes A2 parameters fetched from DTS
- *
- * @pipe_dir: pipe direction
- * @pipe_connect: connect structure containing the parameters fetched from DTS
- *
- * Return codes:
- * 0: success
- * -EFAULT: invalid parameters
- */
- int ipa_get_a2_mux_pipe_info(enum a2_mux_pipe_direction pipe_dir,
- struct a2_mux_pipe_connection *pipe_connect)
- {
- if (!pipe_connect) {
- IPAERR("ipa_get_a2_mux_pipe_info switch null args\n");
- return -EFAULT;
- }
- switch (pipe_dir) {
- case A2_TO_IPA:
- *pipe_connect = ipa_res.a2_to_ipa_pipe;
- break;
- case IPA_TO_A2:
- *pipe_connect = ipa_res.ipa_to_a2_pipe;
- break;
- default:
- IPAERR("ipa_get_a2_mux_pipe_info switch in default\n");
- return -EFAULT;
- }
- return 0;
- }
- /**
- * ipa_get_a2_mux_bam_info() - Exposes A2 parameters fetched from
- * DTS
- *
- * @a2_bam_mem_base: A2 BAM Memory base
- * @a2_bam_mem_size: A2 BAM Memory size
- * @a2_bam_irq: A2 BAM IRQ
- *
- * Return codes:
- * 0: success
- * -EFAULT: invalid parameters
- */
- int ipa_get_a2_mux_bam_info(u32 *a2_bam_mem_base, u32 *a2_bam_mem_size,
- u32 *a2_bam_irq)
- {
- if (!a2_bam_mem_base || !a2_bam_mem_size || !a2_bam_irq) {
- IPAERR("ipa_get_a2_mux_bam_info null args\n");
- return -EFAULT;
- }
- *a2_bam_mem_base = ipa_res.a2_bam_mem_base;
- *a2_bam_mem_size = ipa_res.a2_bam_mem_size;
- *a2_bam_irq = ipa_res.a2_bam_irq;
- return 0;
- }
- static void ipa_set_aggregation_params(void)
- {
- struct ipa_ep_cfg_aggr agg_params;
- struct ipa_ep_cfg_hdr hdr_params;
- u32 producer_hdl = 0;
- u32 consumer_hdl = 0;
- teth_bridge_get_client_handles(&producer_hdl, &consumer_hdl);
- /* configure aggregation on producer */
- memset(&agg_params, 0, sizeof(struct ipa_ep_cfg_aggr));
- agg_params.aggr_en = IPA_ENABLE_AGGR;
- agg_params.aggr = ipa_ctx->aggregation_type;
- agg_params.aggr_byte_limit = ipa_ctx->aggregation_byte_limit;
- agg_params.aggr_time_limit = ipa_ctx->aggregation_time_limit;
- ipa_cfg_ep_aggr(producer_hdl, &agg_params);
- if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
- /* configure header on producer */
- memset(&hdr_params, 0, sizeof(struct ipa_ep_cfg_hdr));
- hdr_params.hdr_len = 1;
- ipa_cfg_ep_hdr(producer_hdl, &hdr_params);
- }
- /* configure deaggregation on consumer */
- memset(&agg_params, 0, sizeof(struct ipa_ep_cfg_aggr));
- agg_params.aggr_en = IPA_ENABLE_DEAGGR;
- agg_params.aggr = ipa_ctx->aggregation_type;
- ipa_cfg_ep_aggr(consumer_hdl, &agg_params);
- }
- /*
- * The following device attributes are for configuring the aggregation
- * attributes when the driver is already running.
- * The attributes are for configuring the aggregation type
- * (MBIM_16/MBIM_32/TLP), the aggregation byte limit and the aggregation
- * time limit.
- */
- static ssize_t ipa_show_aggregation_type(struct device *dev,
- struct device_attribute *attr,
- char *buf)
- {
- ssize_t ret_val;
- char str[IPA_AGGR_MAX_STR_LENGTH];
- if (!buf) {
- IPAERR("buffer for ipa_show_aggregation_type is NULL\n");
- return -EINVAL;
- }
- memset(str, 0, sizeof(str));
- switch (ipa_ctx->aggregation_type) {
- case IPA_MBIM_16:
- strlcpy(str, "MBIM_16", IPA_AGGR_STR_IN_BYTES("MBIM_16"));
- break;
- case IPA_MBIM_32:
- strlcpy(str, "MBIM_32", IPA_AGGR_STR_IN_BYTES("MBIM_32"));
- break;
- case IPA_TLP:
- strlcpy(str, "TLP", IPA_AGGR_STR_IN_BYTES("TLP"));
- break;
- default:
- strlcpy(str, "NONE", IPA_AGGR_STR_IN_BYTES("NONE"));
- break;
- }
- ret_val = scnprintf(buf, PAGE_SIZE, "%s\n", str);
- return ret_val;
- }
- static ssize_t ipa_store_aggregation_type(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- char str[IPA_AGGR_MAX_STR_LENGTH], *pstr;
- if (!buf) {
- IPAERR("buffer for ipa_store_aggregation_type is NULL\n");
- return -EINVAL;
- }
- strlcpy(str, buf, sizeof(str));
- pstr = strim(str);
- if (!strncmp(pstr, "MBIM_16", IPA_AGGR_STR_IN_BYTES("MBIM_16")))
- ipa_ctx->aggregation_type = IPA_MBIM_16;
- else if (!strncmp(pstr, "MBIM_32", IPA_AGGR_STR_IN_BYTES("MBIM_32")))
- ipa_ctx->aggregation_type = IPA_MBIM_32;
- else if (!strncmp(pstr, "TLP", IPA_AGGR_STR_IN_BYTES("TLP")))
- ipa_ctx->aggregation_type = IPA_TLP;
- else {
- IPAERR("ipa_store_aggregation_type wrong input\n");
- return -EINVAL;
- }
- ipa_set_aggregation_params();
- return count;
- }
- static DEVICE_ATTR(aggregation_type, S_IWUSR | S_IRUSR,
- ipa_show_aggregation_type,
- ipa_store_aggregation_type);
- static ssize_t ipa_show_aggregation_byte_limit(struct device *dev,
- struct device_attribute *attr,
- char *buf)
- {
- ssize_t ret_val;
- if (!buf) {
- IPAERR("buffer for ipa_show_aggregation_byte_limit is NULL\n");
- return -EINVAL;
- }
- ret_val = scnprintf(buf, PAGE_SIZE, "%u\n",
- ipa_ctx->aggregation_byte_limit);
- return ret_val;
- }
- static ssize_t ipa_store_aggregation_byte_limit(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- char str[IPA_AGGR_MAX_STR_LENGTH];
- char *pstr;
- u32 ret = 0;
- if (!buf) {
- IPAERR("buffer for ipa_store_aggregation_byte_limit is NULL\n");
- return -EINVAL;
- }
- strlcpy(str, buf, sizeof(str));
- pstr = strim(str);
- if (kstrtouint(pstr, IPA_AGGR_MAX_STR_LENGTH, &ret)) {
- IPAERR("ipa_store_aggregation_byte_limit wrong input\n");
- return -EINVAL;
- }
- ipa_ctx->aggregation_byte_limit = ret;
- ipa_set_aggregation_params();
- return count;
- }
- static DEVICE_ATTR(aggregation_byte_limit, S_IWUSR | S_IRUSR,
- ipa_show_aggregation_byte_limit,
- ipa_store_aggregation_byte_limit);
- static ssize_t ipa_show_aggregation_time_limit(struct device *dev,
- struct device_attribute *attr,
- char *buf)
- {
- ssize_t ret_val;
- if (!buf) {
- IPAERR("buffer for ipa_show_aggregation_time_limit is NULL\n");
- return -EINVAL;
- }
- ret_val = scnprintf(buf,
- PAGE_SIZE,
- "%u\n",
- ipa_ctx->aggregation_time_limit);
- return ret_val;
- }
- static ssize_t ipa_store_aggregation_time_limit(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- char str[IPA_AGGR_MAX_STR_LENGTH], *pstr;
- u32 ret = 0;
- if (!buf) {
- IPAERR("buffer for ipa_store_aggregation_time_limit is NULL\n");
- return -EINVAL;
- }
- strlcpy(str, buf, sizeof(str));
- pstr = strim(str);
- if (kstrtouint(pstr, IPA_AGGR_MAX_STR_LENGTH, &ret)) {
- IPAERR("ipa_store_aggregation_time_limit wrong input\n");
- return -EINVAL;
- }
- ipa_ctx->aggregation_time_limit = ret;
- ipa_set_aggregation_params();
- return count;
- }
- static DEVICE_ATTR(aggregation_time_limit, S_IWUSR | S_IRUSR,
- ipa_show_aggregation_time_limit,
- ipa_store_aggregation_time_limit);
- static const struct file_operations ipa_drv_fops = {
- .owner = THIS_MODULE,
- .open = ipa_open,
- .read = ipa_read,
- .unlocked_ioctl = ipa_ioctl,
- };
- static int ipa_get_clks(struct device *dev)
- {
- ipa_cnoc_clk = clk_get(dev, "iface_clk");
- if (IS_ERR(ipa_cnoc_clk)) {
- ipa_cnoc_clk = NULL;
- IPAERR("fail to get cnoc clk\n");
- return -ENODEV;
- }
- ipa_clk_src = clk_get(dev, "core_src_clk");
- if (IS_ERR(ipa_clk_src)) {
- ipa_clk_src = NULL;
- IPAERR("fail to get ipa clk src\n");
- return -ENODEV;
- }
- ipa_clk = clk_get(dev, "core_clk");
- if (IS_ERR(ipa_clk)) {
- ipa_clk = NULL;
- IPAERR("fail to get ipa clk\n");
- return -ENODEV;
- }
- sys_noc_ipa_axi_clk = clk_get(dev, "bus_clk");
- if (IS_ERR(sys_noc_ipa_axi_clk)) {
- sys_noc_ipa_axi_clk = NULL;
- IPAERR("fail to get sys_noc_ipa_axi clk\n");
- return -ENODEV;
- }
- ipa_inactivity_clk = clk_get(dev, "inactivity_clk");
- if (IS_ERR(ipa_inactivity_clk)) {
- ipa_inactivity_clk = NULL;
- IPAERR("fail to get inactivity clk\n");
- return -ENODEV;
- }
- return 0;
- }
- /**
- * ipa_enable_clks() - Turn on IPA clocks
- *
- * Return codes:
- * None
- */
- void ipa_enable_clks(void)
- {
- if (ipa_cnoc_clk) {
- clk_prepare(ipa_cnoc_clk);
- clk_enable(ipa_cnoc_clk);
- clk_set_rate(ipa_cnoc_clk, IPA_CNOC_CLK_RATE);
- } else {
- WARN_ON(1);
- }
- if (ipa_clk_src)
- if (ipa_res.ipa_hw_type == IPA_HW_v1_0)
- clk_set_rate(ipa_clk_src, IPA_V1_CLK_RATE);
- else if (ipa_res.ipa_hw_type == IPA_HW_v1_1)
- clk_set_rate(ipa_clk_src, IPA_V1_1_CLK_RATE);
- else
- WARN_ON(1);
- else
- WARN_ON(1);
- if (ipa_clk)
- clk_prepare(ipa_clk);
- else
- WARN_ON(1);
- if (sys_noc_ipa_axi_clk)
- clk_prepare(sys_noc_ipa_axi_clk);
- else
- WARN_ON(1);
- if (ipa_inactivity_clk)
- clk_prepare(ipa_inactivity_clk);
- else
- WARN_ON(1);
- if (ipa_clk)
- clk_enable(ipa_clk);
- else
- WARN_ON(1);
- if (sys_noc_ipa_axi_clk)
- clk_enable(sys_noc_ipa_axi_clk);
- else
- WARN_ON(1);
- if (ipa_inactivity_clk)
- clk_enable(ipa_inactivity_clk);
- else
- WARN_ON(1);
- if (msm_bus_scale_client_update_request(ipa_bus_hdl, 1))
- WARN_ON(1);
- }
- /**
- * ipa_disable_clks() - Turn off IPA clocks
- *
- * Return codes:
- * None
- */
- void ipa_disable_clks(void)
- {
- if (ipa_inactivity_clk)
- clk_disable_unprepare(ipa_inactivity_clk);
- else
- WARN_ON(1);
- if (sys_noc_ipa_axi_clk)
- clk_disable_unprepare(sys_noc_ipa_axi_clk);
- else
- WARN_ON(1);
- if (ipa_clk)
- clk_disable_unprepare(ipa_clk);
- else
- WARN_ON(1);
- if (ipa_cnoc_clk)
- clk_disable_unprepare(ipa_cnoc_clk);
- else
- WARN_ON(1);
- if (msm_bus_scale_client_update_request(ipa_bus_hdl, 0))
- WARN_ON(1);
- }
- /**
- * ipa_inc_client_enable_clks() - Increase active clients counter, and
- * enable ipa clocks if necessary
- *
- * Return codes:
- * None
- */
- void ipa_inc_client_enable_clks(void)
- {
- mutex_lock(&ipa_ctx->ipa_active_clients_lock);
- ipa_ctx->ipa_active_clients++;
- if (ipa_ctx->ipa_active_clients == 1)
- if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
- ipa_enable_clks();
- mutex_unlock(&ipa_ctx->ipa_active_clients_lock);
- }
- /**
- * ipa_dec_client_disable_clks() - Decrease active clients counter, and
- * disable ipa clocks if necessary
- *
- * Return codes:
- * None
- */
- void ipa_dec_client_disable_clks(void)
- {
- mutex_lock(&ipa_ctx->ipa_active_clients_lock);
- ipa_ctx->ipa_active_clients--;
- if (ipa_ctx->ipa_active_clients == 0)
- if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
- ipa_disable_clks();
- mutex_unlock(&ipa_ctx->ipa_active_clients_lock);
- }
- static int ipa_setup_bam_cfg(const struct ipa_plat_drv_res *res)
- {
- void *bam_cnfg_bits;
- if ((ipa_ctx->ipa_hw_type == IPA_HW_v1_0) ||
- (ipa_ctx->ipa_hw_type == IPA_HW_v1_1)) {
- bam_cnfg_bits = ioremap(res->ipa_mem_base +
- IPA_BAM_REG_BASE_OFST,
- IPA_BAM_REMAP_SIZE);
- if (!bam_cnfg_bits)
- return -ENOMEM;
- ipa_write_reg(bam_cnfg_bits, IPA_BAM_CNFG_BITS_OFST,
- IPA_BAM_CNFG_BITS_VAL);
- iounmap(bam_cnfg_bits);
- }
- return 0;
- }
- static int ipa_init_flt_block(void)
- {
- int result = 0;
- /*
- * SW workaround for Improper Filter Behaviour when neiher Global nor
- * Pipe Rules are present => configure dummy global filter rule
- * always which results in a miss
- */
- struct ipa_ioc_add_flt_rule *rules;
- struct ipa_flt_rule_add *rule;
- struct ipa_ioc_get_rt_tbl rt_lookup;
- enum ipa_ip_type ip;
- if (ipa_ctx->ipa_hw_type == IPA_HW_v1_1) {
- size_t sz = sizeof(struct ipa_ioc_add_flt_rule) +
- sizeof(struct ipa_flt_rule_add);
- rules = kmalloc(sz, GFP_KERNEL);
- if (rules == NULL) {
- IPAERR("fail to alloc mem for dummy filter rule\n");
- return -ENOMEM;
- }
- for (ip = IPA_IP_v4; ip < IPA_IP_MAX; ip++) {
- memset(&rt_lookup, 0,
- sizeof(struct ipa_ioc_get_rt_tbl));
- rt_lookup.ip = ip;
- strlcpy(rt_lookup.name, IPA_DFLT_RT_TBL_NAME,
- IPA_RESOURCE_NAME_MAX);
- ipa_get_rt_tbl(&rt_lookup);
- ipa_put_rt_tbl(rt_lookup.hdl);
- memset(rules, 0, sz);
- rule = &rules->rules[0];
- rules->commit = 1;
- rules->ip = ip;
- rules->global = 1;
- rules->num_rules = 1;
- rule->at_rear = 1;
- if (ip == IPA_IP_v4) {
- rule->rule.attrib.attrib_mask =
- IPA_FLT_PROTOCOL;
- rule->rule.attrib.u.v4.protocol =
- IPA_INVALID_L4_PROTOCOL;
- } else if (ip == IPA_IP_v6) {
- rule->rule.attrib.attrib_mask =
- IPA_FLT_NEXT_HDR;
- rule->rule.attrib.u.v6.next_hdr =
- IPA_INVALID_L4_PROTOCOL;
- } else {
- result = -EINVAL;
- WARN_ON(1);
- break;
- }
- rule->rule.action = IPA_PASS_TO_ROUTING;
- rule->rule.rt_tbl_hdl = rt_lookup.hdl;
- if (ipa_add_flt_rule(rules) || rules->rules[0].status) {
- result = -EINVAL;
- WARN_ON(1);
- break;
- }
- }
- kfree(rules);
- }
- return result;
- }
- /**
- * ipa_init() - Initialize the IPA Driver
- *@resource_p: contain platform specific values from DST file
- *
- * Function initialization process:
- * - Allocate memory for the driver context data struct
- * - Initializing the ipa_ctx with:
- * 1)parsed values from the dts file
- * 2)parameters passed to the module initialization
- * 3)read HW values(such as core memory size)
- * - Map IPA core registers to CPU memory
- * - Restart IPA core(HW reset)
- * - Register IPA BAM to SPS driver and get a BAM handler
- * - Set configuration for IPA BAM via BAM_CNFG_BITS
- * - Initialize the look-aside caches(kmem_cache/slab) for filter,
- * routing and IPA-tree
- * - Create memory pool with 4 objects for DMA operations(each object
- * is 512Bytes long), this object will be use for tx(A5->IPA)
- * - Initialize lists head(routing,filter,hdr,system pipes)
- * - Initialize mutexes (for ipa_ctx and NAT memory mutexes)
- * - Initialize spinlocks (for list related to A5<->IPA pipes)
- * - Initialize 2 single-threaded work-queue named "ipa rx wq" and "ipa tx wq"
- * - Initialize Red-Black-Tree(s) for handles of header,routing rule,
- * routing table ,filtering rule
- * - Setup all A5<->IPA pipes by calling to ipa_setup_a5_pipes
- * - Preparing the descriptors for System pipes
- * - Initialize the filter block by committing IPV4 and IPV6 default rules
- * - Create empty routing table in system memory(no committing)
- * - Initialize pipes memory pool with ipa_pipe_mem_init for supported platforms
- * - Create a char-device for IPA
- * - Initialize IPA RM (resource manager)
- */
- static int ipa_init(const struct ipa_plat_drv_res *resource_p)
- {
- int result = 0;
- int i;
- struct sps_bam_props bam_props = { 0 };
- struct ipa_flt_tbl *flt_tbl;
- struct ipa_rt_tbl_set *rset;
- IPADBG("IPA init\n");
- ipa_ctx = kzalloc(sizeof(*ipa_ctx), GFP_KERNEL);
- if (!ipa_ctx) {
- IPAERR(":kzalloc err.\n");
- result = -ENOMEM;
- goto fail_mem;
- }
- IPADBG("polling_mode=%u delay_ms=%u\n", polling_mode, polling_delay_ms);
- ipa_ctx->polling_mode = polling_mode;
- IPADBG("hdr_lcl=%u ip4_rt=%u ip6_rt=%u ip4_flt=%u ip6_flt=%u\n",
- hdr_tbl_lcl, ip4_rt_tbl_lcl, ip6_rt_tbl_lcl, ip4_flt_tbl_lcl,
- ip6_flt_tbl_lcl);
- ipa_ctx->hdr_tbl_lcl = hdr_tbl_lcl;
- ipa_ctx->ip4_rt_tbl_lcl = ip4_rt_tbl_lcl;
- ipa_ctx->ip6_rt_tbl_lcl = ip6_rt_tbl_lcl;
- ipa_ctx->ip4_flt_tbl_lcl = ip4_flt_tbl_lcl;
- ipa_ctx->ip6_flt_tbl_lcl = ip6_flt_tbl_lcl;
- ipa_ctx->ipa_wrapper_base = resource_p->ipa_mem_base;
- ipa_ctx->ipa_hw_type = resource_p->ipa_hw_type;
- ipa_ctx->ipa_hw_mode = resource_p->ipa_hw_mode;
- /* setup IPA register access */
- ipa_ctx->mmio = ioremap(resource_p->ipa_mem_base + IPA_REG_BASE_OFST,
- resource_p->ipa_mem_size);
- if (!ipa_ctx->mmio) {
- IPAERR(":ipa-base ioremap err.\n");
- result = -EFAULT;
- goto fail_remap;
- }
- /* do POR programming to setup HW */
- result = ipa_init_hw();
- if (result) {
- IPAERR(":error initializing driver.\n");
- result = -ENODEV;
- goto fail_init_hw;
- }
- if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
- /* setup chicken bits */
- result = ipa_set_single_ndp_per_mbim(true);
- if (result) {
- IPAERR(":failed to set single ndp per mbim.\n");
- result = -EFAULT;
- goto fail_init_hw;
- }
- result = ipa_set_hw_timer_fix_for_mbim_aggr(true);
- if (result) {
- IPAERR(":failed to set HW timer fix for MBIM agg.\n");
- result = -EFAULT;
- goto fail_init_hw;
- }
- }
- /* read how much SRAM is available for SW use */
- if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0)
- ipa_ctx->smem_sz = ipa_read_reg(ipa_ctx->mmio,
- IPA_SHARED_MEM_SIZE_OFST_v1);
- else
- ipa_ctx->smem_sz = ipa_read_reg(ipa_ctx->mmio,
- IPA_SHARED_MEM_SIZE_OFST_v2);
- if (IPA_RAM_END_OFST > ipa_ctx->smem_sz) {
- IPAERR("SW expect more core memory, needed %d, avail %d\n",
- IPA_RAM_END_OFST, ipa_ctx->smem_sz);
- result = -ENOMEM;
- goto fail_init_hw;
- }
- /* register IPA with SPS driver */
- bam_props.phys_addr = resource_p->bam_mem_base;
- bam_props.virt_size = resource_p->bam_mem_size;
- bam_props.irq = resource_p->bam_irq;
- bam_props.num_pipes = IPA_NUM_PIPES;
- bam_props.summing_threshold = IPA_SUMMING_THRESHOLD;
- bam_props.event_threshold = IPA_EVENT_THRESHOLD;
- bam_props.options |= SPS_BAM_NO_LOCAL_CLK_GATING;
- result = sps_register_bam_device(&bam_props, &ipa_ctx->bam_handle);
- if (result) {
- IPAERR(":bam register err.\n");
- result = -ENODEV;
- goto fail_init_hw;
- }
- if (ipa_setup_bam_cfg(resource_p)) {
- IPAERR(":bam cfg err.\n");
- result = -ENODEV;
- goto fail_flt_rule_cache;
- }
- /* set up the default op mode */
- ipa_ctx->mode = IPA_MODE_MOBILE_AP_WAN;
- /* init the lookaside cache */
- ipa_ctx->flt_rule_cache = kmem_cache_create("IPA FLT",
- sizeof(struct ipa_flt_entry), 0, 0, NULL);
- if (!ipa_ctx->flt_rule_cache) {
- IPAERR(":ipa flt cache create failed\n");
- result = -ENOMEM;
- goto fail_flt_rule_cache;
- }
- ipa_ctx->rt_rule_cache = kmem_cache_create("IPA RT",
- sizeof(struct ipa_rt_entry), 0, 0, NULL);
- if (!ipa_ctx->rt_rule_cache) {
- IPAERR(":ipa rt cache create failed\n");
- result = -ENOMEM;
- goto fail_rt_rule_cache;
- }
- ipa_ctx->hdr_cache = kmem_cache_create("IPA HDR",
- sizeof(struct ipa_hdr_entry), 0, 0, NULL);
- if (!ipa_ctx->hdr_cache) {
- IPAERR(":ipa hdr cache create failed\n");
- result = -ENOMEM;
- goto fail_hdr_cache;
- }
- ipa_ctx->hdr_offset_cache =
- kmem_cache_create("IPA HDR OFF", sizeof(struct ipa_hdr_offset_entry),
- 0, 0, NULL);
- if (!ipa_ctx->hdr_offset_cache) {
- IPAERR(":ipa hdr off cache create failed\n");
- result = -ENOMEM;
- goto fail_hdr_offset_cache;
- }
- ipa_ctx->rt_tbl_cache = kmem_cache_create("IPA RT TBL",
- sizeof(struct ipa_rt_tbl), 0, 0, NULL);
- if (!ipa_ctx->rt_tbl_cache) {
- IPAERR(":ipa rt tbl cache create failed\n");
- result = -ENOMEM;
- goto fail_rt_tbl_cache;
- }
- ipa_ctx->tx_pkt_wrapper_cache =
- kmem_cache_create("IPA TX PKT WRAPPER",
- sizeof(struct ipa_tx_pkt_wrapper), 0, 0, NULL);
- if (!ipa_ctx->tx_pkt_wrapper_cache) {
- IPAERR(":ipa tx pkt wrapper cache create failed\n");
- result = -ENOMEM;
- goto fail_tx_pkt_wrapper_cache;
- }
- ipa_ctx->rx_pkt_wrapper_cache =
- kmem_cache_create("IPA RX PKT WRAPPER",
- sizeof(struct ipa_rx_pkt_wrapper), 0, 0, NULL);
- if (!ipa_ctx->rx_pkt_wrapper_cache) {
- IPAERR(":ipa rx pkt wrapper cache create failed\n");
- result = -ENOMEM;
- goto fail_rx_pkt_wrapper_cache;
- }
- ipa_ctx->tree_node_cache =
- kmem_cache_create("IPA TREE", sizeof(struct ipa_tree_node), 0, 0,
- NULL);
- if (!ipa_ctx->tree_node_cache) {
- IPAERR(":ipa tree node cache create failed\n");
- result = -ENOMEM;
- goto fail_tree_node_cache;
- }
- /*
- * setup DMA pool 4 byte aligned, don't cross 1k boundaries, nominal
- * size 512 bytes
- * This is an issue with IPA HW v1.0 only.
- */
- if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0) {
- ipa_ctx->dma_pool = dma_pool_create("ipa_1k",
- NULL,
- IPA_DMA_POOL_SIZE, IPA_DMA_POOL_ALIGNMENT,
- IPA_DMA_POOL_BOUNDARY);
- } else {
- ipa_ctx->dma_pool = dma_pool_create("ipa_tx", NULL,
- IPA_NUM_DESC_PER_SW_TX * sizeof(struct sps_iovec),
- 0, 0);
- }
- if (!ipa_ctx->dma_pool) {
- IPAERR("cannot alloc DMA pool.\n");
- result = -ENOMEM;
- goto fail_dma_pool;
- }
- ipa_ctx->glob_flt_tbl[IPA_IP_v4].in_sys = !ipa_ctx->ip4_flt_tbl_lcl;
- ipa_ctx->glob_flt_tbl[IPA_IP_v6].in_sys = !ipa_ctx->ip6_flt_tbl_lcl;
- /* init the various list heads */
- INIT_LIST_HEAD(&ipa_ctx->glob_flt_tbl[IPA_IP_v4].head_flt_rule_list);
- INIT_LIST_HEAD(&ipa_ctx->glob_flt_tbl[IPA_IP_v6].head_flt_rule_list);
- INIT_LIST_HEAD(&ipa_ctx->hdr_tbl.head_hdr_entry_list);
- for (i = 0; i < IPA_HDR_BIN_MAX; i++) {
- INIT_LIST_HEAD(&ipa_ctx->hdr_tbl.head_offset_list[i]);
- INIT_LIST_HEAD(&ipa_ctx->hdr_tbl.head_free_offset_list[i]);
- }
- INIT_LIST_HEAD(&ipa_ctx->rt_tbl_set[IPA_IP_v4].head_rt_tbl_list);
- INIT_LIST_HEAD(&ipa_ctx->rt_tbl_set[IPA_IP_v6].head_rt_tbl_list);
- for (i = 0; i < IPA_NUM_PIPES; i++) {
- flt_tbl = &ipa_ctx->flt_tbl[i][IPA_IP_v4];
- INIT_LIST_HEAD(&flt_tbl->head_flt_rule_list);
- flt_tbl->in_sys = !ipa_ctx->ip4_flt_tbl_lcl;
- flt_tbl = &ipa_ctx->flt_tbl[i][IPA_IP_v6];
- INIT_LIST_HEAD(&flt_tbl->head_flt_rule_list);
- flt_tbl->in_sys = !ipa_ctx->ip6_flt_tbl_lcl;
- }
- rset = &ipa_ctx->reap_rt_tbl_set[IPA_IP_v4];
- INIT_LIST_HEAD(&rset->head_rt_tbl_list);
- rset = &ipa_ctx->reap_rt_tbl_set[IPA_IP_v6];
- INIT_LIST_HEAD(&rset->head_rt_tbl_list);
- INIT_LIST_HEAD(&ipa_ctx->intf_list);
- INIT_LIST_HEAD(&ipa_ctx->msg_list);
- INIT_LIST_HEAD(&ipa_ctx->pull_msg_list);
- init_waitqueue_head(&ipa_ctx->msg_waitq);
- mutex_init(&ipa_ctx->msg_lock);
- mutex_init(&ipa_ctx->lock);
- mutex_init(&ipa_ctx->nat_mem.lock);
- for (i = 0; i < IPA_A5_SYS_MAX; i++) {
- INIT_LIST_HEAD(&ipa_ctx->sys[i].head_desc_list);
- spin_lock_init(&ipa_ctx->sys[i].spinlock);
- if (i != IPA_A5_WLAN_AMPDU_OUT)
- ipa_ctx->sys[i].ep = &ipa_ctx->ep[i];
- else
- ipa_ctx->sys[i].ep = &ipa_ctx->ep[WLAN_AMPDU_TX_EP];
- if (ipa_ctx->polling_mode)
- atomic_set(&ipa_ctx->sys[i].curr_polling_state, 1);
- else
- atomic_set(&ipa_ctx->sys[i].curr_polling_state, 0);
- }
- ipa_ctx->rx_wq = create_singlethread_workqueue("ipa rx wq");
- if (!ipa_ctx->rx_wq) {
- IPAERR(":fail to create rx wq\n");
- result = -ENOMEM;
- goto fail_rx_wq;
- }
- ipa_ctx->tx_wq = alloc_workqueue("ipa tx wq", WQ_MEM_RECLAIM |
- WQ_CPU_INTENSIVE, 1);
- if (!ipa_ctx->tx_wq) {
- IPAERR(":fail to create tx wq\n");
- result = -ENOMEM;
- goto fail_tx_wq;
- }
- ipa_ctx->hdr_hdl_tree = RB_ROOT;
- ipa_ctx->rt_rule_hdl_tree = RB_ROOT;
- ipa_ctx->rt_tbl_hdl_tree = RB_ROOT;
- ipa_ctx->flt_rule_hdl_tree = RB_ROOT;
- mutex_init(&ipa_ctx->ipa_active_clients_lock);
- ipa_ctx->ipa_active_clients = 0;
- result = ipa_bridge_init();
- if (result) {
- IPAERR("ipa bridge init err.\n");
- result = -ENODEV;
- goto fail_a5_pipes;
- }
- /* setup the A5-IPA pipes */
- if (ipa_setup_a5_pipes()) {
- IPAERR(":failed to setup IPA-A5 pipes.\n");
- result = -ENODEV;
- goto fail_a5_pipes;
- }
- ipa_replenish_rx_cache();
- if (ipa_init_flt_block()) {
- IPAERR("fail to setup dummy filter rules\n");
- result = -ENODEV;
- goto fail_empty_rt_tbl;
- }
- /*
- * setup an empty routing table in system memory, this will be used
- * to delete a routing table cleanly and safely
- */
- ipa_ctx->empty_rt_tbl_mem.size = IPA_ROUTING_RULE_BYTE_SIZE;
- ipa_ctx->empty_rt_tbl_mem.base =
- dma_alloc_coherent(NULL, ipa_ctx->empty_rt_tbl_mem.size,
- &ipa_ctx->empty_rt_tbl_mem.phys_base,
- GFP_KERNEL);
- if (!ipa_ctx->empty_rt_tbl_mem.base) {
- IPAERR("DMA buff alloc fail %d bytes for empty routing tbl\n",
- ipa_ctx->empty_rt_tbl_mem.size);
- result = -ENOMEM;
- goto fail_empty_rt_tbl;
- }
- memset(ipa_ctx->empty_rt_tbl_mem.base, 0,
- ipa_ctx->empty_rt_tbl_mem.size);
- /* setup the IPA pipe mem pool */
- ipa_pipe_mem_init(resource_p->ipa_pipe_mem_start_ofst,
- resource_p->ipa_pipe_mem_size);
- ipa_ctx->class = class_create(THIS_MODULE, DRV_NAME);
- result = alloc_chrdev_region(&ipa_ctx->dev_num, 0, 1, DRV_NAME);
- if (result) {
- IPAERR("alloc_chrdev_region err.\n");
- result = -ENODEV;
- goto fail_alloc_chrdev_region;
- }
- ipa_ctx->dev = device_create(ipa_ctx->class, NULL, ipa_ctx->dev_num,
- ipa_ctx, DRV_NAME);
- if (IS_ERR(ipa_ctx->dev)) {
- IPAERR(":device_create err.\n");
- result = -ENODEV;
- goto fail_device_create;
- }
- cdev_init(&ipa_ctx->cdev, &ipa_drv_fops);
- ipa_ctx->cdev.owner = THIS_MODULE;
- ipa_ctx->cdev.ops = &ipa_drv_fops; /* from LDD3 */
- result = cdev_add(&ipa_ctx->cdev, ipa_ctx->dev_num, 1);
- if (result) {
- IPAERR(":cdev_add err=%d\n", -result);
- result = -ENODEV;
- goto fail_cdev_add;
- }
- /* default aggregation parameters */
- ipa_ctx->aggregation_type = IPA_MBIM_16;
- ipa_ctx->aggregation_byte_limit = 1;
- ipa_ctx->aggregation_time_limit = 0;
- if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_PCIE) {
- /* Initialize IPA RM (resource manager) */
- result = ipa_rm_initialize();
- if (result) {
- IPAERR(":cdev_add err=%d\n", -result);
- result = -ENODEV;
- goto fail_ipa_rm_init;
- }
- }
- if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL) {
- a2_mux_init();
- /* Initialize the tethering bridge driver */
- result = teth_bridge_driver_init();
- if (result) {
- IPAERR(":teth_bridge_driver_init() failed\n");
- result = -ENODEV;
- goto fail_cdev_add;
- }
- }
- /* gate IPA clocks */
- if (ipa_ctx->ipa_hw_mode == IPA_HW_MODE_NORMAL)
- ipa_disable_clks();
- IPADBG(":IPA driver init OK.\n");
- return 0;
- fail_ipa_rm_init:
- cdev_del(&ipa_ctx->cdev);
- fail_cdev_add:
- device_destroy(ipa_ctx->class, ipa_ctx->dev_num);
- fail_device_create:
- unregister_chrdev_region(ipa_ctx->dev_num, 1);
- fail_alloc_chrdev_region:
- if (ipa_ctx->pipe_mem_pool)
- gen_pool_destroy(ipa_ctx->pipe_mem_pool);
- dma_free_coherent(NULL,
- ipa_ctx->empty_rt_tbl_mem.size,
- ipa_ctx->empty_rt_tbl_mem.base,
- ipa_ctx->empty_rt_tbl_mem.phys_base);
- fail_empty_rt_tbl:
- ipa_cleanup_rx();
- ipa_teardown_a5_pipes();
- fail_a5_pipes:
- destroy_workqueue(ipa_ctx->tx_wq);
- fail_tx_wq:
- destroy_workqueue(ipa_ctx->rx_wq);
- fail_rx_wq:
- /*
- * DMA pool need to be released only for IPA HW v1.0 only.
- */
- if (ipa_ctx->ipa_hw_type == IPA_HW_v1_0)
- dma_pool_destroy(ipa_ctx->dma_pool);
- fail_dma_pool:
- kmem_cache_destroy(ipa_ctx->tree_node_cache);
- fail_tree_node_cache:
- kmem_cache_destroy(ipa_ctx->rx_pkt_wrapper_cache);
- fail_rx_pkt_wrapper_cache:
- kmem_cache_destroy(ipa_ctx->tx_pkt_wrapper_cache);
- fail_tx_pkt_wrapper_cache:
- kmem_cache_destroy(ipa_ctx->rt_tbl_cache);
- fail_rt_tbl_cache:
- kmem_cache_destroy(ipa_ctx->hdr_offset_cache);
- fail_hdr_offset_cache:
- kmem_cache_destroy(ipa_ctx->hdr_cache);
- fail_hdr_cache:
- kmem_cache_destroy(ipa_ctx->rt_rule_cache);
- fail_rt_rule_cache:
- kmem_cache_destroy(ipa_ctx->flt_rule_cache);
- fail_flt_rule_cache:
- sps_deregister_bam_device(ipa_ctx->bam_handle);
- fail_init_hw:
- iounmap(ipa_ctx->mmio);
- fail_remap:
- kfree(ipa_ctx);
- ipa_ctx = NULL;
- fail_mem:
- return result;
- }
- static int ipa_plat_drv_probe(struct platform_device *pdev_p)
- {
- int result = 0;
- struct resource *resource_p;
- IPADBG("IPA plat drv probe\n");
- /* initialize ipa_res */
- ipa_res.ipa_pipe_mem_start_ofst = IPA_PIPE_MEM_START_OFST;
- ipa_res.ipa_pipe_mem_size = IPA_PIPE_MEM_SIZE;
- ipa_res.ipa_hw_type = 0;
- ipa_res.ipa_hw_mode = 0;
- result = ipa_load_pipe_connection(pdev_p,
- A2_TO_IPA,
- &ipa_res.a2_to_ipa_pipe);
- if (0 != result)
- IPAERR(":ipa_load_pipe_connection failed!\n");
- result = ipa_load_pipe_connection(pdev_p, IPA_TO_A2,
- &ipa_res.ipa_to_a2_pipe);
- if (0 != result)
- IPAERR(":ipa_load_pipe_connection failed!\n");
- /* Get IPA wrapper address */
- resource_p = platform_get_resource_byname(pdev_p, IORESOURCE_MEM,
- "ipa-base");
- if (!resource_p) {
- IPAERR(":get resource failed for ipa-base!\n");
- return -ENODEV;
- } else {
- ipa_res.ipa_mem_base = resource_p->start;
- ipa_res.ipa_mem_size = resource_size(resource_p);
- }
- /* Get IPA BAM address */
- resource_p = platform_get_resource_byname(pdev_p, IORESOURCE_MEM,
- "bam-base");
- if (!resource_p) {
- IPAERR(":get resource failed for bam-base!\n");
- return -ENODEV;
- } else {
- ipa_res.bam_mem_base = resource_p->start;
- ipa_res.bam_mem_size = resource_size(resource_p);
- }
- /* Get IPA A2 BAM address */
- resource_p = platform_get_resource_byname(pdev_p, IORESOURCE_MEM,
- "a2-bam-base");
- if (!resource_p) {
- IPAERR(":get resource failed for a2-bam-base!\n");
- return -ENODEV;
- } else {
- ipa_res.a2_bam_mem_base = resource_p->start;
- ipa_res.a2_bam_mem_size = resource_size(resource_p);
- }
- /* Get IPA pipe mem start ofst */
- resource_p = platform_get_resource_byname(pdev_p, IORESOURCE_MEM,
- "ipa-pipe-mem");
- if (!resource_p) {
- IPADBG(":get resource failed for ipa-pipe-mem\n");
- } else {
- ipa_res.ipa_pipe_mem_start_ofst = resource_p->start;
- ipa_res.ipa_pipe_mem_size = resource_size(resource_p);
- }
- /* Get IPA IRQ number */
- resource_p = platform_get_resource_byname(pdev_p, IORESOURCE_IRQ,
- "ipa-irq");
- if (!resource_p) {
- IPAERR(":get resource failed for ipa-irq!\n");
- return -ENODEV;
- } else {
- ipa_res.ipa_irq = resource_p->start;
- }
- /* Get IPA BAM IRQ number */
- resource_p = platform_get_resource_byname(pdev_p, IORESOURCE_IRQ,
- "bam-irq");
- if (!resource_p) {
- IPAERR(":get resource failed for bam-irq!\n");
- return -ENODEV;
- } else {
- ipa_res.bam_irq = resource_p->start;
- }
- /* Get IPA A2 BAM IRQ number */
- resource_p = platform_get_resource_byname(pdev_p, IORESOURCE_IRQ,
- "a2-bam-irq");
- if (!resource_p) {
- IPAERR(":get resource failed for a2-bam-irq!\n");
- return -ENODEV;
- } else {
- ipa_res.a2_bam_irq = resource_p->start;
- }
- /* Get IPA HW Version */
- result = of_property_read_u32(pdev_p->dev.of_node, "qcom,ipa-hw-ver",
- &ipa_res.ipa_hw_type);
- if ((result) || (ipa_res.ipa_hw_type == 0)) {
- IPAERR(":get resource failed for ipa-hw-ver!\n");
- return -ENODEV;
- }
- IPADBG(": found ipa_res.ipa_hw_type = %d", ipa_res.ipa_hw_type);
- /* Get IPA HW mode */
- result = of_property_read_u32(pdev_p->dev.of_node, "ipa-hw-mode",
- &ipa_res.ipa_hw_mode);
- if (result)
- IPADBG("using default (IPA_MODE_NORMAL) for ipa-hw-mode\n");
- else
- IPADBG(": found ipa_res.ipa_hw_mode = %d", ipa_res.ipa_hw_mode);
- IPADBG(":ipa_mem_base = 0x%x, ipa_mem_size = 0x%x\n",
- ipa_res.ipa_mem_base, ipa_res.ipa_mem_size);
- IPADBG(":bam_mem_base = 0x%x, bam_mem_size = 0x%x\n",
- ipa_res.bam_mem_base, ipa_res.bam_mem_size);
- IPADBG(":pipe_mem_start_ofst = 0x%x, pipe_mem_size = 0x%x\n",
- ipa_res.ipa_pipe_mem_start_ofst, ipa_res.ipa_pipe_mem_size);
- IPADBG(":ipa_irq = %d\n", ipa_res.ipa_irq);
- IPADBG(":bam_irq = %d\n", ipa_res.bam_irq);
- /* stash the IPA dev ptr */
- ipa_dev = &pdev_p->dev;
- if (ipa_res.ipa_hw_mode == IPA_HW_MODE_NORMAL) {
- /* get IPA clocks */
- if (ipa_get_clks(ipa_dev) != 0) {
- IPAERR(":fail to get clk handle's!\n");
- return -ENODEV;
- }
- /* get BUS handle */
- ipa_bus_hdl =
- msm_bus_scale_register_client(&ipa_bus_client_pdata);
- if (!ipa_bus_hdl) {
- IPAERR(":fail to register with bus mgr!\n");
- return -ENODEV;
- }
- /* enable IPA clocks */
- ipa_enable_clks();
- }
- /* Proceed to real initialization */
- result = ipa_init(&ipa_res);
- if (result) {
- IPAERR("ipa_init failed\n");
- /* gate IPA clocks */
- if (ipa_res.ipa_hw_mode == IPA_HW_MODE_NORMAL)
- ipa_disable_clks();
- }
- result = device_create_file(&pdev_p->dev,
- &dev_attr_aggregation_type);
- if (result)
- IPAERR("failed to create device file\n");
- result = device_create_file(&pdev_p->dev,
- &dev_attr_aggregation_byte_limit);
- if (result)
- IPAERR("failed to create device file\n");
- result = device_create_file(&pdev_p->dev,
- &dev_attr_aggregation_time_limit);
- if (result)
- IPAERR("failed to create device file\n");
- return result;
- }
- static struct platform_driver ipa_plat_drv = {
- .probe = ipa_plat_drv_probe,
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- .of_match_table = ipa_plat_drv_match,
- },
- };
- struct ipa_context *ipa_get_ctx(void)
- {
- return ipa_ctx;
- }
- static int __init ipa_module_init(void)
- {
- int result = 0;
- IPADBG("IPA module init\n");
- /* Register as a platform device driver */
- platform_driver_register(&ipa_plat_drv);
- ipa_debugfs_init();
- return result;
- }
- subsys_initcall(ipa_module_init);
- MODULE_LICENSE("GPL v2");
- MODULE_DESCRIPTION("IPA HW device driver");
|