1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
- */
- #include <linux/ipa.h>
- #include <linux/errno.h>
- #include <linux/ipc_logging.h>
- #include <linux/debugfs.h>
- #include "ipahal.h"
- #include "ipahal_fltrt.h"
- #include "ipahal_fltrt_i.h"
- #include "ipahal_i.h"
- #include "../../ipa_common_i.h"
- #define IPA_MAC_FLT_BITS (IPA_FLT_MAC_DST_ADDR_ETHER_II | \
- IPA_FLT_MAC_SRC_ADDR_ETHER_II | IPA_FLT_MAC_DST_ADDR_802_3 | \
- IPA_FLT_MAC_SRC_ADDR_802_3 | IPA_FLT_MAC_DST_ADDR_802_1Q | \
- IPA_FLT_MAC_SRC_ADDR_802_1Q)
- /*
- * struct ipahal_fltrt_obj - Flt/Rt H/W information for specific IPA version
- * @support_hash: Is hashable tables supported
- * @tbl_width: Width of table in bytes
- * @sysaddr_alignment: System table address alignment
- * @lcladdr_alignment: Local table offset alignment
- * @blk_sz_alignment: Rules block size alignment
- * @rule_start_alignment: Rule start address alignment
- * @tbl_hdr_width: Width of the header structure in bytes
- * @tbl_addr_mask: Masking for Table address
- * @rule_max_prio: Max possible priority of a rule
- * @rule_min_prio: Min possible priority of a rule
- * @low_rule_id: Low value of Rule ID that can be used
- * @rule_id_bit_len: Rule is high (MSB) bit len
- * @rule_buf_size: Max size rule may utilize.
- * @write_val_to_hdr: Write address or offset to header entry
- * @create_flt_bitmap: Create bitmap in H/W format using given bitmap
- * @create_tbl_addr: Given raw table address, create H/W formated one
- * @parse_tbl_addr: Parse the given H/W address (hdr format)
- * @rt_generate_hw_rule: Generate RT rule in H/W format
- * @flt_generate_hw_rule: Generate FLT rule in H/W format
- * @flt_generate_eq: Generate flt equation attributes from rule attributes
- * @rt_parse_hw_rule: Parse rt rule read from H/W
- * @flt_parse_hw_rule: Parse flt rule read from H/W
- * @eq_bitfield: Array of the bit fields of the support equations.
- * 0xFF means the equation is not supported
- */
- struct ipahal_fltrt_obj {
- bool support_hash;
- u32 tbl_width;
- u32 sysaddr_alignment;
- u32 lcladdr_alignment;
- u32 blk_sz_alignment;
- u32 rule_start_alignment;
- u32 tbl_hdr_width;
- u32 tbl_addr_mask;
- int rule_max_prio;
- int rule_min_prio;
- u32 low_rule_id;
- u32 rule_id_bit_len;
- u32 rule_buf_size;
- u8* (*write_val_to_hdr)(u64 val, u8 *hdr);
- u64 (*create_flt_bitmap)(u64 ep_bitmap);
- u64 (*create_tbl_addr)(bool is_sys, u64 addr);
- void (*parse_tbl_addr)(u64 hwaddr, u64 *addr, bool *is_sys);
- int (*rt_generate_hw_rule)(struct ipahal_rt_rule_gen_params *params,
- u32 *hw_len, u8 *buf);
- int (*flt_generate_hw_rule)(struct ipahal_flt_rule_gen_params *params,
- u32 *hw_len, u8 *buf);
- int (*flt_generate_eq)(enum ipa_ip_type ipt,
- const struct ipa_rule_attrib *attrib,
- struct ipa_ipfltri_rule_eq *eq_atrb);
- int (*rt_parse_hw_rule)(u8 *addr, struct ipahal_rt_rule_entry *rule);
- int (*flt_parse_hw_rule)(u8 *addr, struct ipahal_flt_rule_entry *rule);
- u8 eq_bitfield[IPA_EQ_MAX];
- };
- static u64 ipa_fltrt_create_flt_bitmap(u64 ep_bitmap)
- {
- /* At IPA3, there global configuration is possible but not used */
- return (ep_bitmap << 1) & ~0x1;
- }
- static u64 ipa_fltrt_create_tbl_addr(bool is_sys, u64 addr)
- {
- if (is_sys) {
- if (addr & IPA3_0_HW_TBL_SYSADDR_ALIGNMENT) {
- IPAHAL_ERR(
- "sys addr is not aligned accordingly addr=0x%pad\n",
- &addr);
- ipa_assert();
- return 0;
- }
- } else {
- if (addr & IPA3_0_HW_TBL_LCLADDR_ALIGNMENT) {
- IPAHAL_ERR("addr/ofst isn't lcl addr aligned %llu\n",
- addr);
- ipa_assert();
- return 0;
- }
- /*
- * for local tables (at sram) offsets is used as tables
- * addresses. offset need to be in 8B units
- * (local address aligned) and left shifted to its place.
- * Local bit need to be enabled.
- */
- addr /= IPA3_0_HW_TBL_LCLADDR_ALIGNMENT + 1;
- addr *= IPA3_0_HW_TBL_ADDR_MASK + 1;
- addr += 1;
- }
- return addr;
- }
- static void ipa_fltrt_parse_tbl_addr(u64 hwaddr, u64 *addr, bool *is_sys)
- {
- IPAHAL_DBG_LOW("Parsing hwaddr 0x%llx\n", hwaddr);
- *is_sys = !(hwaddr & 0x1);
- hwaddr &= (~0ULL - 1);
- if (hwaddr & IPA3_0_HW_TBL_SYSADDR_ALIGNMENT) {
- IPAHAL_ERR(
- "sys addr is not aligned accordingly addr=0x%pad\n",
- &hwaddr);
- ipa_assert();
- return;
- }
- if (!*is_sys) {
- hwaddr /= IPA3_0_HW_TBL_ADDR_MASK + 1;
- hwaddr *= IPA3_0_HW_TBL_LCLADDR_ALIGNMENT + 1;
- }
- *addr = hwaddr;
- }
- /* Update these tables of the number of equations changes */
- static const int ipa3_0_ofst_meq32[] = { IPA_OFFSET_MEQ32_0,
- IPA_OFFSET_MEQ32_1};
- static const int ipa3_0_ofst_meq128[] = { IPA_OFFSET_MEQ128_0,
- IPA_OFFSET_MEQ128_1};
- static const int ipa3_0_ihl_ofst_rng16[] = { IPA_IHL_OFFSET_RANGE16_0,
- IPA_IHL_OFFSET_RANGE16_1};
- static const int ipa3_0_ihl_ofst_meq32[] = { IPA_IHL_OFFSET_MEQ32_0,
- IPA_IHL_OFFSET_MEQ32_1};
- static int ipa_fltrt_generate_hw_rule_bdy(enum ipa_ip_type ipt,
- const struct ipa_rule_attrib *attrib, u8 **buf, u16 *en_rule);
- static int ipa_fltrt_generate_hw_rule_bdy_from_eq(
- const struct ipa_ipfltri_rule_eq *attrib, u8 **buf);
- static int ipa_flt_generate_eq_ip4(enum ipa_ip_type ip,
- const struct ipa_rule_attrib *attrib,
- struct ipa_ipfltri_rule_eq *eq_atrb);
- static int ipa_flt_generate_eq_ip6(enum ipa_ip_type ip,
- const struct ipa_rule_attrib *attrib,
- struct ipa_ipfltri_rule_eq *eq_atrb);
- static int ipa_flt_generate_eq(enum ipa_ip_type ipt,
- const struct ipa_rule_attrib *attrib,
- struct ipa_ipfltri_rule_eq *eq_atrb);
- static int ipa_rt_parse_hw_rule(u8 *addr,
- struct ipahal_rt_rule_entry *rule);
- static int ipa_rt_parse_hw_rule_ipav4_5(u8 *addr,
- struct ipahal_rt_rule_entry *rule);
- static int ipa_flt_parse_hw_rule(u8 *addr,
- struct ipahal_flt_rule_entry *rule);
- static int ipa_flt_parse_hw_rule_ipav4(u8 *addr,
- struct ipahal_flt_rule_entry *rule);
- static int ipa_flt_parse_hw_rule_ipav4_5(u8 *addr,
- struct ipahal_flt_rule_entry *rule);
- #define IPA_IS_RAN_OUT_OF_EQ(__eq_array, __eq_index) \
- (ARRAY_SIZE(__eq_array) <= (__eq_index))
- #define IPA_GET_RULE_EQ_BIT_PTRN(__eq) \
- (BIT(ipahal_fltrt_objs[ipahal_ctx->hw_type].eq_bitfield[(__eq)]))
- #define IPA_IS_RULE_EQ_VALID(__eq) \
- (ipahal_fltrt_objs[ipahal_ctx->hw_type].eq_bitfield[(__eq)] != 0xFF)
- /*
- * ipa_fltrt_rule_generation_err_check() - check basic validity on the rule
- * attribs before starting building it
- * checks if not not using ipv4 attribs on ipv6 and vice-versa
- * @ip: IP address type
- * @attrib: IPA rule attribute
- *
- * Return: 0 on success, -EPERM on failure
- */
- static int ipa_fltrt_rule_generation_err_check(
- enum ipa_ip_type ipt, const struct ipa_rule_attrib *attrib)
- {
- if (ipt == IPA_IP_v4) {
- if (attrib->attrib_mask & IPA_FLT_NEXT_HDR ||
- attrib->attrib_mask & IPA_FLT_TC ||
- attrib->attrib_mask & IPA_FLT_FLOW_LABEL) {
- IPAHAL_ERR_RL("v6 attrib's specified for v4 rule\n");
- return -EPERM;
- }
- } else if (ipt == IPA_IP_v6) {
- if (attrib->attrib_mask & IPA_FLT_TOS ||
- attrib->attrib_mask & IPA_FLT_PROTOCOL) {
- IPAHAL_ERR_RL("v4 attrib's specified for v6 rule\n");
- return -EPERM;
- }
- } else {
- IPAHAL_ERR_RL("unsupported ip %d\n", ipt);
- return -EPERM;
- }
- return 0;
- }
- static int ipa_rt_gen_hw_rule(struct ipahal_rt_rule_gen_params *params,
- u32 *hw_len, u8 *buf)
- {
- struct ipa3_0_rt_rule_hw_hdr *rule_hdr;
- u8 *start;
- u16 en_rule = 0;
- start = buf;
- rule_hdr = (struct ipa3_0_rt_rule_hw_hdr *)buf;
- ipa_assert_on(params->dst_pipe_idx & ~0x1F);
- rule_hdr->u.hdr.pipe_dest_idx = params->dst_pipe_idx;
- switch (params->hdr_type) {
- case IPAHAL_RT_RULE_HDR_PROC_CTX:
- rule_hdr->u.hdr.system = !params->hdr_lcl;
- rule_hdr->u.hdr.proc_ctx = 1;
- ipa_assert_on(params->hdr_ofst & 31);
- rule_hdr->u.hdr.hdr_offset = (params->hdr_ofst) >> 5;
- break;
- case IPAHAL_RT_RULE_HDR_RAW:
- rule_hdr->u.hdr.system = !params->hdr_lcl;
- rule_hdr->u.hdr.proc_ctx = 0;
- ipa_assert_on(params->hdr_ofst & 3);
- rule_hdr->u.hdr.hdr_offset = (params->hdr_ofst) >> 2;
- break;
- case IPAHAL_RT_RULE_HDR_NONE:
- rule_hdr->u.hdr.system = !params->hdr_lcl;
- rule_hdr->u.hdr.proc_ctx = 0;
- rule_hdr->u.hdr.hdr_offset = 0;
- break;
- default:
- IPAHAL_ERR("Invalid HDR type %d\n", params->hdr_type);
- WARN_ON_RATELIMIT_IPA(1);
- return -EINVAL;
- }
- ipa_assert_on(params->priority & ~0x3FF);
- rule_hdr->u.hdr.priority = params->priority;
- rule_hdr->u.hdr.retain_hdr = params->rule->retain_hdr ? 0x1 : 0x0;
- ipa_assert_on(params->id & ~((1 << IPA3_0_RULE_ID_BIT_LEN) - 1));
- ipa_assert_on(params->id == ((1 << IPA3_0_RULE_ID_BIT_LEN) - 1));
- rule_hdr->u.hdr.rule_id = params->id;
- buf += sizeof(struct ipa3_0_rt_rule_hw_hdr);
- if (ipa_fltrt_generate_hw_rule_bdy(params->ipt, ¶ms->rule->attrib,
- &buf, &en_rule)) {
- IPAHAL_ERR("fail to generate hw rule\n");
- return -EPERM;
- }
- rule_hdr->u.hdr.en_rule = en_rule;
- IPAHAL_DBG_LOW("en_rule 0x%x\n", en_rule);
- ipa_write_64(rule_hdr->u.word, (u8 *)rule_hdr);
- if (*hw_len == 0) {
- *hw_len = buf - start;
- } else if (*hw_len != (buf - start)) {
- IPAHAL_ERR("hw_len differs b/w passed=0x%x calc=%td\n",
- *hw_len, (buf - start));
- return -EPERM;
- }
- return 0;
- }
- static int ipa_rt_gen_hw_rule_ipav4_5(struct ipahal_rt_rule_gen_params *params,
- u32 *hw_len, u8 *buf)
- {
- struct ipa4_5_rt_rule_hw_hdr *rule_hdr;
- u8 *start;
- u16 en_rule = 0;
- start = buf;
- rule_hdr = (struct ipa4_5_rt_rule_hw_hdr *)buf;
- ipa_assert_on(params->dst_pipe_idx & ~0x1F);
- rule_hdr->u.hdr.pipe_dest_idx = params->dst_pipe_idx;
- switch (params->hdr_type) {
- case IPAHAL_RT_RULE_HDR_PROC_CTX:
- rule_hdr->u.hdr.system = !params->hdr_lcl;
- rule_hdr->u.hdr.proc_ctx = 1;
- ipa_assert_on(params->hdr_ofst & 31);
- rule_hdr->u.hdr.hdr_offset = (params->hdr_ofst) >> 5;
- break;
- case IPAHAL_RT_RULE_HDR_RAW:
- rule_hdr->u.hdr.system = !params->hdr_lcl;
- rule_hdr->u.hdr.proc_ctx = 0;
- ipa_assert_on(params->hdr_ofst & 3);
- rule_hdr->u.hdr.hdr_offset = (params->hdr_ofst) >> 2;
- break;
- case IPAHAL_RT_RULE_HDR_NONE:
- rule_hdr->u.hdr.system = !params->hdr_lcl;
- rule_hdr->u.hdr.proc_ctx = 0;
- rule_hdr->u.hdr.hdr_offset = 0;
- break;
- default:
- IPAHAL_ERR("Invalid HDR type %d\n", params->hdr_type);
- WARN_ON_RATELIMIT_IPA(1);
- return -EINVAL;
- }
- ipa_assert_on(params->priority & ~0x3FF);
- rule_hdr->u.hdr.priority = params->priority;
- rule_hdr->u.hdr.retain_hdr = params->rule->retain_hdr ? 0x1 : 0x0;
- ipa_assert_on(params->id & ~((1 << IPA3_0_RULE_ID_BIT_LEN) - 1));
- ipa_assert_on(params->id == ((1 << IPA3_0_RULE_ID_BIT_LEN) - 1));
- rule_hdr->u.hdr.rule_id = params->id;
- rule_hdr->u.hdr.stats_cnt_idx_lsb = params->cnt_idx & 0x3F;
- rule_hdr->u.hdr.stats_cnt_idx_msb = (params->cnt_idx & 0xC0) >> 6;
- buf += sizeof(struct ipa4_5_rt_rule_hw_hdr);
- if (ipa_fltrt_generate_hw_rule_bdy(params->ipt, ¶ms->rule->attrib,
- &buf, &en_rule)) {
- IPAHAL_ERR("fail to generate hw rule\n");
- return -EPERM;
- }
- rule_hdr->u.hdr.en_rule = en_rule;
- IPAHAL_DBG_LOW("en_rule 0x%x\n", en_rule);
- ipa_write_64(rule_hdr->u.word, (u8 *)rule_hdr);
- if (*hw_len == 0) {
- *hw_len = buf - start;
- } else if (*hw_len != (buf - start)) {
- IPAHAL_ERR("hw_len differs b/w passed=0x%x calc=%td\n",
- *hw_len, (buf - start));
- return -EPERM;
- }
- return 0;
- }
- static int ipa_flt_gen_hw_rule(struct ipahal_flt_rule_gen_params *params,
- u32 *hw_len, u8 *buf)
- {
- struct ipa3_0_flt_rule_hw_hdr *rule_hdr;
- u8 *start;
- u16 en_rule = 0;
- start = buf;
- rule_hdr = (struct ipa3_0_flt_rule_hw_hdr *)buf;
- switch (params->rule->action) {
- case IPA_PASS_TO_ROUTING:
- rule_hdr->u.hdr.action = 0x0;
- break;
- case IPA_PASS_TO_SRC_NAT:
- rule_hdr->u.hdr.action = 0x1;
- break;
- case IPA_PASS_TO_DST_NAT:
- rule_hdr->u.hdr.action = 0x2;
- break;
- case IPA_PASS_TO_EXCEPTION:
- rule_hdr->u.hdr.action = 0x3;
- break;
- default:
- IPAHAL_ERR_RL("Invalid Rule Action %d\n", params->rule->action);
- WARN_ON_RATELIMIT_IPA(1);
- return -EINVAL;
- }
- ipa_assert_on(params->rt_tbl_idx & ~0x1F);
- rule_hdr->u.hdr.rt_tbl_idx = params->rt_tbl_idx;
- rule_hdr->u.hdr.retain_hdr = params->rule->retain_hdr ? 0x1 : 0x0;
- rule_hdr->u.hdr.rsvd1 = 0;
- rule_hdr->u.hdr.rsvd2 = 0;
- rule_hdr->u.hdr.rsvd3 = 0;
- ipa_assert_on(params->priority & ~0x3FF);
- rule_hdr->u.hdr.priority = params->priority;
- ipa_assert_on(params->id & ~((1 << IPA3_0_RULE_ID_BIT_LEN) - 1));
- ipa_assert_on(params->id == ((1 << IPA3_0_RULE_ID_BIT_LEN) - 1));
- rule_hdr->u.hdr.rule_id = params->id;
- buf += sizeof(struct ipa3_0_flt_rule_hw_hdr);
- if (params->rule->eq_attrib_type) {
- if (ipa_fltrt_generate_hw_rule_bdy_from_eq(
- ¶ms->rule->eq_attrib, &buf)) {
- IPAHAL_ERR_RL("fail to generate hw rule from eq\n");
- return -EPERM;
- }
- en_rule = params->rule->eq_attrib.rule_eq_bitmap;
- } else {
- if (ipa_fltrt_generate_hw_rule_bdy(params->ipt,
- ¶ms->rule->attrib, &buf, &en_rule)) {
- IPAHAL_ERR_RL("fail to generate hw rule\n");
- return -EPERM;
- }
- }
- rule_hdr->u.hdr.en_rule = en_rule;
- IPAHAL_DBG_LOW("en_rule=0x%x, action=%d, rt_idx=%d, retain_hdr=%d\n",
- en_rule,
- rule_hdr->u.hdr.action,
- rule_hdr->u.hdr.rt_tbl_idx,
- rule_hdr->u.hdr.retain_hdr);
- IPAHAL_DBG_LOW("priority=%d, rule_id=%d\n",
- rule_hdr->u.hdr.priority,
- rule_hdr->u.hdr.rule_id);
- ipa_write_64(rule_hdr->u.word, (u8 *)rule_hdr);
- if (*hw_len == 0) {
- *hw_len = buf - start;
- } else if (*hw_len != (buf - start)) {
- IPAHAL_ERR_RL("hw_len differs b/w passed=0x%x calc=%td\n",
- *hw_len, (buf - start));
- return -EPERM;
- }
- return 0;
- }
- static int ipa_flt_gen_hw_rule_ipav4(struct ipahal_flt_rule_gen_params *params,
- u32 *hw_len, u8 *buf)
- {
- struct ipa4_0_flt_rule_hw_hdr *rule_hdr;
- u8 *start;
- u16 en_rule = 0;
- start = buf;
- rule_hdr = (struct ipa4_0_flt_rule_hw_hdr *)buf;
- switch (params->rule->action) {
- case IPA_PASS_TO_ROUTING:
- rule_hdr->u.hdr.action = 0x0;
- break;
- case IPA_PASS_TO_SRC_NAT:
- rule_hdr->u.hdr.action = 0x1;
- break;
- case IPA_PASS_TO_DST_NAT:
- rule_hdr->u.hdr.action = 0x2;
- break;
- case IPA_PASS_TO_EXCEPTION:
- rule_hdr->u.hdr.action = 0x3;
- break;
- default:
- IPAHAL_ERR("Invalid Rule Action %d\n", params->rule->action);
- WARN_ON_RATELIMIT_IPA(1);
- return -EINVAL;
- }
- ipa_assert_on(params->rt_tbl_idx & ~0x1F);
- rule_hdr->u.hdr.rt_tbl_idx = params->rt_tbl_idx;
- rule_hdr->u.hdr.retain_hdr = params->rule->retain_hdr ? 0x1 : 0x0;
- ipa_assert_on(params->rule->pdn_idx & ~0xF);
- rule_hdr->u.hdr.pdn_idx = params->rule->pdn_idx;
- rule_hdr->u.hdr.set_metadata = params->rule->set_metadata;
- rule_hdr->u.hdr.rsvd2 = 0;
- rule_hdr->u.hdr.rsvd3 = 0;
- ipa_assert_on(params->priority & ~0x3FF);
- rule_hdr->u.hdr.priority = params->priority;
- ipa_assert_on(params->id & ~((1 << IPA3_0_RULE_ID_BIT_LEN) - 1));
- ipa_assert_on(params->id == ((1 << IPA3_0_RULE_ID_BIT_LEN) - 1));
- rule_hdr->u.hdr.rule_id = params->id;
- buf += sizeof(struct ipa4_0_flt_rule_hw_hdr);
- if (params->rule->eq_attrib_type) {
- if (ipa_fltrt_generate_hw_rule_bdy_from_eq(
- ¶ms->rule->eq_attrib, &buf)) {
- IPAHAL_ERR("fail to generate hw rule from eq\n");
- return -EPERM;
- }
- en_rule = params->rule->eq_attrib.rule_eq_bitmap;
- } else {
- if (ipa_fltrt_generate_hw_rule_bdy(params->ipt,
- ¶ms->rule->attrib, &buf, &en_rule)) {
- IPAHAL_ERR("fail to generate hw rule\n");
- return -EPERM;
- }
- }
- rule_hdr->u.hdr.en_rule = en_rule;
- IPAHAL_DBG_LOW("en_rule=0x%x, action=%d, rt_idx=%d, retain_hdr=%d\n",
- en_rule,
- rule_hdr->u.hdr.action,
- rule_hdr->u.hdr.rt_tbl_idx,
- rule_hdr->u.hdr.retain_hdr);
- IPAHAL_DBG_LOW("priority=%d, rule_id=%d, pdn=%d, set_metadata=%d\n",
- rule_hdr->u.hdr.priority,
- rule_hdr->u.hdr.rule_id,
- rule_hdr->u.hdr.pdn_idx,
- rule_hdr->u.hdr.set_metadata);
- ipa_write_64(rule_hdr->u.word, (u8 *)rule_hdr);
- if (*hw_len == 0) {
- *hw_len = buf - start;
- } else if (*hw_len != (buf - start)) {
- IPAHAL_ERR("hw_len differs b/w passed=0x%x calc=%td\n",
- *hw_len, (buf - start));
- return -EPERM;
- }
- return 0;
- }
- static int ipa_flt_gen_hw_rule_ipav4_5(
- struct ipahal_flt_rule_gen_params *params,
- u32 *hw_len, u8 *buf)
- {
- struct ipa4_5_flt_rule_hw_hdr *rule_hdr;
- u8 *start;
- u16 en_rule = 0;
- start = buf;
- rule_hdr = (struct ipa4_5_flt_rule_hw_hdr *)buf;
- switch (params->rule->action) {
- case IPA_PASS_TO_ROUTING:
- rule_hdr->u.hdr.action = 0x0;
- break;
- case IPA_PASS_TO_SRC_NAT:
- rule_hdr->u.hdr.action = 0x1;
- break;
- case IPA_PASS_TO_DST_NAT:
- rule_hdr->u.hdr.action = 0x2;
- break;
- case IPA_PASS_TO_EXCEPTION:
- rule_hdr->u.hdr.action = 0x3;
- break;
- default:
- IPAHAL_ERR("Invalid Rule Action %d\n", params->rule->action);
- WARN_ON_RATELIMIT_IPA(1);
- return -EINVAL;
- }
- ipa_assert_on(params->rt_tbl_idx & ~0x1F);
- rule_hdr->u.hdr.rt_tbl_idx = params->rt_tbl_idx;
- rule_hdr->u.hdr.retain_hdr = params->rule->retain_hdr ? 0x1 : 0x0;
- ipa_assert_on(params->rule->pdn_idx & ~0xF);
- rule_hdr->u.hdr.pdn_idx = params->rule->pdn_idx;
- rule_hdr->u.hdr.set_metadata = params->rule->set_metadata;
- rule_hdr->u.hdr.rsvd2 = 0;
- ipa_assert_on(params->priority & ~0x3FF);
- rule_hdr->u.hdr.priority = params->priority;
- ipa_assert_on(params->id & ~((1 << IPA3_0_RULE_ID_BIT_LEN) - 1));
- ipa_assert_on(params->id == ((1 << IPA3_0_RULE_ID_BIT_LEN) - 1));
- rule_hdr->u.hdr.rule_id = params->id;
- rule_hdr->u.hdr.stats_cnt_idx_lsb = params->cnt_idx & 0x3F;
- rule_hdr->u.hdr.stats_cnt_idx_msb = (params->cnt_idx & 0xC0) >> 6;
- buf += sizeof(struct ipa4_5_flt_rule_hw_hdr);
- if (params->rule->eq_attrib_type) {
- if (ipa_fltrt_generate_hw_rule_bdy_from_eq(
- ¶ms->rule->eq_attrib, &buf)) {
- IPAHAL_ERR("fail to generate hw rule from eq\n");
- return -EPERM;
- }
- en_rule = params->rule->eq_attrib.rule_eq_bitmap;
- } else {
- if (ipa_fltrt_generate_hw_rule_bdy(params->ipt,
- ¶ms->rule->attrib, &buf, &en_rule)) {
- IPAHAL_ERR("fail to generate hw rule\n");
- return -EPERM;
- }
- }
- rule_hdr->u.hdr.en_rule = en_rule;
- IPAHAL_DBG_LOW("en_rule=0x%x, action=%d, rt_idx=%d, retain_hdr=%d\n",
- en_rule,
- rule_hdr->u.hdr.action,
- rule_hdr->u.hdr.rt_tbl_idx,
- rule_hdr->u.hdr.retain_hdr);
- IPAHAL_DBG_LOW("priority=%d, rule_id=%d, pdn=%d, set_metadata=%d\n",
- rule_hdr->u.hdr.priority,
- rule_hdr->u.hdr.rule_id,
- rule_hdr->u.hdr.pdn_idx,
- rule_hdr->u.hdr.set_metadata);
- ipa_write_64(rule_hdr->u.word, (u8 *)rule_hdr);
- if (*hw_len == 0) {
- *hw_len = buf - start;
- } else if (*hw_len != (buf - start)) {
- IPAHAL_ERR("hw_len differs b/w passed=0x%x calc=%td\n",
- *hw_len, (buf - start));
- return -EPERM;
- }
- return 0;
- }
- /*
- * This array contains the FLT/RT info for IPAv3 and later.
- * All the information on IPAv3 are statically defined below.
- * If information is missing regarding on some IPA version,
- * the init function will fill it with the information from the previous
- * IPA version.
- * Information is considered missing if all of the fields are 0.
- */
- static struct ipahal_fltrt_obj ipahal_fltrt_objs[IPA_HW_MAX] = {
- /* IPAv3 */
- [IPA_HW_v3_0] = {
- true,
- IPA3_0_HW_TBL_WIDTH,
- IPA3_0_HW_TBL_SYSADDR_ALIGNMENT,
- IPA3_0_HW_TBL_LCLADDR_ALIGNMENT,
- IPA3_0_HW_TBL_BLK_SIZE_ALIGNMENT,
- IPA3_0_HW_RULE_START_ALIGNMENT,
- IPA3_0_HW_TBL_HDR_WIDTH,
- IPA3_0_HW_TBL_ADDR_MASK,
- IPA3_0_RULE_MAX_PRIORITY,
- IPA3_0_RULE_MIN_PRIORITY,
- IPA3_0_LOW_RULE_ID,
- IPA3_0_RULE_ID_BIT_LEN,
- IPA3_0_HW_RULE_BUF_SIZE,
- ipa_write_64,
- ipa_fltrt_create_flt_bitmap,
- ipa_fltrt_create_tbl_addr,
- ipa_fltrt_parse_tbl_addr,
- ipa_rt_gen_hw_rule,
- ipa_flt_gen_hw_rule,
- ipa_flt_generate_eq,
- ipa_rt_parse_hw_rule,
- ipa_flt_parse_hw_rule,
- {
- [IPA_TOS_EQ] = 0,
- [IPA_PROTOCOL_EQ] = 1,
- [IPA_TC_EQ] = 2,
- [IPA_OFFSET_MEQ128_0] = 3,
- [IPA_OFFSET_MEQ128_1] = 4,
- [IPA_OFFSET_MEQ32_0] = 5,
- [IPA_OFFSET_MEQ32_1] = 6,
- [IPA_IHL_OFFSET_MEQ32_0] = 7,
- [IPA_IHL_OFFSET_MEQ32_1] = 8,
- [IPA_METADATA_COMPARE] = 9,
- [IPA_IHL_OFFSET_RANGE16_0] = 10,
- [IPA_IHL_OFFSET_RANGE16_1] = 11,
- [IPA_IHL_OFFSET_EQ_32] = 12,
- [IPA_IHL_OFFSET_EQ_16] = 13,
- [IPA_FL_EQ] = 14,
- [IPA_IS_FRAG] = 15,
- [IPA_IS_PURE_ACK] = 0xFF,
- },
- },
- /* IPAv4 */
- [IPA_HW_v4_0] = {
- true,
- IPA3_0_HW_TBL_WIDTH,
- IPA3_0_HW_TBL_SYSADDR_ALIGNMENT,
- IPA3_0_HW_TBL_LCLADDR_ALIGNMENT,
- IPA3_0_HW_TBL_BLK_SIZE_ALIGNMENT,
- IPA3_0_HW_RULE_START_ALIGNMENT,
- IPA3_0_HW_TBL_HDR_WIDTH,
- IPA3_0_HW_TBL_ADDR_MASK,
- IPA3_0_RULE_MAX_PRIORITY,
- IPA3_0_RULE_MIN_PRIORITY,
- IPA3_0_LOW_RULE_ID,
- IPA3_0_RULE_ID_BIT_LEN,
- IPA3_0_HW_RULE_BUF_SIZE,
- ipa_write_64,
- ipa_fltrt_create_flt_bitmap,
- ipa_fltrt_create_tbl_addr,
- ipa_fltrt_parse_tbl_addr,
- ipa_rt_gen_hw_rule,
- ipa_flt_gen_hw_rule_ipav4,
- ipa_flt_generate_eq,
- ipa_rt_parse_hw_rule,
- ipa_flt_parse_hw_rule_ipav4,
- {
- [IPA_TOS_EQ] = 0,
- [IPA_PROTOCOL_EQ] = 1,
- [IPA_TC_EQ] = 2,
- [IPA_OFFSET_MEQ128_0] = 3,
- [IPA_OFFSET_MEQ128_1] = 4,
- [IPA_OFFSET_MEQ32_0] = 5,
- [IPA_OFFSET_MEQ32_1] = 6,
- [IPA_IHL_OFFSET_MEQ32_0] = 7,
- [IPA_IHL_OFFSET_MEQ32_1] = 8,
- [IPA_METADATA_COMPARE] = 9,
- [IPA_IHL_OFFSET_RANGE16_0] = 10,
- [IPA_IHL_OFFSET_RANGE16_1] = 11,
- [IPA_IHL_OFFSET_EQ_32] = 12,
- [IPA_IHL_OFFSET_EQ_16] = 13,
- [IPA_FL_EQ] = 14,
- [IPA_IS_FRAG] = 15,
- [IPA_IS_PURE_ACK] = 0xFF,
- },
- },
- /* IPAv4.2 */
- [IPA_HW_v4_2] = {
- false,
- IPA3_0_HW_TBL_WIDTH,
- IPA3_0_HW_TBL_SYSADDR_ALIGNMENT,
- IPA3_0_HW_TBL_LCLADDR_ALIGNMENT,
- IPA3_0_HW_TBL_BLK_SIZE_ALIGNMENT,
- IPA3_0_HW_RULE_START_ALIGNMENT,
- IPA3_0_HW_TBL_HDR_WIDTH,
- IPA3_0_HW_TBL_ADDR_MASK,
- IPA3_0_RULE_MAX_PRIORITY,
- IPA3_0_RULE_MIN_PRIORITY,
- IPA3_0_LOW_RULE_ID,
- IPA3_0_RULE_ID_BIT_LEN,
- IPA3_0_HW_RULE_BUF_SIZE,
- ipa_write_64,
- ipa_fltrt_create_flt_bitmap,
- ipa_fltrt_create_tbl_addr,
- ipa_fltrt_parse_tbl_addr,
- ipa_rt_gen_hw_rule,
- ipa_flt_gen_hw_rule_ipav4,
- ipa_flt_generate_eq,
- ipa_rt_parse_hw_rule,
- ipa_flt_parse_hw_rule_ipav4,
- {
- [IPA_TOS_EQ] = 0,
- [IPA_PROTOCOL_EQ] = 1,
- [IPA_TC_EQ] = 2,
- [IPA_OFFSET_MEQ128_0] = 3,
- [IPA_OFFSET_MEQ128_1] = 4,
- [IPA_OFFSET_MEQ32_0] = 5,
- [IPA_OFFSET_MEQ32_1] = 6,
- [IPA_IHL_OFFSET_MEQ32_0] = 7,
- [IPA_IHL_OFFSET_MEQ32_1] = 8,
- [IPA_METADATA_COMPARE] = 9,
- [IPA_IHL_OFFSET_RANGE16_0] = 10,
- [IPA_IHL_OFFSET_RANGE16_1] = 11,
- [IPA_IHL_OFFSET_EQ_32] = 12,
- [IPA_IHL_OFFSET_EQ_16] = 13,
- [IPA_FL_EQ] = 14,
- [IPA_IS_FRAG] = 15,
- [IPA_IS_PURE_ACK] = 0xFF,
- },
- },
- /* IPAv4.5 */
- [IPA_HW_v4_5] = {
- true,
- IPA3_0_HW_TBL_WIDTH,
- IPA3_0_HW_TBL_SYSADDR_ALIGNMENT,
- IPA3_0_HW_TBL_LCLADDR_ALIGNMENT,
- IPA3_0_HW_TBL_BLK_SIZE_ALIGNMENT,
- IPA3_0_HW_RULE_START_ALIGNMENT,
- IPA3_0_HW_TBL_HDR_WIDTH,
- IPA3_0_HW_TBL_ADDR_MASK,
- IPA3_0_RULE_MAX_PRIORITY,
- IPA3_0_RULE_MIN_PRIORITY,
- IPA3_0_LOW_RULE_ID,
- IPA3_0_RULE_ID_BIT_LEN,
- IPA3_0_HW_RULE_BUF_SIZE,
- ipa_write_64,
- ipa_fltrt_create_flt_bitmap,
- ipa_fltrt_create_tbl_addr,
- ipa_fltrt_parse_tbl_addr,
- ipa_rt_gen_hw_rule_ipav4_5,
- ipa_flt_gen_hw_rule_ipav4_5,
- ipa_flt_generate_eq,
- ipa_rt_parse_hw_rule_ipav4_5,
- ipa_flt_parse_hw_rule_ipav4_5,
- {
- [IPA_TOS_EQ] = 0xFF,
- [IPA_PROTOCOL_EQ] = 1,
- [IPA_TC_EQ] = 2,
- [IPA_OFFSET_MEQ128_0] = 3,
- [IPA_OFFSET_MEQ128_1] = 4,
- [IPA_OFFSET_MEQ32_0] = 5,
- [IPA_OFFSET_MEQ32_1] = 6,
- [IPA_IHL_OFFSET_MEQ32_0] = 7,
- [IPA_IHL_OFFSET_MEQ32_1] = 8,
- [IPA_METADATA_COMPARE] = 9,
- [IPA_IHL_OFFSET_RANGE16_0] = 10,
- [IPA_IHL_OFFSET_RANGE16_1] = 11,
- [IPA_IHL_OFFSET_EQ_32] = 12,
- [IPA_IHL_OFFSET_EQ_16] = 13,
- [IPA_FL_EQ] = 14,
- [IPA_IS_FRAG] = 15,
- [IPA_IS_PURE_ACK] = 0,
- },
- },
- };
- static int ipa_flt_generate_eq(enum ipa_ip_type ipt,
- const struct ipa_rule_attrib *attrib,
- struct ipa_ipfltri_rule_eq *eq_atrb)
- {
- if (ipa_fltrt_rule_generation_err_check(ipt, attrib))
- return -EPERM;
- if (ipt == IPA_IP_v4) {
- if (ipa_flt_generate_eq_ip4(ipt, attrib, eq_atrb)) {
- IPAHAL_ERR("failed to build ipv4 flt eq rule\n");
- return -EPERM;
- }
- } else if (ipt == IPA_IP_v6) {
- if (ipa_flt_generate_eq_ip6(ipt, attrib, eq_atrb)) {
- IPAHAL_ERR("failed to build ipv6 flt eq rule\n");
- return -EPERM;
- }
- } else {
- IPAHAL_ERR("unsupported ip %d\n", ipt);
- return -EPERM;
- }
- /*
- * default "rule" means no attributes set -> map to
- * OFFSET_MEQ32_0 with mask of 0 and val of 0 and offset 0
- */
- if (attrib->attrib_mask == 0) {
- eq_atrb->rule_eq_bitmap = 0;
- eq_atrb->rule_eq_bitmap |= IPA_GET_RULE_EQ_BIT_PTRN(
- IPA_OFFSET_MEQ32_0);
- eq_atrb->offset_meq_32[0].offset = 0;
- eq_atrb->offset_meq_32[0].mask = 0;
- eq_atrb->offset_meq_32[0].value = 0;
- }
- return 0;
- }
- static void ipa_fltrt_generate_mac_addr_hw_rule(u8 **extra, u8 **rest,
- u8 hdr_mac_addr_offset,
- const uint8_t mac_addr_mask[ETH_ALEN],
- const uint8_t mac_addr[ETH_ALEN])
- {
- int i;
- *extra = ipa_write_8(hdr_mac_addr_offset, *extra);
- /* LSB MASK and ADDR */
- *rest = ipa_write_64(0, *rest);
- *rest = ipa_write_64(0, *rest);
- /* MSB MASK and ADDR */
- *rest = ipa_write_16(0, *rest);
- for (i = 5; i >= 0; i--)
- *rest = ipa_write_8(mac_addr_mask[i], *rest);
- *rest = ipa_write_16(0, *rest);
- for (i = 5; i >= 0; i--)
- *rest = ipa_write_8(mac_addr[i], *rest);
- }
- static inline void ipa_fltrt_get_mac_data(const struct ipa_rule_attrib *attrib,
- uint32_t attrib_mask, u8 *offset, const uint8_t **mac_addr,
- const uint8_t **mac_addr_mask)
- {
- if (attrib_mask & IPA_FLT_MAC_DST_ADDR_ETHER_II) {
- *offset = -14;
- *mac_addr = attrib->dst_mac_addr;
- *mac_addr_mask = attrib->dst_mac_addr_mask;
- return;
- }
- if (attrib_mask & IPA_FLT_MAC_SRC_ADDR_ETHER_II) {
- *offset = -8;
- *mac_addr = attrib->src_mac_addr;
- *mac_addr_mask = attrib->src_mac_addr_mask;
- return;
- }
- if (attrib_mask & IPA_FLT_MAC_DST_ADDR_802_3) {
- *offset = -22;
- *mac_addr = attrib->dst_mac_addr;
- *mac_addr_mask = attrib->dst_mac_addr_mask;
- return;
- }
- if (attrib_mask & IPA_FLT_MAC_SRC_ADDR_802_3) {
- *offset = -16;
- *mac_addr = attrib->src_mac_addr;
- *mac_addr_mask = attrib->src_mac_addr_mask;
- return;
- }
- if (attrib_mask & IPA_FLT_MAC_DST_ADDR_802_1Q) {
- *offset = -18;
- *mac_addr = attrib->dst_mac_addr;
- *mac_addr_mask = attrib->dst_mac_addr_mask;
- return;
- }
- if (attrib_mask & IPA_FLT_MAC_SRC_ADDR_802_1Q) {
- *offset = -10;
- *mac_addr = attrib->src_mac_addr;
- *mac_addr_mask = attrib->src_mac_addr_mask;
- return;
- }
- }
- static int ipa_fltrt_generate_mac_hw_rule_bdy(u16 *en_rule,
- const struct ipa_rule_attrib *attrib,
- u8 *ofst_meq128, u8 **extra, u8 **rest)
- {
- u8 offset = 0;
- const uint8_t *mac_addr = NULL;
- const uint8_t *mac_addr_mask = NULL;
- int i;
- uint32_t attrib_mask;
- for (i = 0; i < hweight_long(IPA_MAC_FLT_BITS); i++) {
- switch (i) {
- case 0:
- attrib_mask = IPA_FLT_MAC_DST_ADDR_ETHER_II;
- break;
- case 1:
- attrib_mask = IPA_FLT_MAC_SRC_ADDR_ETHER_II;
- break;
- case 2:
- attrib_mask = IPA_FLT_MAC_DST_ADDR_802_3;
- break;
- case 3:
- attrib_mask = IPA_FLT_MAC_SRC_ADDR_802_3;
- break;
- case 4:
- attrib_mask = IPA_FLT_MAC_DST_ADDR_802_1Q;
- break;
- case 5:
- attrib_mask = IPA_FLT_MAC_SRC_ADDR_802_1Q;
- break;
- default:
- return -EPERM;
- }
- attrib_mask &= attrib->attrib_mask;
- if (!attrib_mask)
- continue;
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq128, *ofst_meq128)) {
- IPAHAL_ERR("ran out of meq128 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq128[*ofst_meq128]);
- ipa_fltrt_get_mac_data(attrib, attrib_mask, &offset,
- &mac_addr, &mac_addr_mask);
- ipa_fltrt_generate_mac_addr_hw_rule(extra, rest, offset,
- mac_addr_mask,
- mac_addr);
- (*ofst_meq128)++;
- }
- return 0;
- }
- static inline int ipa_fltrt_generate_vlan_hw_rule_bdy(u16 *en_rule,
- const struct ipa_rule_attrib *attrib,
- u8 *ofst_meq32, u8 **extra, u8 **rest)
- {
- if (attrib->attrib_mask & IPA_FLT_VLAN_ID) {
- uint32_t vlan_tag;
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, *ofst_meq32)) {
- IPAHAL_ERR("ran out of meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[*ofst_meq32]);
- /* -6 => offset of 802_1Q tag in L2 hdr */
- *extra = ipa_write_8((u8)-6, *extra);
- /* filter vlan packets: 0x8100 TPID + required VLAN ID */
- vlan_tag = (0x8100 << 16) | (attrib->vlan_id & 0xFFF);
- *rest = ipa_write_32(0xFFFF0FFF, *rest);
- *rest = ipa_write_32(vlan_tag, *rest);
- (*ofst_meq32)++;
- }
- return 0;
- }
- static int ipa_fltrt_generate_hw_rule_bdy_ip4(u16 *en_rule,
- const struct ipa_rule_attrib *attrib,
- u8 **extra_wrds, u8 **rest_wrds)
- {
- u8 *extra = *extra_wrds;
- u8 *rest = *rest_wrds;
- u8 ofst_meq32 = 0;
- u8 ihl_ofst_rng16 = 0;
- u8 ihl_ofst_meq32 = 0;
- u8 ofst_meq128 = 0;
- int rc = 0;
- bool tos_done = false;
- if (attrib->attrib_mask & IPA_FLT_IS_PURE_ACK) {
- if (!IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK)) {
- IPAHAL_ERR("is_pure_ack eq not supported\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_PURE_ACK);
- extra = ipa_write_8(0, extra);
- }
- if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) {
- if (!IPA_IS_RULE_EQ_VALID(IPA_TOS_EQ)) {
- IPAHAL_DBG("tos eq not supported\n");
- } else {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_TOS_EQ);
- extra = ipa_write_8(attrib->u.v4.tos, extra);
- tos_done = true;
- }
- }
- if (attrib->attrib_mask & IPA_FLT_PROTOCOL) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_PROTOCOL_EQ);
- extra = ipa_write_8(attrib->u.v4.protocol, extra);
- }
- if (attrib->attrib_mask & IPA_MAC_FLT_BITS) {
- if (ipa_fltrt_generate_mac_hw_rule_bdy(en_rule, attrib,
- &ofst_meq128, &extra, &rest))
- goto err;
- }
- if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
- IPAHAL_ERR("ran out of meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[ofst_meq32]);
- /* 0 => Take the first word. offset of TOS in v4 header is 1 */
- extra = ipa_write_8(0, extra);
- rest = ipa_write_32((attrib->tos_mask << 16), rest);
- rest = ipa_write_32((attrib->tos_value << 16), rest);
- ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_SRC_ADDR) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
- IPAHAL_ERR("ran out of meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[ofst_meq32]);
- /* 12 => offset of src ip in v4 header */
- extra = ipa_write_8(12, extra);
- rest = ipa_write_32(attrib->u.v4.src_addr_mask, rest);
- rest = ipa_write_32(attrib->u.v4.src_addr, rest);
- ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_DST_ADDR) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
- IPAHAL_ERR("ran out of meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[ofst_meq32]);
- /* 16 => offset of dst ip in v4 header */
- extra = ipa_write_8(16, extra);
- rest = ipa_write_32(attrib->u.v4.dst_addr_mask, rest);
- rest = ipa_write_32(attrib->u.v4.dst_addr, rest);
- ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
- IPAHAL_ERR("ran out of meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[ofst_meq32]);
- /* -2 => offset of ether type in L2 hdr */
- extra = ipa_write_8((u8)-2, extra);
- rest = ipa_write_16(0, rest);
- rest = ipa_write_16(htons(attrib->ether_type), rest);
- rest = ipa_write_16(0, rest);
- rest = ipa_write_16(htons(attrib->ether_type), rest);
- ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
- IPAHAL_DBG("ran out of meq32 eq\n");
- } else {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[ofst_meq32]);
- /*
- * 0 => Take the first word.
- * offset of TOS in v4 header is 1
- */
- extra = ipa_write_8(0, extra);
- rest = ipa_write_32(0xFF << 16, rest);
- rest = ipa_write_32((attrib->u.v4.tos << 16), rest);
- ofst_meq32++;
- tos_done = true;
- }
- }
- if (ipa_fltrt_generate_vlan_hw_rule_bdy(en_rule, attrib, &ofst_meq32,
- &extra, &rest))
- goto err;
- if (attrib->attrib_mask & IPA_FLT_TYPE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 0 => offset of type after v4 header */
- extra = ipa_write_8(0, extra);
- rest = ipa_write_32(0xFF, rest);
- rest = ipa_write_32(attrib->type, rest);
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_CODE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 1 => offset of code after v4 header */
- extra = ipa_write_8(1, extra);
- rest = ipa_write_32(0xFF, rest);
- rest = ipa_write_32(attrib->code, rest);
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_SPI) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 0 => offset of SPI after v4 header */
- extra = ipa_write_8(0, extra);
- rest = ipa_write_32(0xFFFFFFFF, rest);
- rest = ipa_write_32(attrib->spi, rest);
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_L2TP) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
- ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
- /* populate first ihl meq eq */
- extra = ipa_write_8(8, extra);
- rest = ipa_write_8(attrib->dst_mac_addr_mask[3], rest);
- rest = ipa_write_8(attrib->dst_mac_addr_mask[2], rest);
- rest = ipa_write_8(attrib->dst_mac_addr_mask[1], rest);
- rest = ipa_write_8(attrib->dst_mac_addr_mask[0], rest);
- rest = ipa_write_8(attrib->dst_mac_addr[3], rest);
- rest = ipa_write_8(attrib->dst_mac_addr[2], rest);
- rest = ipa_write_8(attrib->dst_mac_addr[1], rest);
- rest = ipa_write_8(attrib->dst_mac_addr[0], rest);
- /* populate second ihl meq eq */
- extra = ipa_write_8(12, extra);
- rest = ipa_write_16(0, rest);
- rest = ipa_write_8(attrib->dst_mac_addr_mask[5], rest);
- rest = ipa_write_8(attrib->dst_mac_addr_mask[4], rest);
- rest = ipa_write_16(0, rest);
- rest = ipa_write_8(attrib->dst_mac_addr[5], rest);
- rest = ipa_write_8(attrib->dst_mac_addr[4], rest);
- ihl_ofst_meq32 += 2;
- }
- if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 12 => offset of SYN after v4 header */
- extra = ipa_write_8(12, extra);
- rest = ipa_write_32(0x20000, rest);
- rest = ipa_write_32(0x20000, rest);
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_DBG("ran out of ihl_meq32 eq\n");
- } else {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /*
- * 0 => Take the first word. offset of TOS in
- * v4 header is 1. MSB bit asserted at IHL means
- * to ignore packet IHL and do offset inside IPA header
- */
- extra = ipa_write_8(0x80, extra);
- rest = ipa_write_32(0xFF << 16, rest);
- rest = ipa_write_32((attrib->u.v4.tos << 16), rest);
- ihl_ofst_meq32++;
- tos_done = true;
- }
- }
- if (attrib->attrib_mask & IPA_FLT_META_DATA) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_METADATA_COMPARE);
- rest = ipa_write_32(attrib->meta_data_mask, rest);
- rest = ipa_write_32(attrib->meta_data, rest);
- }
- if (attrib->attrib_mask & IPA_FLT_SRC_PORT_RANGE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- goto err;
- }
- if (attrib->src_port_hi < attrib->src_port_lo) {
- IPAHAL_ERR("bad src port range param\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- /* 0 => offset of src port after v4 header */
- extra = ipa_write_8(0, extra);
- rest = ipa_write_16(attrib->src_port_hi, rest);
- rest = ipa_write_16(attrib->src_port_lo, rest);
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_DST_PORT_RANGE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- goto err;
- }
- if (attrib->dst_port_hi < attrib->dst_port_lo) {
- IPAHAL_ERR("bad dst port range param\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- /* 2 => offset of dst port after v4 header */
- extra = ipa_write_8(2, extra);
- rest = ipa_write_16(attrib->dst_port_hi, rest);
- rest = ipa_write_16(attrib->dst_port_lo, rest);
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_SRC_PORT) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- /* 0 => offset of src port after v4 header */
- extra = ipa_write_8(0, extra);
- rest = ipa_write_16(attrib->src_port, rest);
- rest = ipa_write_16(attrib->src_port, rest);
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_DST_PORT) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- /* 2 => offset of dst port after v4 header */
- extra = ipa_write_8(2, extra);
- rest = ipa_write_16(attrib->dst_port, rest);
- rest = ipa_write_16(attrib->dst_port, rest);
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_FRAGMENT)
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_FRAG);
- if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) {
- IPAHAL_ERR("could not find equation for tos\n");
- goto err;
- }
- goto done;
- err:
- rc = -EPERM;
- done:
- *extra_wrds = extra;
- *rest_wrds = rest;
- return rc;
- }
- static int ipa_fltrt_generate_hw_rule_bdy_ip6(u16 *en_rule,
- const struct ipa_rule_attrib *attrib,
- u8 **extra_wrds, u8 **rest_wrds)
- {
- u8 *extra = *extra_wrds;
- u8 *rest = *rest_wrds;
- u8 ofst_meq32 = 0;
- u8 ihl_ofst_rng16 = 0;
- u8 ihl_ofst_meq32 = 0;
- u8 ofst_meq128 = 0;
- int rc = 0;
- /* v6 code below assumes no extension headers TODO: fix this */
- if (attrib->attrib_mask & IPA_FLT_IS_PURE_ACK) {
- if (!IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK)) {
- IPAHAL_ERR("is_pure_ack eq not supported\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_PURE_ACK);
- extra = ipa_write_8(0, extra);
- }
- if (attrib->attrib_mask & IPA_FLT_NEXT_HDR) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_PROTOCOL_EQ);
- extra = ipa_write_8(attrib->u.v6.next_hdr, extra);
- }
- if (attrib->attrib_mask & IPA_FLT_TC) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_TC_EQ);
- extra = ipa_write_8(attrib->u.v6.tc, extra);
- }
- if (attrib->attrib_mask & IPA_FLT_SRC_ADDR) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq128, ofst_meq128)) {
- IPAHAL_ERR("ran out of meq128 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq128[ofst_meq128]);
- /* 8 => offset of src ip in v6 header */
- extra = ipa_write_8(8, extra);
- rest = ipa_write_32(attrib->u.v6.src_addr_mask[3], rest);
- rest = ipa_write_32(attrib->u.v6.src_addr_mask[2], rest);
- rest = ipa_write_32(attrib->u.v6.src_addr[3], rest);
- rest = ipa_write_32(attrib->u.v6.src_addr[2], rest);
- rest = ipa_write_32(attrib->u.v6.src_addr_mask[1], rest);
- rest = ipa_write_32(attrib->u.v6.src_addr_mask[0], rest);
- rest = ipa_write_32(attrib->u.v6.src_addr[1], rest);
- rest = ipa_write_32(attrib->u.v6.src_addr[0], rest);
- ofst_meq128++;
- }
- if (attrib->attrib_mask & IPA_FLT_DST_ADDR) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq128, ofst_meq128)) {
- IPAHAL_ERR("ran out of meq128 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq128[ofst_meq128]);
- /* 24 => offset of dst ip in v6 header */
- extra = ipa_write_8(24, extra);
- rest = ipa_write_32(attrib->u.v6.dst_addr_mask[3], rest);
- rest = ipa_write_32(attrib->u.v6.dst_addr_mask[2], rest);
- rest = ipa_write_32(attrib->u.v6.dst_addr[3], rest);
- rest = ipa_write_32(attrib->u.v6.dst_addr[2], rest);
- rest = ipa_write_32(attrib->u.v6.dst_addr_mask[1], rest);
- rest = ipa_write_32(attrib->u.v6.dst_addr_mask[0], rest);
- rest = ipa_write_32(attrib->u.v6.dst_addr[1], rest);
- rest = ipa_write_32(attrib->u.v6.dst_addr[0], rest);
- ofst_meq128++;
- }
- if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq128, ofst_meq128)) {
- IPAHAL_ERR("ran out of meq128 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq128[ofst_meq128]);
- /* 0 => offset of TOS in v6 header */
- extra = ipa_write_8(0, extra);
- rest = ipa_write_64(0, rest);
- rest = ipa_write_64(0, rest);
- rest = ipa_write_32(0, rest);
- rest = ipa_write_32((attrib->tos_mask << 20), rest);
- rest = ipa_write_32(0, rest);
- rest = ipa_write_32((attrib->tos_value << 20), rest);
- ofst_meq128++;
- }
- if (attrib->attrib_mask & IPA_MAC_FLT_BITS) {
- if (ipa_fltrt_generate_mac_hw_rule_bdy(en_rule, attrib,
- &ofst_meq128, &extra, &rest))
- goto err;
- }
- if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
- IPAHAL_ERR("ran out of meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[ofst_meq32]);
- /* -2 => offset of ether type in L2 hdr */
- extra = ipa_write_8((u8)-2, extra);
- rest = ipa_write_16(0, rest);
- rest = ipa_write_16(htons(attrib->ether_type), rest);
- rest = ipa_write_16(0, rest);
- rest = ipa_write_16(htons(attrib->ether_type), rest);
- ofst_meq32++;
- }
- if (ipa_fltrt_generate_vlan_hw_rule_bdy(en_rule, attrib, &ofst_meq32,
- &extra, &rest))
- goto err;
- if (attrib->attrib_mask & IPA_FLT_TYPE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 0 => offset of type after v6 header */
- extra = ipa_write_8(0, extra);
- rest = ipa_write_32(0xFF, rest);
- rest = ipa_write_32(attrib->type, rest);
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_CODE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 1 => offset of code after v6 header */
- extra = ipa_write_8(1, extra);
- rest = ipa_write_32(0xFF, rest);
- rest = ipa_write_32(attrib->code, rest);
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_SPI) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 0 => offset of SPI after v6 header FIXME */
- extra = ipa_write_8(0, extra);
- rest = ipa_write_32(0xFFFFFFFF, rest);
- rest = ipa_write_32(attrib->spi, rest);
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_L2TP) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
- ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
- /* populate first ihl meq eq */
- extra = ipa_write_8(8, extra);
- rest = ipa_write_8(attrib->dst_mac_addr_mask[3], rest);
- rest = ipa_write_8(attrib->dst_mac_addr_mask[2], rest);
- rest = ipa_write_8(attrib->dst_mac_addr_mask[1], rest);
- rest = ipa_write_8(attrib->dst_mac_addr_mask[0], rest);
- rest = ipa_write_8(attrib->dst_mac_addr[3], rest);
- rest = ipa_write_8(attrib->dst_mac_addr[2], rest);
- rest = ipa_write_8(attrib->dst_mac_addr[1], rest);
- rest = ipa_write_8(attrib->dst_mac_addr[0], rest);
- /* populate second ihl meq eq */
- extra = ipa_write_8(12, extra);
- rest = ipa_write_16(0, rest);
- rest = ipa_write_8(attrib->dst_mac_addr_mask[5], rest);
- rest = ipa_write_8(attrib->dst_mac_addr_mask[4], rest);
- rest = ipa_write_16(0, rest);
- rest = ipa_write_8(attrib->dst_mac_addr[5], rest);
- rest = ipa_write_8(attrib->dst_mac_addr[4], rest);
- ihl_ofst_meq32 += 2;
- }
- if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 12 => offset of SYN after v4 header */
- extra = ipa_write_8(12, extra);
- rest = ipa_write_32(0x20000, rest);
- rest = ipa_write_32(0x20000, rest);
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
- ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
- /* populate TCP protocol eq */
- if (attrib->ether_type == 0x0800) {
- extra = ipa_write_8(30, extra);
- rest = ipa_write_32(0xFF0000, rest);
- rest = ipa_write_32(0x60000, rest);
- } else {
- extra = ipa_write_8(26, extra);
- rest = ipa_write_32(0xFF00, rest);
- rest = ipa_write_32(0x600, rest);
- }
- /* populate TCP SYN eq */
- if (attrib->ether_type == 0x0800) {
- extra = ipa_write_8(54, extra);
- rest = ipa_write_32(0x20000, rest);
- rest = ipa_write_32(0x20000, rest);
- } else {
- extra = ipa_write_8(74, extra);
- rest = ipa_write_32(0x20000, rest);
- rest = ipa_write_32(0x20000, rest);
- }
- ihl_ofst_meq32 += 2;
- }
- if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IP_TYPE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 22 => offset of IP type after v6 header */
- extra = ipa_write_8(22, extra);
- rest = ipa_write_32(0xF0000000, rest);
- if (attrib->type == 0x40)
- rest = ipa_write_32(0x40000000, rest);
- else
- rest = ipa_write_32(0x60000000, rest);
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IPV4_DST_ADDR) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 38 => offset of inner IPv4 addr */
- extra = ipa_write_8(38, extra);
- rest = ipa_write_32(attrib->u.v4.dst_addr_mask, rest);
- rest = ipa_write_32(attrib->u.v4.dst_addr, rest);
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_META_DATA) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_METADATA_COMPARE);
- rest = ipa_write_32(attrib->meta_data_mask, rest);
- rest = ipa_write_32(attrib->meta_data, rest);
- }
- if (attrib->attrib_mask & IPA_FLT_SRC_PORT) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- /* 0 => offset of src port after v6 header */
- extra = ipa_write_8(0, extra);
- rest = ipa_write_16(attrib->src_port, rest);
- rest = ipa_write_16(attrib->src_port, rest);
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_DST_PORT) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- /* 2 => offset of dst port after v6 header */
- extra = ipa_write_8(2, extra);
- rest = ipa_write_16(attrib->dst_port, rest);
- rest = ipa_write_16(attrib->dst_port, rest);
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_SRC_PORT_RANGE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- goto err;
- }
- if (attrib->src_port_hi < attrib->src_port_lo) {
- IPAHAL_ERR("bad src port range param\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- /* 0 => offset of src port after v6 header */
- extra = ipa_write_8(0, extra);
- rest = ipa_write_16(attrib->src_port_hi, rest);
- rest = ipa_write_16(attrib->src_port_lo, rest);
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_DST_PORT_RANGE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- goto err;
- }
- if (attrib->dst_port_hi < attrib->dst_port_lo) {
- IPAHAL_ERR("bad dst port range param\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- /* 2 => offset of dst port after v6 header */
- extra = ipa_write_8(2, extra);
- rest = ipa_write_16(attrib->dst_port_hi, rest);
- rest = ipa_write_16(attrib->dst_port_lo, rest);
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- goto err;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- /* 20 => offset of Ethertype after v4 header */
- if (attrib->ether_type == 0x0800) {
- extra = ipa_write_8(21, extra);
- rest = ipa_write_16(0x0045, rest);
- rest = ipa_write_16(0x0045, rest);
- } else {
- extra = ipa_write_8(20, extra);
- rest = ipa_write_16(attrib->ether_type, rest);
- rest = ipa_write_16(attrib->ether_type, rest);
- }
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_FLOW_LABEL) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_FL_EQ);
- rest = ipa_write_32(attrib->u.v6.flow_label & 0xFFFFF,
- rest);
- }
- if (attrib->attrib_mask & IPA_FLT_FRAGMENT)
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_FRAG);
- goto done;
- err:
- rc = -EPERM;
- done:
- *extra_wrds = extra;
- *rest_wrds = rest;
- return rc;
- }
- static u8 *ipa_fltrt_copy_mem(u8 *src, u8 *dst, int cnt)
- {
- while (cnt--)
- *dst++ = *src++;
- return dst;
- }
- /*
- * ipa_fltrt_generate_hw_rule_bdy() - generate HW rule body (w/o header)
- * @ip: IP address type
- * @attrib: IPA rule attribute
- * @buf: output buffer. Advance it after building the rule
- * @en_rule: enable rule
- *
- * Return codes:
- * 0: success
- * -EPERM: wrong input
- */
- static int ipa_fltrt_generate_hw_rule_bdy(enum ipa_ip_type ipt,
- const struct ipa_rule_attrib *attrib, u8 **buf, u16 *en_rule)
- {
- int sz;
- int rc = 0;
- u8 *extra_wrd_buf;
- u8 *rest_wrd_buf;
- u8 *extra_wrd_start;
- u8 *rest_wrd_start;
- u8 *extra_wrd_i;
- u8 *rest_wrd_i;
- sz = IPA3_0_HW_TBL_WIDTH * 2 + IPA3_0_HW_RULE_START_ALIGNMENT;
- extra_wrd_buf = kzalloc(sz, GFP_KERNEL);
- if (!extra_wrd_buf) {
- rc = -ENOMEM;
- goto fail_extra_alloc;
- }
- sz = IPA3_0_HW_RULE_BUF_SIZE + IPA3_0_HW_RULE_START_ALIGNMENT;
- rest_wrd_buf = kzalloc(sz, GFP_KERNEL);
- if (!rest_wrd_buf) {
- rc = -ENOMEM;
- goto fail_rest_alloc;
- }
- extra_wrd_start = extra_wrd_buf + IPA3_0_HW_RULE_START_ALIGNMENT;
- extra_wrd_start = (u8 *)((long)extra_wrd_start &
- ~IPA3_0_HW_RULE_START_ALIGNMENT);
- rest_wrd_start = rest_wrd_buf + IPA3_0_HW_RULE_START_ALIGNMENT;
- rest_wrd_start = (u8 *)((long)rest_wrd_start &
- ~IPA3_0_HW_RULE_START_ALIGNMENT);
- extra_wrd_i = extra_wrd_start;
- rest_wrd_i = rest_wrd_start;
- rc = ipa_fltrt_rule_generation_err_check(ipt, attrib);
- if (rc) {
- IPAHAL_ERR_RL("rule generation err check failed\n");
- goto fail_err_check;
- }
- if (ipt == IPA_IP_v4) {
- if (ipa_fltrt_generate_hw_rule_bdy_ip4(en_rule, attrib,
- &extra_wrd_i, &rest_wrd_i)) {
- IPAHAL_ERR_RL("failed to build ipv4 hw rule\n");
- rc = -EPERM;
- goto fail_err_check;
- }
- } else if (ipt == IPA_IP_v6) {
- if (ipa_fltrt_generate_hw_rule_bdy_ip6(en_rule, attrib,
- &extra_wrd_i, &rest_wrd_i)) {
- IPAHAL_ERR_RL("failed to build ipv6 hw rule\n");
- rc = -EPERM;
- goto fail_err_check;
- }
- } else {
- IPAHAL_ERR_RL("unsupported ip %d\n", ipt);
- goto fail_err_check;
- }
- /*
- * default "rule" means no attributes set -> map to
- * OFFSET_MEQ32_0 with mask of 0 and val of 0 and offset 0
- */
- if (attrib->attrib_mask == 0) {
- IPAHAL_DBG_LOW("building default rule\n");
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(ipa3_0_ofst_meq32[0]);
- extra_wrd_i = ipa_write_8(0, extra_wrd_i); /* offset */
- rest_wrd_i = ipa_write_32(0, rest_wrd_i); /* mask */
- rest_wrd_i = ipa_write_32(0, rest_wrd_i); /* val */
- }
- IPAHAL_DBG_LOW("extra_word_1 0x%llx\n", *(u64 *)extra_wrd_start);
- IPAHAL_DBG_LOW("extra_word_2 0x%llx\n",
- *(u64 *)(extra_wrd_start + IPA3_0_HW_TBL_WIDTH));
- extra_wrd_i = ipa_pad_to_64(extra_wrd_i);
- sz = extra_wrd_i - extra_wrd_start;
- IPAHAL_DBG_LOW("extra words params sz %d\n", sz);
- *buf = ipa_fltrt_copy_mem(extra_wrd_start, *buf, sz);
- rest_wrd_i = ipa_pad_to_64(rest_wrd_i);
- sz = rest_wrd_i - rest_wrd_start;
- IPAHAL_DBG_LOW("non extra words params sz %d\n", sz);
- *buf = ipa_fltrt_copy_mem(rest_wrd_start, *buf, sz);
- fail_err_check:
- kfree(rest_wrd_buf);
- fail_rest_alloc:
- kfree(extra_wrd_buf);
- fail_extra_alloc:
- return rc;
- }
- /**
- * ipa_fltrt_calc_extra_wrd_bytes()- Calculate the number of extra words for eq
- * @attrib: equation attribute
- *
- * Return value: 0 on success, negative otherwise
- */
- static int ipa_fltrt_calc_extra_wrd_bytes(
- const struct ipa_ipfltri_rule_eq *attrib)
- {
- int num = 0;
- /*
- * tos_eq_present field has two meanings:
- * tos equation for IPA ver < 4.5 (as the field name reveals)
- * pure_ack equation for IPA ver >= 4.5
- * In both cases it needs one extra word.
- */
- if (attrib->tos_eq_present)
- num++;
- if (attrib->protocol_eq_present)
- num++;
- if (attrib->tc_eq_present)
- num++;
- num += attrib->num_offset_meq_128;
- num += attrib->num_offset_meq_32;
- num += attrib->num_ihl_offset_meq_32;
- num += attrib->num_ihl_offset_range_16;
- if (attrib->ihl_offset_eq_32_present)
- num++;
- if (attrib->ihl_offset_eq_16_present)
- num++;
- IPAHAL_DBG_LOW("extra bytes number %d\n", num);
- return num;
- }
- static int ipa_fltrt_generate_hw_rule_bdy_from_eq(
- const struct ipa_ipfltri_rule_eq *attrib, u8 **buf)
- {
- uint8_t num_offset_meq_32 = attrib->num_offset_meq_32;
- uint8_t num_ihl_offset_range_16 = attrib->num_ihl_offset_range_16;
- uint8_t num_ihl_offset_meq_32 = attrib->num_ihl_offset_meq_32;
- uint8_t num_offset_meq_128 = attrib->num_offset_meq_128;
- int i;
- int extra_bytes;
- u8 *extra;
- u8 *rest;
- extra_bytes = ipa_fltrt_calc_extra_wrd_bytes(attrib);
- /* only 3 eq does not have extra word param, 13 out of 16 is the number
- * of equations that needs extra word param
- */
- if (extra_bytes > 13) {
- IPAHAL_ERR_RL("too much extra bytes\n");
- return -EPERM;
- } else if (extra_bytes > IPA3_0_HW_TBL_HDR_WIDTH) {
- /* two extra words */
- extra = *buf;
- rest = *buf + IPA3_0_HW_TBL_HDR_WIDTH * 2;
- } else if (extra_bytes > 0) {
- /* single exra word */
- extra = *buf;
- rest = *buf + IPA3_0_HW_TBL_HDR_WIDTH;
- } else {
- /* no extra words */
- extra = NULL;
- rest = *buf;
- }
- /*
- * tos_eq_present field has two meanings:
- * tos equation for IPA ver < 4.5 (as the field name reveals)
- * pure_ack equation for IPA ver >= 4.5
- * In both cases it needs one extra word.
- */
- if (attrib->tos_eq_present) {
- if (IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK)) {
- extra = ipa_write_8(0, extra);
- } else if (IPA_IS_RULE_EQ_VALID(IPA_TOS_EQ)) {
- extra = ipa_write_8(attrib->tos_eq, extra);
- } else {
- IPAHAL_ERR("no support for pure_ack and tos eqs\n");
- return -EPERM;
- }
- }
- if (attrib->protocol_eq_present)
- extra = ipa_write_8(attrib->protocol_eq, extra);
- if (attrib->tc_eq_present)
- extra = ipa_write_8(attrib->tc_eq, extra);
- if (num_offset_meq_128) {
- extra = ipa_write_8(attrib->offset_meq_128[0].offset, extra);
- for (i = 0; i < 8; i++)
- rest = ipa_write_8(attrib->offset_meq_128[0].mask[i],
- rest);
- for (i = 0; i < 8; i++)
- rest = ipa_write_8(attrib->offset_meq_128[0].value[i],
- rest);
- for (i = 8; i < 16; i++)
- rest = ipa_write_8(attrib->offset_meq_128[0].mask[i],
- rest);
- for (i = 8; i < 16; i++)
- rest = ipa_write_8(attrib->offset_meq_128[0].value[i],
- rest);
- num_offset_meq_128--;
- }
- if (num_offset_meq_128) {
- extra = ipa_write_8(attrib->offset_meq_128[1].offset, extra);
- for (i = 0; i < 8; i++)
- rest = ipa_write_8(attrib->offset_meq_128[1].mask[i],
- rest);
- for (i = 0; i < 8; i++)
- rest = ipa_write_8(attrib->offset_meq_128[1].value[i],
- rest);
- for (i = 8; i < 16; i++)
- rest = ipa_write_8(attrib->offset_meq_128[1].mask[i],
- rest);
- for (i = 8; i < 16; i++)
- rest = ipa_write_8(attrib->offset_meq_128[1].value[i],
- rest);
- num_offset_meq_128--;
- }
- if (num_offset_meq_32) {
- extra = ipa_write_8(attrib->offset_meq_32[0].offset, extra);
- rest = ipa_write_32(attrib->offset_meq_32[0].mask, rest);
- rest = ipa_write_32(attrib->offset_meq_32[0].value, rest);
- num_offset_meq_32--;
- }
- if (num_offset_meq_32) {
- extra = ipa_write_8(attrib->offset_meq_32[1].offset, extra);
- rest = ipa_write_32(attrib->offset_meq_32[1].mask, rest);
- rest = ipa_write_32(attrib->offset_meq_32[1].value, rest);
- num_offset_meq_32--;
- }
- if (num_ihl_offset_meq_32) {
- extra = ipa_write_8(attrib->ihl_offset_meq_32[0].offset,
- extra);
- rest = ipa_write_32(attrib->ihl_offset_meq_32[0].mask, rest);
- rest = ipa_write_32(attrib->ihl_offset_meq_32[0].value, rest);
- num_ihl_offset_meq_32--;
- }
- if (num_ihl_offset_meq_32) {
- extra = ipa_write_8(attrib->ihl_offset_meq_32[1].offset,
- extra);
- rest = ipa_write_32(attrib->ihl_offset_meq_32[1].mask, rest);
- rest = ipa_write_32(attrib->ihl_offset_meq_32[1].value, rest);
- num_ihl_offset_meq_32--;
- }
- if (attrib->metadata_meq32_present) {
- rest = ipa_write_32(attrib->metadata_meq32.mask, rest);
- rest = ipa_write_32(attrib->metadata_meq32.value, rest);
- }
- if (num_ihl_offset_range_16) {
- extra = ipa_write_8(attrib->ihl_offset_range_16[0].offset,
- extra);
- rest = ipa_write_16(attrib->ihl_offset_range_16[0].range_high,
- rest);
- rest = ipa_write_16(attrib->ihl_offset_range_16[0].range_low,
- rest);
- num_ihl_offset_range_16--;
- }
- if (num_ihl_offset_range_16) {
- extra = ipa_write_8(attrib->ihl_offset_range_16[1].offset,
- extra);
- rest = ipa_write_16(attrib->ihl_offset_range_16[1].range_high,
- rest);
- rest = ipa_write_16(attrib->ihl_offset_range_16[1].range_low,
- rest);
- num_ihl_offset_range_16--;
- }
- if (attrib->ihl_offset_eq_32_present) {
- extra = ipa_write_8(attrib->ihl_offset_eq_32.offset, extra);
- rest = ipa_write_32(attrib->ihl_offset_eq_32.value, rest);
- }
- if (attrib->ihl_offset_eq_16_present) {
- extra = ipa_write_8(attrib->ihl_offset_eq_16.offset, extra);
- rest = ipa_write_16(attrib->ihl_offset_eq_16.value, rest);
- rest = ipa_write_16(0, rest);
- }
- if (attrib->fl_eq_present)
- rest = ipa_write_32(attrib->fl_eq & 0xFFFFF, rest);
- if (extra)
- extra = ipa_pad_to_64(extra);
- rest = ipa_pad_to_64(rest);
- *buf = rest;
- return 0;
- }
- static void ipa_flt_generate_mac_addr_eq(struct ipa_ipfltri_rule_eq *eq_atrb,
- u8 hdr_mac_addr_offset, const uint8_t mac_addr_mask[ETH_ALEN],
- const uint8_t mac_addr[ETH_ALEN], u8 ofst_meq128)
- {
- int i;
- eq_atrb->offset_meq_128[ofst_meq128].offset = hdr_mac_addr_offset;
- /* LSB MASK and ADDR */
- memset(eq_atrb->offset_meq_128[ofst_meq128].mask, 0, 8);
- memset(eq_atrb->offset_meq_128[ofst_meq128].value, 0, 8);
- /* MSB MASK and ADDR */
- memset(eq_atrb->offset_meq_128[ofst_meq128].mask + 8, 0, 2);
- for (i = 0; i <= 5; i++)
- eq_atrb->offset_meq_128[ofst_meq128].mask[15 - i] =
- mac_addr_mask[i];
- memset(eq_atrb->offset_meq_128[ofst_meq128].value + 8, 0, 2);
- for (i = 0; i <= 5; i++)
- eq_atrb->offset_meq_128[ofst_meq128].value[15 - i] =
- mac_addr[i];
- }
- static int ipa_flt_generate_mac_eq(
- const struct ipa_rule_attrib *attrib, u16 *en_rule, u8 *ofst_meq128,
- struct ipa_ipfltri_rule_eq *eq_atrb)
- {
- u8 offset = 0;
- const uint8_t *mac_addr = NULL;
- const uint8_t *mac_addr_mask = NULL;
- int i;
- uint32_t attrib_mask;
- for (i = 0; i < hweight_long(IPA_MAC_FLT_BITS); i++) {
- switch (i) {
- case 0:
- attrib_mask = IPA_FLT_MAC_DST_ADDR_ETHER_II;
- break;
- case 1:
- attrib_mask = IPA_FLT_MAC_SRC_ADDR_ETHER_II;
- break;
- case 2:
- attrib_mask = IPA_FLT_MAC_DST_ADDR_802_3;
- break;
- case 3:
- attrib_mask = IPA_FLT_MAC_SRC_ADDR_802_3;
- break;
- case 4:
- attrib_mask = IPA_FLT_MAC_DST_ADDR_802_1Q;
- break;
- case 5:
- attrib_mask = IPA_FLT_MAC_SRC_ADDR_802_1Q;
- break;
- default:
- return -EPERM;
- }
- attrib_mask &= attrib->attrib_mask;
- if (!attrib_mask)
- continue;
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq128, *ofst_meq128)) {
- IPAHAL_ERR("ran out of meq128 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq128[*ofst_meq128]);
- ipa_fltrt_get_mac_data(attrib, attrib_mask, &offset,
- &mac_addr, &mac_addr_mask);
- ipa_flt_generate_mac_addr_eq(eq_atrb, offset,
- mac_addr_mask, mac_addr,
- *ofst_meq128);
- (*ofst_meq128)++;
- }
- return 0;
- }
- static inline int ipa_flt_generat_vlan_eq(
- const struct ipa_rule_attrib *attrib, u16 *en_rule, u8 *ofst_meq32,
- struct ipa_ipfltri_rule_eq *eq_atrb)
- {
- if (attrib->attrib_mask & IPA_FLT_VLAN_ID) {
- uint32_t vlan_tag;
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, *ofst_meq32)) {
- IPAHAL_ERR("ran out of meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[*ofst_meq32]);
- /* -6 => offset of 802_1Q tag in L2 hdr */
- eq_atrb->offset_meq_32[*ofst_meq32].offset = -6;
- /* filter vlan packets: 0x8100 TPID + required VLAN ID */
- vlan_tag = (0x8100 << 16) | (attrib->vlan_id & 0xFFF);
- eq_atrb->offset_meq_32[*ofst_meq32].mask = 0xFFFF0FFF;
- eq_atrb->offset_meq_32[*ofst_meq32].value = vlan_tag;
- (*ofst_meq32)++;
- }
- return 0;
- }
- static int ipa_flt_generate_eq_ip4(enum ipa_ip_type ip,
- const struct ipa_rule_attrib *attrib,
- struct ipa_ipfltri_rule_eq *eq_atrb)
- {
- u8 ofst_meq32 = 0;
- u8 ihl_ofst_rng16 = 0;
- u8 ihl_ofst_meq32 = 0;
- u8 ofst_meq128 = 0;
- u16 eq_bitmap = 0;
- u16 *en_rule = &eq_bitmap;
- bool tos_done = false;
- if (attrib->attrib_mask & IPA_FLT_IS_PURE_ACK) {
- if (!IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK)) {
- IPAHAL_ERR("is_pure_ack eq not supported\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_PURE_ACK);
- /*
- * Starting IPA 4.5, where PURE ACK equation supported
- * and TOS equation support removed, field tos_eq_present
- * represent pure_ack presence.
- */
- eq_atrb->tos_eq_present = 1;
- eq_atrb->tos_eq = 0;
- }
- if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) {
- if (!IPA_IS_RULE_EQ_VALID(IPA_TOS_EQ)) {
- IPAHAL_DBG("tos eq not supported\n");
- } else {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_TOS_EQ);
- eq_atrb->tos_eq_present = 1;
- eq_atrb->tos_eq = attrib->u.v4.tos;
- }
- }
- if (attrib->attrib_mask & IPA_FLT_PROTOCOL) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_PROTOCOL_EQ);
- eq_atrb->protocol_eq_present = 1;
- eq_atrb->protocol_eq = attrib->u.v4.protocol;
- }
- if (attrib->attrib_mask & IPA_MAC_FLT_BITS) {
- if (ipa_flt_generate_mac_eq(attrib, en_rule,
- &ofst_meq128, eq_atrb))
- return -EPERM;
- }
- if (attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_L2TP) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
- ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
- /* populate the first ihl meq 32 eq */
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 8;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
- (attrib->dst_mac_addr_mask[3] & 0xFF) |
- ((attrib->dst_mac_addr_mask[2] << 8) & 0xFF00) |
- ((attrib->dst_mac_addr_mask[1] << 16) & 0xFF0000) |
- ((attrib->dst_mac_addr_mask[0] << 24) & 0xFF000000);
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- (attrib->dst_mac_addr[3] & 0xFF) |
- ((attrib->dst_mac_addr[2] << 8) & 0xFF00) |
- ((attrib->dst_mac_addr[1] << 16) & 0xFF0000) |
- ((attrib->dst_mac_addr[0] << 24) & 0xFF000000);
- /* populate the second ihl meq 32 eq */
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32 + 1].offset = 12;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32 + 1].mask =
- ((attrib->dst_mac_addr_mask[5] << 16) & 0xFF0000) |
- ((attrib->dst_mac_addr_mask[4] << 24) & 0xFF000000);
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32 + 1].value =
- ((attrib->dst_mac_addr[5] << 16) & 0xFF0000) |
- ((attrib->dst_mac_addr[4] << 24) & 0xFF000000);
- ihl_ofst_meq32 += 2;
- }
- if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 12 => offset of SYN after v4 header */
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 12;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = 0x20000;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value = 0x20000;
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
- IPAHAL_ERR("ran out of meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[ofst_meq32]);
- eq_atrb->offset_meq_32[ofst_meq32].offset = 0;
- eq_atrb->offset_meq_32[ofst_meq32].mask =
- attrib->tos_mask << 16;
- eq_atrb->offset_meq_32[ofst_meq32].value =
- attrib->tos_value << 16;
- ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_SRC_ADDR) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
- IPAHAL_ERR("ran out of meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[ofst_meq32]);
- eq_atrb->offset_meq_32[ofst_meq32].offset = 12;
- eq_atrb->offset_meq_32[ofst_meq32].mask =
- attrib->u.v4.src_addr_mask;
- eq_atrb->offset_meq_32[ofst_meq32].value =
- attrib->u.v4.src_addr;
- ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_DST_ADDR) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
- IPAHAL_ERR("ran out of meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[ofst_meq32]);
- eq_atrb->offset_meq_32[ofst_meq32].offset = 16;
- eq_atrb->offset_meq_32[ofst_meq32].mask =
- attrib->u.v4.dst_addr_mask;
- eq_atrb->offset_meq_32[ofst_meq32].value =
- attrib->u.v4.dst_addr;
- ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
- IPAHAL_ERR("ran out of meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[ofst_meq32]);
- eq_atrb->offset_meq_32[ofst_meq32].offset = -2;
- eq_atrb->offset_meq_32[ofst_meq32].mask =
- htons(attrib->ether_type);
- eq_atrb->offset_meq_32[ofst_meq32].value =
- htons(attrib->ether_type);
- ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
- IPAHAL_DBG("ran out of meq32 eq\n");
- } else {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[ofst_meq32]);
- /*
- * offset 0 => Take the first word.
- * offset of TOS in v4 header is 1
- */
- eq_atrb->offset_meq_32[ofst_meq32].offset = 0;
- eq_atrb->offset_meq_32[ofst_meq32].mask =
- 0xFF << 16;
- eq_atrb->offset_meq_32[ofst_meq32].value =
- attrib->u.v4.tos << 16;
- ofst_meq32++;
- tos_done = true;
- }
- }
- if (ipa_flt_generat_vlan_eq(attrib, en_rule, &ofst_meq32, eq_atrb))
- return -EPERM;
- if (attrib->attrib_mask & IPA_FLT_TYPE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 0;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = 0xFF;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- attrib->type;
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_CODE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 1;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = 0xFF;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- attrib->code;
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_SPI) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 0;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
- 0xFFFFFFFF;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- attrib->spi;
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_DBG("ran out of ihl_meq32 eq\n");
- } else {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /*
- * 0 => Take the first word. offset of TOS in
- * v4 header is 1. MSB bit asserted at IHL means
- * to ignore packet IHL and do offset inside IPA header
- */
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset =
- 0x80;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
- 0xFF << 16;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- attrib->u.v4.tos << 16;
- ihl_ofst_meq32++;
- tos_done = true;
- }
- }
- if (attrib->attrib_mask & IPA_FLT_META_DATA) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- IPA_METADATA_COMPARE);
- eq_atrb->metadata_meq32_present = 1;
- eq_atrb->metadata_meq32.offset = 0;
- eq_atrb->metadata_meq32.mask = attrib->meta_data_mask;
- eq_atrb->metadata_meq32.value = attrib->meta_data;
- }
- if (attrib->attrib_mask & IPA_FLT_SRC_PORT_RANGE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- return -EPERM;
- }
- if (attrib->src_port_hi < attrib->src_port_lo) {
- IPAHAL_ERR("bad src port range param\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset = 0;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
- = attrib->src_port_lo;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
- = attrib->src_port_hi;
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_DST_PORT_RANGE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- return -EPERM;
- }
- if (attrib->dst_port_hi < attrib->dst_port_lo) {
- IPAHAL_ERR("bad dst port range param\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset = 2;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
- = attrib->dst_port_lo;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
- = attrib->dst_port_hi;
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_SRC_PORT) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset = 0;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
- = attrib->src_port;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
- = attrib->src_port;
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_DST_PORT) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset = 2;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
- = attrib->dst_port;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
- = attrib->dst_port;
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_FRAGMENT) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_FRAG);
- eq_atrb->ipv4_frag_eq_present = 1;
- }
- if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) {
- IPAHAL_ERR("could not find equation for tos\n");
- return -EPERM;
- }
- eq_atrb->rule_eq_bitmap = *en_rule;
- eq_atrb->num_offset_meq_32 = ofst_meq32;
- eq_atrb->num_ihl_offset_range_16 = ihl_ofst_rng16;
- eq_atrb->num_ihl_offset_meq_32 = ihl_ofst_meq32;
- eq_atrb->num_offset_meq_128 = ofst_meq128;
- return 0;
- }
- static int ipa_flt_generate_eq_ip6(enum ipa_ip_type ip,
- const struct ipa_rule_attrib *attrib,
- struct ipa_ipfltri_rule_eq *eq_atrb)
- {
- u8 ofst_meq32 = 0;
- u8 ihl_ofst_rng16 = 0;
- u8 ihl_ofst_meq32 = 0;
- u8 ofst_meq128 = 0;
- u16 eq_bitmap = 0;
- u16 *en_rule = &eq_bitmap;
- if (attrib->attrib_mask & IPA_FLT_IS_PURE_ACK) {
- if (!IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK)) {
- IPAHAL_ERR("is_pure_ack eq not supported\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_PURE_ACK);
- /*
- * Starting IPA 4.5, where PURE ACK equation supported
- * and TOS equation support removed, field tos_eq_present
- * represent pure_ack presenence.
- */
- eq_atrb->tos_eq_present = 1;
- eq_atrb->tos_eq = 0;
- }
- if (attrib->attrib_mask & IPA_FLT_NEXT_HDR) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- IPA_PROTOCOL_EQ);
- eq_atrb->protocol_eq_present = 1;
- eq_atrb->protocol_eq = attrib->u.v6.next_hdr;
- }
- if (attrib->attrib_mask & IPA_FLT_TC) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- IPA_TC_EQ);
- eq_atrb->tc_eq_present = 1;
- eq_atrb->tc_eq = attrib->u.v6.tc;
- }
- if (attrib->attrib_mask & IPA_FLT_SRC_ADDR) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq128, ofst_meq128)) {
- IPAHAL_ERR_RL("ran out of meq128 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq128[ofst_meq128]);
- /* use the same word order as in ipa v2 */
- eq_atrb->offset_meq_128[ofst_meq128].offset = 8;
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].mask + 0)
- = attrib->u.v6.src_addr_mask[0];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].mask + 4)
- = attrib->u.v6.src_addr_mask[1];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].mask + 8)
- = attrib->u.v6.src_addr_mask[2];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].mask + 12)
- = attrib->u.v6.src_addr_mask[3];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].value + 0)
- = attrib->u.v6.src_addr[0];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].value + 4)
- = attrib->u.v6.src_addr[1];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].value + 8)
- = attrib->u.v6.src_addr[2];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].value +
- 12) = attrib->u.v6.src_addr[3];
- ofst_meq128++;
- }
- if (attrib->attrib_mask & IPA_FLT_DST_ADDR) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq128, ofst_meq128)) {
- IPAHAL_ERR_RL("ran out of meq128 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq128[ofst_meq128]);
- eq_atrb->offset_meq_128[ofst_meq128].offset = 24;
- /* use the same word order as in ipa v2 */
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].mask + 0)
- = attrib->u.v6.dst_addr_mask[0];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].mask + 4)
- = attrib->u.v6.dst_addr_mask[1];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].mask + 8)
- = attrib->u.v6.dst_addr_mask[2];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].mask + 12)
- = attrib->u.v6.dst_addr_mask[3];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].value + 0)
- = attrib->u.v6.dst_addr[0];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].value + 4)
- = attrib->u.v6.dst_addr[1];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].value + 8)
- = attrib->u.v6.dst_addr[2];
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].value +
- 12) = attrib->u.v6.dst_addr[3];
- ofst_meq128++;
- }
- if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq128, ofst_meq128)) {
- IPAHAL_ERR_RL("ran out of meq128 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq128[ofst_meq128]);
- eq_atrb->offset_meq_128[ofst_meq128].offset = 0;
- memset(eq_atrb->offset_meq_128[ofst_meq128].mask, 0, 12);
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].mask + 12)
- = attrib->tos_mask << 20;
- memset(eq_atrb->offset_meq_128[ofst_meq128].value, 0, 12);
- *(u32 *)(eq_atrb->offset_meq_128[ofst_meq128].value +
- 12) = attrib->tos_value << 20;
- ofst_meq128++;
- }
- if (attrib->attrib_mask & IPA_MAC_FLT_BITS) {
- if (ipa_flt_generate_mac_eq(attrib, en_rule,
- &ofst_meq128, eq_atrb))
- return -EPERM;
- }
- if (attrib->attrib_mask & IPA_FLT_MAC_DST_ADDR_L2TP) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
- ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
- IPAHAL_ERR_RL("ran out of ihl_meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
- /* populate the first ihl meq 32 eq */
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 8;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
- (attrib->dst_mac_addr_mask[3] & 0xFF) |
- ((attrib->dst_mac_addr_mask[2] << 8) & 0xFF00) |
- ((attrib->dst_mac_addr_mask[1] << 16) & 0xFF0000) |
- ((attrib->dst_mac_addr_mask[0] << 24) & 0xFF000000);
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- (attrib->dst_mac_addr[3] & 0xFF) |
- ((attrib->dst_mac_addr[2] << 8) & 0xFF00) |
- ((attrib->dst_mac_addr[1] << 16) & 0xFF0000) |
- ((attrib->dst_mac_addr[0] << 24) & 0xFF000000);
- /* populate the second ihl meq 32 eq */
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32 + 1].offset = 12;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32 + 1].mask =
- ((attrib->dst_mac_addr_mask[5] << 16) & 0xFF0000) |
- ((attrib->dst_mac_addr_mask[4] << 24) & 0xFF000000);
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32 + 1].value =
- ((attrib->dst_mac_addr[5] << 16) & 0xFF0000) |
- ((attrib->dst_mac_addr[4] << 24) & 0xFF000000);
- ihl_ofst_meq32 += 2;
- }
- if (attrib->attrib_mask & IPA_FLT_TCP_SYN) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR_RL("ran out of ihl_meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 12 => offset of SYN after v4 header */
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 12;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = 0x20000;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value = 0x20000;
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32) || IPA_IS_RAN_OUT_OF_EQ(
- ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32 + 1)) {
- IPAHAL_ERR_RL("ran out of ihl_meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32 + 1]);
- /* populate TCP protocol eq */
- if (attrib->ether_type == 0x0800) {
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 30;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
- 0xFF0000;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- 0x60000;
- } else {
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 26;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
- 0xFF00;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- 0x600;
- }
- /* populate TCP SYN eq */
- if (attrib->ether_type == 0x0800) {
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 54;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
- 0x20000;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- 0x20000;
- } else {
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 74;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
- 0x20000;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- 0x20000;
- }
- ihl_ofst_meq32 += 2;
- }
- if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IP_TYPE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 22 => offset of inner IP type after v6 header */
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 22;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
- 0xF0000000;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- (u32)attrib->type << 24;
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_L2TP_INNER_IPV4_DST_ADDR) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR("ran out of ihl_meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- /* 38 => offset of inner IPv4 addr */
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 38;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
- attrib->u.v4.dst_addr_mask;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- attrib->u.v4.dst_addr;
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_MAC_ETHER_TYPE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) {
- IPAHAL_ERR_RL("ran out of meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ofst_meq32[ofst_meq32]);
- eq_atrb->offset_meq_32[ofst_meq32].offset = -2;
- eq_atrb->offset_meq_32[ofst_meq32].mask =
- htons(attrib->ether_type);
- eq_atrb->offset_meq_32[ofst_meq32].value =
- htons(attrib->ether_type);
- ofst_meq32++;
- }
- if (ipa_flt_generat_vlan_eq(attrib, en_rule, &ofst_meq32, eq_atrb))
- return -EPERM;
- if (attrib->attrib_mask & IPA_FLT_TYPE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR_RL("ran out of ihl_meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 0;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = 0xFF;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- attrib->type;
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_CODE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR_RL("ran out of ihl_meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 1;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = 0xFF;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- attrib->code;
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_SPI) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32,
- ihl_ofst_meq32)) {
- IPAHAL_ERR_RL("ran out of ihl_meq32 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]);
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = 0;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask =
- 0xFFFFFFFF;
- eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value =
- attrib->spi;
- ihl_ofst_meq32++;
- }
- if (attrib->attrib_mask & IPA_FLT_META_DATA) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- IPA_METADATA_COMPARE);
- eq_atrb->metadata_meq32_present = 1;
- eq_atrb->metadata_meq32.offset = 0;
- eq_atrb->metadata_meq32.mask = attrib->meta_data_mask;
- eq_atrb->metadata_meq32.value = attrib->meta_data;
- }
- if (attrib->attrib_mask & IPA_FLT_SRC_PORT) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR_RL("ran out of ihl_rng16 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset = 0;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
- = attrib->src_port;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
- = attrib->src_port;
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_DST_PORT) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR_RL("ran out of ihl_rng16 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset = 2;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
- = attrib->dst_port;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
- = attrib->dst_port;
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_SRC_PORT_RANGE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR_RL("ran out of ihl_rng16 eq\n");
- return -EPERM;
- }
- if (attrib->src_port_hi < attrib->src_port_lo) {
- IPAHAL_ERR_RL("bad src port range param\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset = 0;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
- = attrib->src_port_lo;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
- = attrib->src_port_hi;
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_DST_PORT_RANGE) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR_RL("ran out of ihl_rng16 eq\n");
- return -EPERM;
- }
- if (attrib->dst_port_hi < attrib->dst_port_lo) {
- IPAHAL_ERR_RL("bad dst port range param\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset = 2;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
- = attrib->dst_port_lo;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
- = attrib->dst_port_hi;
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR("ran out of ihl_rng16 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- if (attrib->ether_type == 0x0800) {
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset
- = 21;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
- = 0x0045;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
- = 0x0045;
- } else {
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset =
- 20;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
- = attrib->ether_type;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
- = attrib->ether_type;
- }
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_TCP_SYN_L2TP) {
- if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_rng16,
- ihl_ofst_rng16)) {
- IPAHAL_ERR_RL("ran out of ihl_rng16 eq\n");
- return -EPERM;
- }
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- ipa3_0_ihl_ofst_rng16[ihl_ofst_rng16]);
- if (attrib->ether_type == 0x0800) {
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset
- = 21;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
- = 0x0045;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
- = 0x0045;
- } else {
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].offset =
- 20;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_low
- = attrib->ether_type;
- eq_atrb->ihl_offset_range_16[ihl_ofst_rng16].range_high
- = attrib->ether_type;
- }
- ihl_ofst_rng16++;
- }
- if (attrib->attrib_mask & IPA_FLT_FLOW_LABEL) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_FL_EQ);
- eq_atrb->fl_eq_present = 1;
- eq_atrb->fl_eq = attrib->u.v6.flow_label;
- }
- if (attrib->attrib_mask & IPA_FLT_FRAGMENT) {
- *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(
- IPA_IS_FRAG);
- eq_atrb->ipv4_frag_eq_present = 1;
- }
- eq_atrb->rule_eq_bitmap = *en_rule;
- eq_atrb->num_offset_meq_32 = ofst_meq32;
- eq_atrb->num_ihl_offset_range_16 = ihl_ofst_rng16;
- eq_atrb->num_ihl_offset_meq_32 = ihl_ofst_meq32;
- eq_atrb->num_offset_meq_128 = ofst_meq128;
- return 0;
- }
- static int ipa_fltrt_parse_hw_rule_eq(u8 *addr, u32 hdr_sz,
- struct ipa_ipfltri_rule_eq *atrb, u32 *rule_size)
- {
- u16 eq_bitmap;
- int extra_bytes;
- u8 *extra;
- u8 *rest;
- int i;
- u8 dummy_extra_wrd;
- if (!addr || !atrb || !rule_size) {
- IPAHAL_ERR("Input error: addr=%pK atrb=%pK rule_size=%pK\n",
- addr, atrb, rule_size);
- return -EINVAL;
- }
- eq_bitmap = atrb->rule_eq_bitmap;
- IPAHAL_DBG_LOW("eq_bitmap=0x%x\n", eq_bitmap);
- if (IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK) &&
- (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_PURE_ACK))) {
- /*
- * tos_eq_present field represents pure_ack when pure
- * ack equation valid (started IPA 4.5). In this case
- * tos equation should not be supported.
- */
- atrb->tos_eq_present = true;
- }
- if (IPA_IS_RULE_EQ_VALID(IPA_TOS_EQ) &&
- (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_TOS_EQ))) {
- atrb->tos_eq_present = true;
- }
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_PROTOCOL_EQ))
- atrb->protocol_eq_present = true;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_TC_EQ))
- atrb->tc_eq_present = true;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_OFFSET_MEQ128_0))
- atrb->num_offset_meq_128++;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_OFFSET_MEQ128_1))
- atrb->num_offset_meq_128++;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_OFFSET_MEQ32_0))
- atrb->num_offset_meq_32++;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_OFFSET_MEQ32_1))
- atrb->num_offset_meq_32++;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_IHL_OFFSET_MEQ32_0))
- atrb->num_ihl_offset_meq_32++;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_IHL_OFFSET_MEQ32_1))
- atrb->num_ihl_offset_meq_32++;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_METADATA_COMPARE))
- atrb->metadata_meq32_present = true;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_IHL_OFFSET_RANGE16_0))
- atrb->num_ihl_offset_range_16++;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_IHL_OFFSET_RANGE16_1))
- atrb->num_ihl_offset_range_16++;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_IHL_OFFSET_EQ_32))
- atrb->ihl_offset_eq_32_present = true;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_IHL_OFFSET_EQ_16))
- atrb->ihl_offset_eq_16_present = true;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_FL_EQ))
- atrb->fl_eq_present = true;
- if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_FRAG))
- atrb->ipv4_frag_eq_present = true;
- extra_bytes = ipa_fltrt_calc_extra_wrd_bytes(atrb);
- /* only 3 eq does not have extra word param, 13 out of 16 is the number
- * of equations that needs extra word param
- */
- if (extra_bytes > 13) {
- IPAHAL_ERR("too much extra bytes\n");
- return -EPERM;
- } else if (extra_bytes > IPA3_0_HW_TBL_HDR_WIDTH) {
- /* two extra words */
- extra = addr + hdr_sz;
- rest = extra + IPA3_0_HW_TBL_HDR_WIDTH * 2;
- } else if (extra_bytes > 0) {
- /* single extra word */
- extra = addr + hdr_sz;
- rest = extra + IPA3_0_HW_TBL_HDR_WIDTH;
- } else {
- /* no extra words */
- dummy_extra_wrd = 0;
- extra = &dummy_extra_wrd;
- rest = addr + hdr_sz;
- }
- IPAHAL_DBG_LOW("addr=0x%pK extra=0x%pK rest=0x%pK\n",
- addr, extra, rest);
- if (IPA_IS_RULE_EQ_VALID(IPA_TOS_EQ) && atrb->tos_eq_present)
- atrb->tos_eq = *extra++;
- if (IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK) && atrb->tos_eq_present) {
- atrb->tos_eq = 0;
- extra++;
- }
- if (atrb->protocol_eq_present)
- atrb->protocol_eq = *extra++;
- if (atrb->tc_eq_present)
- atrb->tc_eq = *extra++;
- if (atrb->num_offset_meq_128 > 0) {
- atrb->offset_meq_128[0].offset = *extra++;
- for (i = 0; i < 8; i++)
- atrb->offset_meq_128[0].mask[i] = *rest++;
- for (i = 0; i < 8; i++)
- atrb->offset_meq_128[0].value[i] = *rest++;
- for (i = 8; i < 16; i++)
- atrb->offset_meq_128[0].mask[i] = *rest++;
- for (i = 8; i < 16; i++)
- atrb->offset_meq_128[0].value[i] = *rest++;
- }
- if (atrb->num_offset_meq_128 > 1) {
- atrb->offset_meq_128[1].offset = *extra++;
- for (i = 0; i < 8; i++)
- atrb->offset_meq_128[1].mask[i] = *rest++;
- for (i = 0; i < 8; i++)
- atrb->offset_meq_128[1].value[i] = *rest++;
- for (i = 8; i < 16; i++)
- atrb->offset_meq_128[1].mask[i] = *rest++;
- for (i = 8; i < 16; i++)
- atrb->offset_meq_128[1].value[i] = *rest++;
- }
- if (atrb->num_offset_meq_32 > 0) {
- atrb->offset_meq_32[0].offset = *extra++;
- atrb->offset_meq_32[0].mask = *((u32 *)rest);
- rest += 4;
- atrb->offset_meq_32[0].value = *((u32 *)rest);
- rest += 4;
- }
- if (atrb->num_offset_meq_32 > 1) {
- atrb->offset_meq_32[1].offset = *extra++;
- atrb->offset_meq_32[1].mask = *((u32 *)rest);
- rest += 4;
- atrb->offset_meq_32[1].value = *((u32 *)rest);
- rest += 4;
- }
- if (atrb->num_ihl_offset_meq_32 > 0) {
- atrb->ihl_offset_meq_32[0].offset = *extra++;
- atrb->ihl_offset_meq_32[0].mask = *((u32 *)rest);
- rest += 4;
- atrb->ihl_offset_meq_32[0].value = *((u32 *)rest);
- rest += 4;
- }
- if (atrb->num_ihl_offset_meq_32 > 1) {
- atrb->ihl_offset_meq_32[1].offset = *extra++;
- atrb->ihl_offset_meq_32[1].mask = *((u32 *)rest);
- rest += 4;
- atrb->ihl_offset_meq_32[1].value = *((u32 *)rest);
- rest += 4;
- }
- if (atrb->metadata_meq32_present) {
- atrb->metadata_meq32.mask = *((u32 *)rest);
- rest += 4;
- atrb->metadata_meq32.value = *((u32 *)rest);
- rest += 4;
- }
- if (atrb->num_ihl_offset_range_16 > 0) {
- atrb->ihl_offset_range_16[0].offset = *extra++;
- atrb->ihl_offset_range_16[0].range_high = *((u16 *)rest);
- rest += 2;
- atrb->ihl_offset_range_16[0].range_low = *((u16 *)rest);
- rest += 2;
- }
- if (atrb->num_ihl_offset_range_16 > 1) {
- atrb->ihl_offset_range_16[1].offset = *extra++;
- atrb->ihl_offset_range_16[1].range_high = *((u16 *)rest);
- rest += 2;
- atrb->ihl_offset_range_16[1].range_low = *((u16 *)rest);
- rest += 2;
- }
- if (atrb->ihl_offset_eq_32_present) {
- atrb->ihl_offset_eq_32.offset = *extra++;
- atrb->ihl_offset_eq_32.value = *((u32 *)rest);
- rest += 4;
- }
- if (atrb->ihl_offset_eq_16_present) {
- atrb->ihl_offset_eq_16.offset = *extra++;
- atrb->ihl_offset_eq_16.value = *((u16 *)rest);
- rest += 4;
- }
- if (atrb->fl_eq_present) {
- atrb->fl_eq = *((u32 *)rest);
- atrb->fl_eq &= 0xfffff;
- rest += 4;
- }
- IPAHAL_DBG_LOW("before rule alignment rest=0x%pK\n", rest);
- rest = (u8 *)(((unsigned long)rest + IPA3_0_HW_RULE_START_ALIGNMENT) &
- ~IPA3_0_HW_RULE_START_ALIGNMENT);
- IPAHAL_DBG_LOW("after rule alignment rest=0x%pK\n", rest);
- *rule_size = rest - addr;
- IPAHAL_DBG_LOW("rule_size=0x%x\n", *rule_size);
- return 0;
- }
- static int ipa_rt_parse_hw_rule(u8 *addr, struct ipahal_rt_rule_entry *rule)
- {
- struct ipa3_0_rt_rule_hw_hdr *rule_hdr;
- struct ipa_ipfltri_rule_eq *atrb;
- IPAHAL_DBG_LOW("Entry\n");
- rule_hdr = (struct ipa3_0_rt_rule_hw_hdr *)addr;
- atrb = &rule->eq_attrib;
- IPAHAL_DBG_LOW("read hdr 0x%llx\n", rule_hdr->u.word);
- if (rule_hdr->u.word == 0) {
- /* table terminator - empty table */
- rule->rule_size = 0;
- return 0;
- }
- rule->dst_pipe_idx = rule_hdr->u.hdr.pipe_dest_idx;
- if (rule_hdr->u.hdr.proc_ctx) {
- rule->hdr_type = IPAHAL_RT_RULE_HDR_PROC_CTX;
- rule->hdr_ofst = (rule_hdr->u.hdr.hdr_offset) << 5;
- } else {
- rule->hdr_type = IPAHAL_RT_RULE_HDR_RAW;
- rule->hdr_ofst = (rule_hdr->u.hdr.hdr_offset) << 2;
- }
- rule->hdr_lcl = !rule_hdr->u.hdr.system;
- rule->priority = rule_hdr->u.hdr.priority;
- rule->retain_hdr = rule_hdr->u.hdr.retain_hdr;
- rule->id = rule_hdr->u.hdr.rule_id;
- atrb->rule_eq_bitmap = rule_hdr->u.hdr.en_rule;
- return ipa_fltrt_parse_hw_rule_eq(addr, sizeof(*rule_hdr),
- atrb, &rule->rule_size);
- }
- static int ipa_rt_parse_hw_rule_ipav4_5(u8 *addr,
- struct ipahal_rt_rule_entry *rule)
- {
- struct ipa4_5_rt_rule_hw_hdr *rule_hdr;
- struct ipa_ipfltri_rule_eq *atrb;
- IPAHAL_DBG_LOW("Entry\n");
- rule_hdr = (struct ipa4_5_rt_rule_hw_hdr *)addr;
- atrb = &rule->eq_attrib;
- IPAHAL_DBG_LOW("read hdr 0x%llx\n", rule_hdr->u.word);
- if (rule_hdr->u.word == 0) {
- /* table termintator - empty table */
- rule->rule_size = 0;
- return 0;
- }
- rule->dst_pipe_idx = rule_hdr->u.hdr.pipe_dest_idx;
- if (rule_hdr->u.hdr.proc_ctx) {
- rule->hdr_type = IPAHAL_RT_RULE_HDR_PROC_CTX;
- rule->hdr_ofst = (rule_hdr->u.hdr.hdr_offset) << 5;
- } else {
- rule->hdr_type = IPAHAL_RT_RULE_HDR_RAW;
- rule->hdr_ofst = (rule_hdr->u.hdr.hdr_offset) << 2;
- }
- rule->hdr_lcl = !rule_hdr->u.hdr.system;
- rule->priority = rule_hdr->u.hdr.priority;
- rule->retain_hdr = rule_hdr->u.hdr.retain_hdr;
- rule->cnt_idx = rule_hdr->u.hdr.stats_cnt_idx_lsb |
- (rule_hdr->u.hdr.stats_cnt_idx_msb) << 6;
- rule->id = rule_hdr->u.hdr.rule_id;
- atrb->rule_eq_bitmap = rule_hdr->u.hdr.en_rule;
- return ipa_fltrt_parse_hw_rule_eq(addr, sizeof(*rule_hdr),
- atrb, &rule->rule_size);
- }
- static int ipa_flt_parse_hw_rule(u8 *addr, struct ipahal_flt_rule_entry *rule)
- {
- struct ipa3_0_flt_rule_hw_hdr *rule_hdr;
- struct ipa_ipfltri_rule_eq *atrb;
- IPAHAL_DBG_LOW("Entry\n");
- rule_hdr = (struct ipa3_0_flt_rule_hw_hdr *)addr;
- atrb = &rule->rule.eq_attrib;
- if (rule_hdr->u.word == 0) {
- /* table termintator - empty table */
- rule->rule_size = 0;
- return 0;
- }
- switch (rule_hdr->u.hdr.action) {
- case 0x0:
- rule->rule.action = IPA_PASS_TO_ROUTING;
- break;
- case 0x1:
- rule->rule.action = IPA_PASS_TO_SRC_NAT;
- break;
- case 0x2:
- rule->rule.action = IPA_PASS_TO_DST_NAT;
- break;
- case 0x3:
- rule->rule.action = IPA_PASS_TO_EXCEPTION;
- break;
- default:
- IPAHAL_ERR("Invalid Rule Action %d\n", rule_hdr->u.hdr.action);
- WARN_ON_RATELIMIT_IPA(1);
- rule->rule.action = rule_hdr->u.hdr.action;
- }
- rule->rule.rt_tbl_idx = rule_hdr->u.hdr.rt_tbl_idx;
- rule->rule.retain_hdr = rule_hdr->u.hdr.retain_hdr;
- rule->priority = rule_hdr->u.hdr.priority;
- rule->id = rule_hdr->u.hdr.rule_id;
- atrb->rule_eq_bitmap = rule_hdr->u.hdr.en_rule;
- rule->rule.eq_attrib_type = 1;
- return ipa_fltrt_parse_hw_rule_eq(addr, sizeof(*rule_hdr),
- atrb, &rule->rule_size);
- }
- static int ipa_flt_parse_hw_rule_ipav4(u8 *addr,
- struct ipahal_flt_rule_entry *rule)
- {
- struct ipa4_0_flt_rule_hw_hdr *rule_hdr;
- struct ipa_ipfltri_rule_eq *atrb;
- IPAHAL_DBG_LOW("Entry\n");
- rule_hdr = (struct ipa4_0_flt_rule_hw_hdr *)addr;
- atrb = &rule->rule.eq_attrib;
- if (rule_hdr->u.word == 0) {
- /* table termintator - empty table */
- rule->rule_size = 0;
- return 0;
- }
- switch (rule_hdr->u.hdr.action) {
- case 0x0:
- rule->rule.action = IPA_PASS_TO_ROUTING;
- break;
- case 0x1:
- rule->rule.action = IPA_PASS_TO_SRC_NAT;
- break;
- case 0x2:
- rule->rule.action = IPA_PASS_TO_DST_NAT;
- break;
- case 0x3:
- rule->rule.action = IPA_PASS_TO_EXCEPTION;
- break;
- default:
- IPAHAL_ERR("Invalid Rule Action %d\n", rule_hdr->u.hdr.action);
- WARN_ON_RATELIMIT_IPA(1);
- rule->rule.action = rule_hdr->u.hdr.action;
- }
- rule->rule.rt_tbl_idx = rule_hdr->u.hdr.rt_tbl_idx;
- rule->rule.retain_hdr = rule_hdr->u.hdr.retain_hdr;
- rule->priority = rule_hdr->u.hdr.priority;
- rule->id = rule_hdr->u.hdr.rule_id;
- rule->rule.pdn_idx = rule_hdr->u.hdr.pdn_idx;
- rule->rule.set_metadata = rule_hdr->u.hdr.set_metadata;
- atrb->rule_eq_bitmap = rule_hdr->u.hdr.en_rule;
- rule->rule.eq_attrib_type = 1;
- return ipa_fltrt_parse_hw_rule_eq(addr, sizeof(*rule_hdr),
- atrb, &rule->rule_size);
- }
- static int ipa_flt_parse_hw_rule_ipav4_5(u8 *addr,
- struct ipahal_flt_rule_entry *rule)
- {
- struct ipa4_5_flt_rule_hw_hdr *rule_hdr;
- struct ipa_ipfltri_rule_eq *atrb;
- IPAHAL_DBG_LOW("Entry\n");
- rule_hdr = (struct ipa4_5_flt_rule_hw_hdr *)addr;
- atrb = &rule->rule.eq_attrib;
- if (rule_hdr->u.word == 0) {
- /* table termintator - empty table */
- rule->rule_size = 0;
- return 0;
- }
- switch (rule_hdr->u.hdr.action) {
- case 0x0:
- rule->rule.action = IPA_PASS_TO_ROUTING;
- break;
- case 0x1:
- rule->rule.action = IPA_PASS_TO_SRC_NAT;
- break;
- case 0x2:
- rule->rule.action = IPA_PASS_TO_DST_NAT;
- break;
- case 0x3:
- rule->rule.action = IPA_PASS_TO_EXCEPTION;
- break;
- default:
- IPAHAL_ERR("Invalid Rule Action %d\n", rule_hdr->u.hdr.action);
- WARN_ON_RATELIMIT_IPA(1);
- rule->rule.action = rule_hdr->u.hdr.action;
- }
- rule->rule.rt_tbl_idx = rule_hdr->u.hdr.rt_tbl_idx;
- rule->rule.retain_hdr = rule_hdr->u.hdr.retain_hdr;
- rule->priority = rule_hdr->u.hdr.priority;
- rule->id = rule_hdr->u.hdr.rule_id;
- rule->rule.pdn_idx = rule_hdr->u.hdr.pdn_idx;
- rule->rule.set_metadata = rule_hdr->u.hdr.set_metadata;
- rule->cnt_idx = rule_hdr->u.hdr.stats_cnt_idx_lsb |
- (rule_hdr->u.hdr.stats_cnt_idx_msb) << 6;
- atrb->rule_eq_bitmap = rule_hdr->u.hdr.en_rule;
- rule->rule.eq_attrib_type = 1;
- return ipa_fltrt_parse_hw_rule_eq(addr, sizeof(*rule_hdr),
- atrb, &rule->rule_size);
- }
- /*
- * ipahal_fltrt_init() - Build the FLT/RT information table
- * See ipahal_fltrt_objs[] comments
- *
- * Note: As global variables are initialized with zero, any un-overridden
- * register entry will be zero. By this we recognize them.
- */
- int ipahal_fltrt_init(enum ipa_hw_type ipa_hw_type)
- {
- struct ipahal_fltrt_obj zero_obj;
- int i;
- struct ipa_mem_buffer *mem;
- int rc = -EFAULT;
- u32 eq_bits;
- u8 *eq_bitfield;
- IPAHAL_DBG("Entry - HW_TYPE=%d\n", ipa_hw_type);
- if (ipa_hw_type >= IPA_HW_MAX) {
- IPAHAL_ERR("Invalid H/W type\n");
- return -EFAULT;
- }
- memset(&zero_obj, 0, sizeof(zero_obj));
- for (i = IPA_HW_v3_0 ; i < ipa_hw_type ; i++) {
- if (!memcmp(&ipahal_fltrt_objs[i+1], &zero_obj,
- sizeof(struct ipahal_fltrt_obj))) {
- memcpy(&ipahal_fltrt_objs[i+1],
- &ipahal_fltrt_objs[i],
- sizeof(struct ipahal_fltrt_obj));
- } else {
- /*
- * explicitly overridden FLT RT info
- * Check validity
- */
- if (!ipahal_fltrt_objs[i+1].tbl_width) {
- IPAHAL_ERR(
- "Zero tbl width ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].sysaddr_alignment) {
- IPAHAL_ERR(
- "No tbl sysaddr alignment ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].lcladdr_alignment) {
- IPAHAL_ERR(
- "No tbl lcladdr alignment ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].blk_sz_alignment) {
- IPAHAL_ERR(
- "No blk sz alignment ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].rule_start_alignment) {
- IPAHAL_ERR(
- "No rule start alignment ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].tbl_hdr_width) {
- IPAHAL_ERR(
- "Zero tbl hdr width ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].tbl_addr_mask) {
- IPAHAL_ERR(
- "Zero tbl hdr width ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (ipahal_fltrt_objs[i+1].rule_id_bit_len < 2) {
- IPAHAL_ERR(
- "Too little bits for rule_id ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].rule_buf_size) {
- IPAHAL_ERR(
- "zero rule buf size ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].write_val_to_hdr) {
- IPAHAL_ERR(
- "No write_val_to_hdr CB ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].create_flt_bitmap) {
- IPAHAL_ERR(
- "No create_flt_bitmap CB ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].create_tbl_addr) {
- IPAHAL_ERR(
- "No create_tbl_addr CB ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].parse_tbl_addr) {
- IPAHAL_ERR(
- "No parse_tbl_addr CB ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].rt_generate_hw_rule) {
- IPAHAL_ERR(
- "No rt_generate_hw_rule CB ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].flt_generate_hw_rule) {
- IPAHAL_ERR(
- "No flt_generate_hw_rule CB ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].flt_generate_eq) {
- IPAHAL_ERR(
- "No flt_generate_eq CB ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].rt_parse_hw_rule) {
- IPAHAL_ERR(
- "No rt_parse_hw_rule CB ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- if (!ipahal_fltrt_objs[i+1].flt_parse_hw_rule) {
- IPAHAL_ERR(
- "No flt_parse_hw_rule CB ipaver=%d\n",
- i+1);
- WARN_ON(1);
- }
- }
- }
- eq_bits = 0;
- eq_bitfield = ipahal_fltrt_objs[ipa_hw_type].eq_bitfield;
- for (i = 0; i < IPA_EQ_MAX; i++) {
- if (!IPA_IS_RULE_EQ_VALID(i))
- continue;
- if (eq_bits & IPA_GET_RULE_EQ_BIT_PTRN(eq_bitfield[i])) {
- IPAHAL_ERR("more than eq with same bit. eq=%d\n", i);
- WARN_ON(1);
- return -EFAULT;
- }
- eq_bits |= IPA_GET_RULE_EQ_BIT_PTRN(eq_bitfield[i]);
- }
- mem = &ipahal_ctx->empty_fltrt_tbl;
- /* setup an empty table in system memory; This will
- * be used, for example, to delete a rt tbl safely
- */
- mem->size = ipahal_fltrt_objs[ipa_hw_type].tbl_width;
- mem->base = dma_alloc_coherent(ipahal_ctx->ipa_pdev, mem->size,
- &mem->phys_base, GFP_KERNEL);
- if (!mem->base) {
- IPAHAL_ERR("DMA buff alloc fail %d bytes for empty tbl\n",
- mem->size);
- return -ENOMEM;
- }
- if (mem->phys_base &
- ipahal_fltrt_objs[ipa_hw_type].sysaddr_alignment) {
- IPAHAL_ERR("Empty table buf is not address aligned 0x%pad\n",
- &mem->phys_base);
- rc = -EFAULT;
- goto clear_empty_tbl;
- }
- memset(mem->base, 0, mem->size);
- IPAHAL_DBG("empty table allocated in system memory");
- return 0;
- clear_empty_tbl:
- dma_free_coherent(ipahal_ctx->ipa_pdev, mem->size, mem->base,
- mem->phys_base);
- return rc;
- }
- void ipahal_fltrt_destroy(void)
- {
- IPAHAL_DBG("Entry\n");
- if (ipahal_ctx && ipahal_ctx->empty_fltrt_tbl.base)
- dma_free_coherent(ipahal_ctx->ipa_pdev,
- ipahal_ctx->empty_fltrt_tbl.size,
- ipahal_ctx->empty_fltrt_tbl.base,
- ipahal_ctx->empty_fltrt_tbl.phys_base);
- }
- /* Get the H/W table (flt/rt) header width */
- u32 ipahal_get_hw_tbl_hdr_width(void)
- {
- return ipahal_fltrt_objs[ipahal_ctx->hw_type].tbl_hdr_width;
- }
- /* Get the H/W local table (SRAM) address alignment
- * Tables headers references to local tables via offsets in SRAM
- * This function return the alignment of the offset that IPA expects
- */
- u32 ipahal_get_lcl_tbl_addr_alignment(void)
- {
- return ipahal_fltrt_objs[ipahal_ctx->hw_type].lcladdr_alignment;
- }
- /*
- * Rule priority is used to distinguish rules order
- * at the integrated table consisting from hashable and
- * non-hashable tables. Max priority are rules that once are
- * scanned by IPA, IPA will not look for further rules and use it.
- */
- int ipahal_get_rule_max_priority(void)
- {
- return ipahal_fltrt_objs[ipahal_ctx->hw_type].rule_max_prio;
- }
- /* Given a priority, calc and return the next lower one if it is in
- * legal range.
- */
- int ipahal_rule_decrease_priority(int *prio)
- {
- struct ipahal_fltrt_obj *obj;
- obj = &ipahal_fltrt_objs[ipahal_ctx->hw_type];
- if (!prio) {
- IPAHAL_ERR("Invalid Input\n");
- return -EINVAL;
- }
- /* Priority logic is reverse. 0 priority considred max priority */
- if (*prio > obj->rule_min_prio || *prio < obj->rule_max_prio) {
- IPAHAL_ERR("Invalid given priority %d\n", *prio);
- return -EINVAL;
- }
- *prio += 1;
- if (*prio > obj->rule_min_prio) {
- IPAHAL_ERR("Cannot decrease priority. Already on min\n");
- *prio -= 1;
- return -EFAULT;
- }
- return 0;
- }
- /* Does the given ID represents rule miss?
- * Rule miss ID, is always the max ID possible in the bit-pattern
- */
- bool ipahal_is_rule_miss_id(u32 id)
- {
- return (id ==
- ((1U << ipahal_fltrt_objs[ipahal_ctx->hw_type].rule_id_bit_len)
- -1));
- }
- /* Get rule ID with high bit only asserted
- * Used e.g. to create groups of IDs according to this bit
- */
- u32 ipahal_get_rule_id_hi_bit(void)
- {
- return BIT(ipahal_fltrt_objs[ipahal_ctx->hw_type].rule_id_bit_len - 1);
- }
- /* Get the low value possible to be used for rule-id */
- u32 ipahal_get_low_rule_id(void)
- {
- return ipahal_fltrt_objs[ipahal_ctx->hw_type].low_rule_id;
- }
- /*
- * Is the given counter id valid
- */
- bool ipahal_is_rule_cnt_id_valid(u8 cnt_id)
- {
- if (cnt_id < 0 || cnt_id > IPA_FLT_RT_HW_COUNTER)
- return false;
- return true;
- }
- /*
- * low value possible for counter hdl id
- */
- u32 ipahal_get_low_hdl_id(void)
- {
- return IPA4_5_LOW_CNT_ID;
- }
- /*
- * max counter hdl id for stats
- */
- u32 ipahal_get_high_hdl_id(void)
- {
- return IPA_MAX_FLT_RT_CNT_INDEX;
- }
- /*
- * ipahal_rt_generate_empty_img() - Generate empty route image
- * Creates routing header buffer for the given tables number.
- * For each table, make it point to the empty table on DDR.
- * @tbls_num: Number of tables. For each will have an entry in the header
- * @hash_hdr_size: SRAM buf size of the hash tbls hdr. Used for space check
- * @nhash_hdr_size: SRAM buf size of the nhash tbls hdr. Used for space check
- * @mem: mem object that points to DMA mem representing the hdr structure
- * @atomic: should DMA allocation be executed with atomic flag
- */
- int ipahal_rt_generate_empty_img(u32 tbls_num, u32 hash_hdr_size,
- u32 nhash_hdr_size, struct ipa_mem_buffer *mem, bool atomic)
- {
- int i;
- u64 addr;
- struct ipahal_fltrt_obj *obj;
- int flag;
- IPAHAL_DBG("Entry\n");
- flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
- obj = &ipahal_fltrt_objs[ipahal_ctx->hw_type];
- if (!tbls_num || !nhash_hdr_size || !mem) {
- IPAHAL_ERR("Input Error: tbls_num=%d nhash_hdr_sz=%d mem=%pK\n",
- tbls_num, nhash_hdr_size, mem);
- return -EINVAL;
- }
- if (obj->support_hash && !hash_hdr_size) {
- IPAHAL_ERR("Input Error: hash_hdr_sz=%d\n", hash_hdr_size);
- return -EINVAL;
- }
- if (nhash_hdr_size < (tbls_num * obj->tbl_hdr_width)) {
- IPAHAL_ERR("No enough spc at non-hash hdr blk for all tbls\n");
- WARN_ON(1);
- return -EINVAL;
- }
- if (obj->support_hash &&
- (hash_hdr_size < (tbls_num * obj->tbl_hdr_width))) {
- IPAHAL_ERR("No enough spc at hash hdr blk for all tbls\n");
- WARN_ON(1);
- return -EINVAL;
- }
- mem->size = tbls_num * obj->tbl_hdr_width;
- mem->base = dma_alloc_coherent(ipahal_ctx->ipa_pdev, mem->size,
- &mem->phys_base, flag);
- if (!mem->base) {
- IPAHAL_ERR("fail to alloc DMA buff of size %d\n", mem->size);
- return -ENOMEM;
- }
- addr = obj->create_tbl_addr(true,
- ipahal_ctx->empty_fltrt_tbl.phys_base);
- for (i = 0; i < tbls_num; i++)
- obj->write_val_to_hdr(addr,
- mem->base + i * obj->tbl_hdr_width);
- return 0;
- }
- /*
- * ipahal_flt_generate_empty_img() - Generate empty filter image
- * Creates filter header buffer for the given tables number.
- * For each table, make it point to the empty table on DDR.
- * @tbls_num: Number of tables. For each will have an entry in the header
- * @hash_hdr_size: SRAM buf size of the hash tbls hdr. Used for space check
- * @nhash_hdr_size: SRAM buf size of the nhash tbls hdr. Used for space check
- * @ep_bitmap: Bitmap representing the EP that has flt tables. The format
- * should be: bit0->EP0, bit1->EP1
- * If bitmap is zero -> create tbl without bitmap entry
- * @mem: mem object that points to DMA mem representing the hdr structure
- * @atomic: should DMA allocation be executed with atomic flag
- */
- int ipahal_flt_generate_empty_img(u32 tbls_num, u32 hash_hdr_size,
- u32 nhash_hdr_size, u64 ep_bitmap, struct ipa_mem_buffer *mem,
- bool atomic)
- {
- int flt_spc;
- u64 flt_bitmap;
- int i;
- u64 addr;
- struct ipahal_fltrt_obj *obj;
- int flag;
- IPAHAL_DBG("Entry - ep_bitmap 0x%llx\n", ep_bitmap);
- flag = atomic ? GFP_ATOMIC : GFP_KERNEL;
- obj = &ipahal_fltrt_objs[ipahal_ctx->hw_type];
- if (!tbls_num || !nhash_hdr_size || !mem) {
- IPAHAL_ERR("Input Error: tbls_num=%d nhash_hdr_sz=%d mem=%pK\n",
- tbls_num, nhash_hdr_size, mem);
- return -EINVAL;
- }
- if (obj->support_hash && !hash_hdr_size) {
- IPAHAL_ERR("Input Error: hash_hdr_sz=%d\n", hash_hdr_size);
- return -EINVAL;
- }
- if (obj->support_hash) {
- flt_spc = hash_hdr_size;
- /* bitmap word */
- if (ep_bitmap)
- flt_spc -= obj->tbl_hdr_width;
- flt_spc /= obj->tbl_hdr_width;
- if (tbls_num > flt_spc) {
- IPAHAL_ERR("space for hash flt hdr is too small\n");
- WARN_ON(1);
- return -EPERM;
- }
- }
- flt_spc = nhash_hdr_size;
- /* bitmap word */
- if (ep_bitmap)
- flt_spc -= obj->tbl_hdr_width;
- flt_spc /= obj->tbl_hdr_width;
- if (tbls_num > flt_spc) {
- IPAHAL_ERR("space for non-hash flt hdr is too small\n");
- WARN_ON(1);
- return -EPERM;
- }
- mem->size = tbls_num * obj->tbl_hdr_width;
- if (ep_bitmap)
- mem->size += obj->tbl_hdr_width;
- mem->base = dma_alloc_coherent(ipahal_ctx->ipa_pdev, mem->size,
- &mem->phys_base, flag);
- if (!mem->base) {
- IPAHAL_ERR("fail to alloc DMA buff of size %d\n", mem->size);
- return -ENOMEM;
- }
- if (ep_bitmap) {
- flt_bitmap = obj->create_flt_bitmap(ep_bitmap);
- IPAHAL_DBG("flt bitmap 0x%llx\n", flt_bitmap);
- obj->write_val_to_hdr(flt_bitmap, mem->base);
- }
- addr = obj->create_tbl_addr(true,
- ipahal_ctx->empty_fltrt_tbl.phys_base);
- if (ep_bitmap) {
- for (i = 1; i <= tbls_num; i++)
- obj->write_val_to_hdr(addr,
- mem->base + i * obj->tbl_hdr_width);
- } else {
- for (i = 0; i < tbls_num; i++)
- obj->write_val_to_hdr(addr,
- mem->base + i * obj->tbl_hdr_width);
- }
- return 0;
- }
- /*
- * ipa_fltrt_alloc_init_tbl_hdr() - allocate and initialize buffers for
- * flt/rt tables headers to be filled into sram. Init each table to point
- * to empty system table
- * @params: Allocate IN and OUT params
- *
- * Return: 0 on success, negative on failure
- */
- static int ipa_fltrt_alloc_init_tbl_hdr(
- struct ipahal_fltrt_alloc_imgs_params *params)
- {
- u64 addr;
- int i;
- struct ipahal_fltrt_obj *obj;
- gfp_t flag = GFP_KERNEL;
- obj = &ipahal_fltrt_objs[ipahal_ctx->hw_type];
- if (!params) {
- IPAHAL_ERR_RL("Input error: params=%pK\n", params);
- return -EINVAL;
- }
- params->nhash_hdr.size = params->tbls_num * obj->tbl_hdr_width;
- alloc:
- params->nhash_hdr.base = dma_alloc_coherent(ipahal_ctx->ipa_pdev,
- params->nhash_hdr.size,
- ¶ms->nhash_hdr.phys_base, flag);
- if (!params->nhash_hdr.base) {
- if (flag == GFP_KERNEL) {
- flag = GFP_ATOMIC;
- goto alloc;
- }
- IPAHAL_ERR_RL("fail to alloc DMA buff of size %d\n",
- params->nhash_hdr.size);
- goto nhash_alloc_fail;
- }
- if (obj->support_hash) {
- params->hash_hdr.size = params->tbls_num * obj->tbl_hdr_width;
- params->hash_hdr.base = dma_alloc_coherent(ipahal_ctx->ipa_pdev,
- params->hash_hdr.size, ¶ms->hash_hdr.phys_base,
- GFP_KERNEL);
- if (!params->hash_hdr.base) {
- IPAHAL_ERR_RL("fail to alloc DMA buff of size %d\n",
- params->hash_hdr.size);
- goto hash_alloc_fail;
- }
- }
- addr = obj->create_tbl_addr(true,
- ipahal_ctx->empty_fltrt_tbl.phys_base);
- for (i = 0; i < params->tbls_num; i++) {
- obj->write_val_to_hdr(addr,
- params->nhash_hdr.base + i * obj->tbl_hdr_width);
- if (obj->support_hash)
- obj->write_val_to_hdr(addr,
- params->hash_hdr.base +
- i * obj->tbl_hdr_width);
- }
- return 0;
- hash_alloc_fail:
- ipahal_free_dma_mem(¶ms->nhash_hdr);
- nhash_alloc_fail:
- return -ENOMEM;
- }
- /*
- * ipa_fltrt_alloc_lcl_bdy() - allocate and initialize buffers for
- * local flt/rt tables bodies to be filled into sram
- * @params: Allocate IN and OUT params
- *
- * Return: 0 on success, negative on failure
- */
- static int ipa_fltrt_alloc_lcl_bdy(
- struct ipahal_fltrt_alloc_imgs_params *params)
- {
- struct ipahal_fltrt_obj *obj;
- gfp_t flag = GFP_KERNEL;
- obj = &ipahal_fltrt_objs[ipahal_ctx->hw_type];
- /* The HAL allocates larger sizes than the given effective ones
- * for alignments and border indications
- */
- IPAHAL_DBG_LOW("lcl tbl bdy total effective sizes: hash=%u nhash=%u\n",
- params->total_sz_lcl_hash_tbls,
- params->total_sz_lcl_nhash_tbls);
- IPAHAL_DBG_LOW("lcl tbl bdy count: hash=%u nhash=%u\n",
- params->num_lcl_hash_tbls,
- params->num_lcl_nhash_tbls);
- /* Align the sizes to coop with termination word
- * and H/W local table start offset alignment
- */
- if (params->nhash_bdy.size) {
- params->nhash_bdy.size = params->total_sz_lcl_nhash_tbls;
- /* for table terminator */
- params->nhash_bdy.size += obj->tbl_width *
- params->num_lcl_nhash_tbls;
- /* align the start of local rule-set */
- params->nhash_bdy.size += obj->lcladdr_alignment *
- params->num_lcl_nhash_tbls;
- /* SRAM block size alignment */
- params->nhash_bdy.size += obj->blk_sz_alignment;
- params->nhash_bdy.size &= ~(obj->blk_sz_alignment);
- IPAHAL_DBG_LOW("nhash lcl tbl bdy total h/w size = %u\n",
- params->nhash_bdy.size);
- alloc1:
- params->nhash_bdy.base = dma_alloc_coherent(
- ipahal_ctx->ipa_pdev, params->nhash_bdy.size,
- ¶ms->nhash_bdy.phys_base, flag);
- if (!params->nhash_bdy.base) {
- if (flag == GFP_KERNEL) {
- flag = GFP_ATOMIC;
- goto alloc1;
- }
- IPAHAL_ERR("fail to alloc DMA buff of size %d\n",
- params->nhash_bdy.size);
- return -ENOMEM;
- }
- }
- if (!obj->support_hash && params->hash_bdy.size) {
- IPAHAL_ERR("No HAL Hash tbls support - Will be ignored\n");
- WARN_ON(1);
- }
- if (obj->support_hash && params->hash_bdy.size) {
- params->hash_bdy.size = params->total_sz_lcl_hash_tbls;
- /* for table terminator */
- params->hash_bdy.size += obj->tbl_width *
- params->num_lcl_hash_tbls;
- /* align the start of local rule-set */
- params->hash_bdy.size += obj->lcladdr_alignment *
- params->num_lcl_hash_tbls;
- /* SRAM block size alignment */
- params->hash_bdy.size += obj->blk_sz_alignment;
- params->hash_bdy.size &= ~(obj->blk_sz_alignment);
- IPAHAL_DBG_LOW("hash lcl tbl bdy total h/w size = %u\n",
- params->hash_bdy.size);
- alloc2:
- params->hash_bdy.base = dma_alloc_coherent(
- ipahal_ctx->ipa_pdev, params->hash_bdy.size,
- ¶ms->hash_bdy.phys_base, flag);
- if (!params->hash_bdy.base) {
- if (flag == GFP_KERNEL) {
- flag = GFP_ATOMIC;
- goto alloc2;
- }
- IPAHAL_ERR("fail to alloc DMA buff of size %d\n",
- params->hash_bdy.size);
- goto hash_bdy_fail;
- }
- }
- return 0;
- hash_bdy_fail:
- if (params->nhash_bdy.size)
- ipahal_free_dma_mem(¶ms->nhash_bdy);
- return -ENOMEM;
- }
- /*
- * ipahal_fltrt_allocate_hw_tbl_imgs() - Allocate tbl images DMA structures
- * Used usually during commit.
- * Allocates header structures and init them to point to empty DDR table
- * Allocate body strucutres for local bodies tables
- * @params: Parameters for IN and OUT regard the allocation.
- */
- int ipahal_fltrt_allocate_hw_tbl_imgs(
- struct ipahal_fltrt_alloc_imgs_params *params)
- {
- IPAHAL_DBG_LOW("Entry\n");
- /* Input validation */
- if (!params) {
- IPAHAL_ERR_RL("Input err: no params\n");
- return -EINVAL;
- }
- if (params->ipt >= IPA_IP_MAX) {
- IPAHAL_ERR_RL("Input err: Invalid ip type %d\n", params->ipt);
- return -EINVAL;
- }
- if (ipa_fltrt_alloc_init_tbl_hdr(params)) {
- IPAHAL_ERR_RL("fail to alloc and init tbl hdr\n");
- return -ENOMEM;
- }
- if (ipa_fltrt_alloc_lcl_bdy(params)) {
- IPAHAL_ERR_RL("fail to alloc tbl bodies\n");
- goto bdy_alloc_fail;
- }
- return 0;
- bdy_alloc_fail:
- ipahal_free_dma_mem(¶ms->nhash_hdr);
- if (params->hash_hdr.size)
- ipahal_free_dma_mem(¶ms->hash_hdr);
- return -ENOMEM;
- }
- /*
- * ipahal_fltrt_allocate_hw_sys_tbl() - Allocate DMA mem for H/W flt/rt sys tbl
- * @tbl_mem: IN/OUT param. size for effective table size. Pointer, for the
- * allocated memory.
- *
- * The size is adapted for needed alignments/borders.
- */
- int ipahal_fltrt_allocate_hw_sys_tbl(struct ipa_mem_buffer *tbl_mem)
- {
- struct ipahal_fltrt_obj *obj;
- gfp_t flag = GFP_KERNEL;
- IPAHAL_DBG_LOW("Entry\n");
- if (!tbl_mem) {
- IPAHAL_ERR("Input err\n");
- return -EINVAL;
- }
- if (!tbl_mem->size) {
- IPAHAL_ERR("Input err: zero table size\n");
- return -EINVAL;
- }
- obj = &ipahal_fltrt_objs[ipahal_ctx->hw_type];
- /* add word for rule-set terminator */
- tbl_mem->size += obj->tbl_width;
- alloc:
- tbl_mem->base = dma_alloc_coherent(ipahal_ctx->ipa_pdev, tbl_mem->size,
- &tbl_mem->phys_base, flag);
- if (!tbl_mem->base) {
- if (flag == GFP_KERNEL) {
- flag = GFP_ATOMIC;
- goto alloc;
- }
- IPAHAL_ERR("fail to alloc DMA buf of size %d\n",
- tbl_mem->size);
- return -ENOMEM;
- }
- if (tbl_mem->phys_base & obj->sysaddr_alignment) {
- IPAHAL_ERR("sys rt tbl address is not aligned\n");
- goto align_err;
- }
- memset(tbl_mem->base, 0, tbl_mem->size);
- return 0;
- align_err:
- ipahal_free_dma_mem(tbl_mem);
- return -EPERM;
- }
- /*
- * ipahal_fltrt_write_addr_to_hdr() - Fill table header with table address
- * Given table addr/offset, adapt it to IPA H/W format and write it
- * to given header index.
- * @addr: Address or offset to be used
- * @hdr_base: base address of header structure to write the address
- * @hdr_idx: index of the address in the header structure
- * @is_sys: Is it system address or local offset
- */
- int ipahal_fltrt_write_addr_to_hdr(u64 addr, void *hdr_base, u32 hdr_idx,
- bool is_sys)
- {
- struct ipahal_fltrt_obj *obj;
- u64 hwaddr;
- u8 *hdr;
- IPAHAL_DBG_LOW("Entry\n");
- obj = &ipahal_fltrt_objs[ipahal_ctx->hw_type];
- if (!addr || !hdr_base) {
- IPAHAL_ERR("Input err: addr=0x%llx hdr_base=%pK\n",
- addr, hdr_base);
- return -EINVAL;
- }
- hdr = (u8 *)hdr_base;
- hdr += hdr_idx * obj->tbl_hdr_width;
- hwaddr = obj->create_tbl_addr(is_sys, addr);
- obj->write_val_to_hdr(hwaddr, hdr);
- return 0;
- }
- /*
- * ipahal_fltrt_read_addr_from_hdr() - Given sram address, read it's
- * content (physical address or offset) and parse it.
- * @hdr_base: base sram address of the header structure.
- * @hdr_idx: index of the header entry line in the header structure.
- * @addr: The parsed address - Out parameter
- * @is_sys: Is this system or local address - Out parameter
- */
- int ipahal_fltrt_read_addr_from_hdr(void *hdr_base, u32 hdr_idx, u64 *addr,
- bool *is_sys)
- {
- struct ipahal_fltrt_obj *obj;
- u64 hwaddr;
- u8 *hdr;
- IPAHAL_DBG_LOW("Entry\n");
- obj = &ipahal_fltrt_objs[ipahal_ctx->hw_type];
- if (!addr || !hdr_base || !is_sys) {
- IPAHAL_ERR("Input err: addr=%pK hdr_base=%pK is_sys=%pK\n",
- addr, hdr_base, is_sys);
- return -EINVAL;
- }
- hdr = (u8 *)hdr_base;
- hdr += hdr_idx * obj->tbl_hdr_width;
- hwaddr = *((u64 *)hdr);
- obj->parse_tbl_addr(hwaddr, addr, is_sys);
- return 0;
- }
- /*
- * ipahal_rt_generate_hw_rule() - generates the routing hardware rule
- * @params: Params for the rule creation.
- * @hw_len: Size of the H/W rule to be returned
- * @buf: Buffer to build the rule in. If buf is NULL, then the rule will
- * be built in internal temp buf. This is used e.g. to get the rule size
- * only.
- */
- int ipahal_rt_generate_hw_rule(struct ipahal_rt_rule_gen_params *params,
- u32 *hw_len, u8 *buf)
- {
- struct ipahal_fltrt_obj *obj;
- u8 *tmp = NULL;
- int rc;
- IPAHAL_DBG_LOW("Entry\n");
- if (!params || !hw_len) {
- IPAHAL_ERR("Input err: params=%pK hw_len=%pK\n",
- params, hw_len);
- return -EINVAL;
- }
- if (!params->rule) {
- IPAHAL_ERR("Input err: invalid rule\n");
- return -EINVAL;
- }
- if (params->ipt >= IPA_IP_MAX) {
- IPAHAL_ERR("Input err: Invalid ip type %d\n", params->ipt);
- return -EINVAL;
- }
- obj = &ipahal_fltrt_objs[ipahal_ctx->hw_type];
- if (buf == NULL) {
- tmp = kzalloc(obj->rule_buf_size, GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
- buf = tmp;
- } else {
- if ((long)buf & obj->rule_start_alignment) {
- IPAHAL_ERR("buff is not rule start aligned\n");
- return -EPERM;
- }
- }
- rc = obj->rt_generate_hw_rule(params, hw_len, buf);
- if (!tmp && !rc) {
- /* write the rule-set terminator */
- memset(buf + *hw_len, 0, obj->tbl_width);
- }
- kfree(tmp);
- return rc;
- }
- /*
- * ipahal_flt_generate_hw_rule() - generates the filtering hardware rule.
- * @params: Params for the rule creation.
- * @hw_len: Size of the H/W rule to be returned
- * @buf: Buffer to build the rule in. If buf is NULL, then the rule will
- * be built in internal temp buf. This is used e.g. to get the rule size
- * only.
- */
- int ipahal_flt_generate_hw_rule(struct ipahal_flt_rule_gen_params *params,
- u32 *hw_len, u8 *buf)
- {
- struct ipahal_fltrt_obj *obj;
- u8 *tmp = NULL;
- int rc;
- IPAHAL_DBG_LOW("Entry\n");
- if (!params || !hw_len) {
- IPAHAL_ERR("Input err: params=%pK hw_len=%pK\n",
- params, hw_len);
- return -EINVAL;
- }
- if (!params->rule) {
- IPAHAL_ERR("Input err: invalid rule\n");
- return -EINVAL;
- }
- if (params->ipt >= IPA_IP_MAX) {
- IPAHAL_ERR("Input err: Invalid ip type %d\n", params->ipt);
- return -EINVAL;
- }
- obj = &ipahal_fltrt_objs[ipahal_ctx->hw_type];
- if (buf == NULL) {
- tmp = kzalloc(obj->rule_buf_size, GFP_KERNEL);
- if (!tmp) {
- IPAHAL_ERR("failed to alloc %u bytes\n",
- obj->rule_buf_size);
- return -ENOMEM;
- }
- buf = tmp;
- } else
- if ((long)buf & obj->rule_start_alignment) {
- IPAHAL_ERR("buff is not rule rule start aligned\n");
- return -EPERM;
- }
- rc = obj->flt_generate_hw_rule(params, hw_len, buf);
- if (!tmp && !rc) {
- /* write the rule-set terminator */
- memset(buf + *hw_len, 0, obj->tbl_width);
- }
- kfree(tmp);
- return rc;
- }
- /*
- * ipahal_flt_generate_equation() - generate flt rule in equation form
- * Will build equation form flt rule from given info.
- * @ipt: IP family
- * @attrib: Rule attribute to be generated
- * @eq_atrb: Equation form generated rule
- * Note: Usage example: Pass the generated form to other sub-systems
- * for inter-subsystems rules exchange.
- */
- int ipahal_flt_generate_equation(enum ipa_ip_type ipt,
- const struct ipa_rule_attrib *attrib,
- struct ipa_ipfltri_rule_eq *eq_atrb)
- {
- IPAHAL_DBG_LOW("Entry\n");
- if (ipt >= IPA_IP_MAX) {
- IPAHAL_ERR_RL("Input err: Invalid ip type %d\n", ipt);
- return -EINVAL;
- }
- if (!attrib || !eq_atrb) {
- IPAHAL_ERR_RL("Input err: attrib=%pK eq_atrb=%pK\n",
- attrib, eq_atrb);
- return -EINVAL;
- }
- return ipahal_fltrt_objs[ipahal_ctx->hw_type].flt_generate_eq(ipt,
- attrib, eq_atrb);
- }
- /*
- * ipahal_rt_parse_hw_rule() - Parse H/W formated rt rule
- * Given the rule address, read the rule info from H/W and parse it.
- * @rule_addr: Rule address (virtual memory)
- * @rule: Out parameter for parsed rule info
- */
- int ipahal_rt_parse_hw_rule(u8 *rule_addr,
- struct ipahal_rt_rule_entry *rule)
- {
- IPAHAL_DBG_LOW("Entry\n");
- if (!rule_addr || !rule) {
- IPAHAL_ERR("Input err: rule_addr=%pK rule=%pK\n",
- rule_addr, rule);
- return -EINVAL;
- }
- return ipahal_fltrt_objs[ipahal_ctx->hw_type].rt_parse_hw_rule(
- rule_addr, rule);
- }
- /*
- * ipahal_flt_parse_hw_rule() - Parse H/W formated flt rule
- * Given the rule address, read the rule info from H/W and parse it.
- * @rule_addr: Rule address (virtual memory)
- * @rule: Out parameter for parsed rule info
- */
- int ipahal_flt_parse_hw_rule(u8 *rule_addr,
- struct ipahal_flt_rule_entry *rule)
- {
- IPAHAL_DBG_LOW("Entry\n");
- if (!rule_addr || !rule) {
- IPAHAL_ERR("Input err: rule_addr=%pK rule=%pK\n",
- rule_addr, rule);
- return -EINVAL;
- }
- return ipahal_fltrt_objs[ipahal_ctx->hw_type].flt_parse_hw_rule(
- rule_addr, rule);
- }
|