123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320313213132231323313243132531326313273132831329313303133131332313333133431335313363133731338313393134031341313423134331344313453134631347313483134931350313513135231353313543135531356313573135831359313603136131362313633136431365313663136731368313693137031371313723137331374313753137631377313783137931380313813138231383313843138531386313873138831389313903139131392313933139431395313963139731398313993140031401314023140331404314053140631407314083140931410314113141231413314143141531416314173141831419314203142131422314233142431425314263142731428314293143031431314323143331434314353143631437314383143931440314413144231443314443144531446314473144831449314503145131452314533145431455314563145731458314593146031461314623146331464314653146631467314683146931470314713147231473314743147531476314773147831479314803148131482314833148431485314863148731488314893149031491314923149331494314953149631497314983149931500315013150231503315043150531506315073150831509315103151131512315133151431515315163151731518315193152031521315223152331524315253152631527315283152931530315313153231533315343153531536315373153831539315403154131542315433154431545315463154731548315493155031551315523155331554315553155631557315583155931560315613156231563315643156531566315673156831569315703157131572315733157431575315763157731578315793158031581315823158331584315853158631587315883158931590315913159231593315943159531596315973159831599316003160131602316033160431605316063160731608316093161031611316123161331614316153161631617316183161931620316213162231623316243162531626316273162831629316303163131632316333163431635316363163731638316393164031641316423164331644316453164631647316483164931650316513165231653316543165531656316573165831659316603166131662316633166431665316663166731668316693167031671316723167331674316753167631677316783167931680316813168231683316843168531686316873168831689316903169131692316933169431695316963169731698316993170031701317023170331704317053170631707317083170931710317113171231713317143171531716317173171831719317203172131722317233172431725317263172731728317293173031731317323173331734317353173631737317383173931740317413174231743317443174531746317473174831749317503175131752317533175431755317563175731758317593176031761317623176331764317653176631767317683176931770317713177231773317743177531776317773177831779317803178131782317833178431785317863178731788317893179031791317923179331794317953179631797317983179931800318013180231803318043180531806318073180831809318103181131812318133181431815318163181731818318193182031821318223182331824318253182631827318283182931830318313183231833318343183531836318373183831839318403184131842318433184431845318463184731848318493185031851318523185331854318553185631857318583185931860318613186231863318643186531866318673186831869318703187131872318733187431875318763187731878318793188031881318823188331884318853188631887318883188931890318913189231893318943189531896318973189831899319003190131902319033190431905319063190731908319093191031911319123191331914319153191631917319183191931920319213192231923319243192531926319273192831929319303193131932319333193431935319363193731938319393194031941319423194331944319453194631947319483194931950319513195231953319543195531956319573195831959319603196131962319633196431965319663196731968319693197031971319723197331974319753197631977319783197931980319813198231983319843198531986319873198831989319903199131992319933199431995319963199731998319993200032001320023200332004320053200632007320083200932010320113201232013320143201532016320173201832019320203202132022320233202432025320263202732028320293203032031320323203332034320353203632037320383203932040320413204232043320443204532046320473204832049320503205132052320533205432055320563205732058320593206032061320623206332064320653206632067320683206932070320713207232073320743207532076320773207832079320803208132082320833208432085320863208732088320893209032091320923209332094320953209632097320983209932100321013210232103321043210532106321073210832109321103211132112321133211432115321163211732118321193212032121321223212332124321253212632127321283212932130321313213232133321343213532136321373213832139321403214132142321433214432145321463214732148321493215032151321523215332154321553215632157321583215932160321613216232163321643216532166321673216832169321703217132172321733217432175321763217732178321793218032181321823218332184321853218632187321883218932190321913219232193321943219532196321973219832199322003220132202322033220432205322063220732208322093221032211322123221332214322153221632217322183221932220322213222232223322243222532226322273222832229322303223132232322333223432235322363223732238322393224032241322423224332244322453224632247322483224932250322513225232253322543225532256322573225832259322603226132262322633226432265322663226732268322693227032271322723227332274322753227632277322783227932280322813228232283322843228532286322873228832289322903229132292322933229432295322963229732298322993230032301323023230332304323053230632307323083230932310323113231232313323143231532316323173231832319323203232132322323233232432325323263232732328323293233032331323323233332334323353233632337323383233932340323413234232343323443234532346323473234832349323503235132352323533235432355323563235732358323593236032361323623236332364323653236632367323683236932370323713237232373323743237532376323773237832379323803238132382323833238432385323863238732388323893239032391323923239332394323953239632397323983239932400324013240232403324043240532406324073240832409324103241132412324133241432415324163241732418324193242032421324223242332424324253242632427324283242932430324313243232433324343243532436324373243832439324403244132442324433244432445324463244732448324493245032451324523245332454324553245632457324583245932460324613246232463324643246532466324673246832469324703247132472324733247432475324763247732478324793248032481324823248332484324853248632487324883248932490324913249232493324943249532496324973249832499325003250132502325033250432505325063250732508325093251032511325123251332514325153251632517325183251932520325213252232523325243252532526325273252832529325303253132532325333253432535325363253732538325393254032541325423254332544325453254632547325483254932550325513255232553325543255532556325573255832559325603256132562325633256432565325663256732568325693257032571325723257332574325753257632577325783257932580325813258232583325843258532586325873258832589325903259132592325933259432595325963259732598325993260032601326023260332604326053260632607326083260932610326113261232613326143261532616326173261832619326203262132622326233262432625326263262732628326293263032631326323263332634326353263632637326383263932640326413264232643326443264532646326473264832649326503265132652326533265432655326563265732658326593266032661326623266332664326653266632667326683266932670326713267232673326743267532676326773267832679326803268132682326833268432685326863268732688326893269032691326923269332694326953269632697326983269932700327013270232703327043270532706327073270832709327103271132712327133271432715327163271732718327193272032721327223272332724327253272632727327283272932730327313273232733327343273532736327373273832739327403274132742327433274432745327463274732748327493275032751327523275332754327553275632757327583275932760327613276232763327643276532766327673276832769327703277132772327733277432775327763277732778327793278032781327823278332784327853278632787327883278932790327913279232793327943279532796327973279832799328003280132802328033280432805328063280732808328093281032811328123281332814328153281632817328183281932820328213282232823328243282532826328273282832829328303283132832328333283432835328363283732838328393284032841328423284332844328453284632847328483284932850328513285232853328543285532856328573285832859328603286132862328633286432865328663286732868328693287032871328723287332874328753287632877328783287932880328813288232883328843288532886328873288832889328903289132892328933289432895328963289732898328993290032901329023290332904329053290632907329083290932910329113291232913329143291532916329173291832919329203292132922329233292432925329263292732928329293293032931329323293332934329353293632937329383293932940329413294232943329443294532946329473294832949329503295132952329533295432955329563295732958329593296032961329623296332964329653296632967329683296932970329713297232973329743297532976329773297832979329803298132982329833298432985329863298732988329893299032991329923299332994329953299632997329983299933000330013300233003330043300533006330073300833009330103301133012330133301433015330163301733018330193302033021330223302333024330253302633027330283302933030330313303233033330343303533036330373303833039330403304133042330433304433045330463304733048330493305033051330523305333054330553305633057330583305933060330613306233063330643306533066330673306833069330703307133072330733307433075330763307733078330793308033081330823308333084330853308633087330883308933090330913309233093330943309533096330973309833099331003310133102331033310433105331063310733108331093311033111331123311333114331153311633117331183311933120331213312233123331243312533126331273312833129331303313133132331333313433135331363313733138331393314033141331423314333144331453314633147331483314933150331513315233153331543315533156331573315833159331603316133162331633316433165331663316733168331693317033171331723317333174331753317633177331783317933180331813318233183331843318533186331873318833189331903319133192331933319433195331963319733198331993320033201332023320333204332053320633207332083320933210332113321233213332143321533216332173321833219332203322133222332233322433225332263322733228332293323033231332323323333234332353323633237332383323933240332413324233243332443324533246332473324833249332503325133252332533325433255332563325733258332593326033261332623326333264332653326633267332683326933270332713327233273332743327533276332773327833279332803328133282332833328433285332863328733288332893329033291332923329333294332953329633297332983329933300333013330233303333043330533306333073330833309333103331133312333133331433315333163331733318333193332033321333223332333324333253332633327333283332933330333313333233333333343333533336333373333833339333403334133342333433334433345333463334733348333493335033351333523335333354333553335633357333583335933360333613336233363333643336533366333673336833369333703337133372333733337433375333763337733378333793338033381333823338333384333853338633387333883338933390333913339233393333943339533396333973339833399334003340133402334033340433405334063340733408334093341033411334123341333414334153341633417334183341933420334213342233423334243342533426334273342833429334303343133432334333343433435334363343733438334393344033441334423344333444334453344633447334483344933450334513345233453334543345533456334573345833459334603346133462334633346433465334663346733468334693347033471334723347333474334753347633477334783347933480334813348233483334843348533486334873348833489334903349133492334933349433495334963349733498334993350033501 |
- From: Matthias Schiffer <mschiffer@universe-factory.net>
- Date: Tue, 10 Mar 2015 12:40:53 +0100
- Subject: mac80211: update ath10k to compat-wireless-2015-03-05
- Taken from http://openwrt.reigndropsfall.net/
- diff --git a/package/kernel/mac80211/patches/917-mac80211-rx-reordering.patch b/package/kernel/mac80211/patches/917-mac80211-rx-reordering.patch
- new file mode 100644
- index 0000000..1d0c559
- --- /dev/null
- +++ b/package/kernel/mac80211/patches/917-mac80211-rx-reordering.patch
- @@ -0,0 +1,271 @@
- +commit 08cf42e843f9a7e253502011c81677f61f7e5c42
- +Author: Michal Kazior <michal.kazior@tieto.com>
- +Date: Wed Jul 16 12:12:15 2014 +0200
- +
- + mac80211: add support for Rx reordering offloading
- +
- + Some drivers may be performing most of Tx/Rx
- + aggregation on their own (e.g. in firmware)
- + including AddBa/DelBa negotiations but may
- + otherwise require Rx reordering assistance.
- +
- + The patch exports 2 new functions for establishing
- + Rx aggregation sessions in assumption device
- + driver has taken care of the necessary
- + negotiations.
- +
- + Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
- + [fix endian bug]
- + Signed-off-by: Johannes Berg <johannes.berg@intel.com>
- +
- +--- a/include/net/mac80211.h
- ++++ b/include/net/mac80211.h
- +@@ -4481,6 +4481,40 @@ void ieee80211_stop_rx_ba_session(struct
- + */
- + void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn);
- +
- ++/**
- ++ * ieee80211_start_rx_ba_session_offl - start a Rx BA session
- ++ *
- ++ * Some device drivers may offload part of the Rx aggregation flow including
- ++ * AddBa/DelBa negotiation but may otherwise be incapable of full Rx
- ++ * reordering.
- ++ *
- ++ * Create structures responsible for reordering so device drivers may call here
- ++ * when they complete AddBa negotiation.
- ++ *
- ++ * @vif: &struct ieee80211_vif pointer from the add_interface callback
- ++ * @addr: station mac address
- ++ * @tid: the rx tid
- ++ */
- ++void ieee80211_start_rx_ba_session_offl(struct ieee80211_vif *vif,
- ++ const u8 *addr, u16 tid);
- ++
- ++/**
- ++ * ieee80211_stop_rx_ba_session_offl - stop a Rx BA session
- ++ *
- ++ * Some device drivers may offload part of the Rx aggregation flow including
- ++ * AddBa/DelBa negotiation but may otherwise be incapable of full Rx
- ++ * reordering.
- ++ *
- ++ * Destroy structures responsible for reordering so device drivers may call here
- ++ * when they complete DelBa negotiation.
- ++ *
- ++ * @vif: &struct ieee80211_vif pointer from the add_interface callback
- ++ * @addr: station mac address
- ++ * @tid: the rx tid
- ++ */
- ++void ieee80211_stop_rx_ba_session_offl(struct ieee80211_vif *vif,
- ++ const u8 *addr, u16 tid);
- ++
- + /* Rate control API */
- +
- + /**
- +--- a/net/mac80211/agg-rx.c
- ++++ b/net/mac80211/agg-rx.c
- +@@ -224,28 +224,15 @@ static void ieee80211_send_addba_resp(st
- + ieee80211_tx_skb(sdata, skb);
- + }
- +
- +-void ieee80211_process_addba_request(struct ieee80211_local *local,
- +- struct sta_info *sta,
- +- struct ieee80211_mgmt *mgmt,
- +- size_t len)
- ++void __ieee80211_start_rx_ba_session(struct sta_info *sta,
- ++ u8 dialog_token, u16 timeout,
- ++ u16 start_seq_num, u16 ba_policy, u16 tid,
- ++ u16 buf_size, bool tx)
- + {
- ++ struct ieee80211_local *local = sta->sdata->local;
- + struct tid_ampdu_rx *tid_agg_rx;
- +- u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
- +- u8 dialog_token;
- + int ret = -EOPNOTSUPP;
- +-
- +- /* extract session parameters from addba request frame */
- +- dialog_token = mgmt->u.action.u.addba_req.dialog_token;
- +- timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
- +- start_seq_num =
- +- le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
- +-
- +- capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
- +- ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
- +- tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
- +- buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
- +-
- +- status = WLAN_STATUS_REQUEST_DECLINED;
- ++ u16 status = WLAN_STATUS_REQUEST_DECLINED;
- +
- + if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
- + ht_dbg(sta->sdata,
- +@@ -264,7 +251,7 @@ void ieee80211_process_addba_request(str
- + status = WLAN_STATUS_INVALID_QOS_PARAM;
- + ht_dbg_ratelimited(sta->sdata,
- + "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
- +- mgmt->sa, tid, ba_policy, buf_size);
- ++ sta->sta.addr, tid, ba_policy, buf_size);
- + goto end_no_lock;
- + }
- + /* determine default buffer size */
- +@@ -281,7 +268,7 @@ void ieee80211_process_addba_request(str
- + if (sta->ampdu_mlme.tid_rx[tid]) {
- + ht_dbg_ratelimited(sta->sdata,
- + "unexpected AddBA Req from %pM on tid %u\n",
- +- mgmt->sa, tid);
- ++ sta->sta.addr, tid);
- +
- + /* delete existing Rx BA session on the same tid */
- + ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
- +@@ -350,6 +337,74 @@ end:
- + mutex_unlock(&sta->ampdu_mlme.mtx);
- +
- + end_no_lock:
- +- ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
- +- dialog_token, status, 1, buf_size, timeout);
- ++ if (tx)
- ++ ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
- ++ dialog_token, status, 1, buf_size,
- ++ timeout);
- ++}
- ++
- ++void ieee80211_process_addba_request(struct ieee80211_local *local,
- ++ struct sta_info *sta,
- ++ struct ieee80211_mgmt *mgmt,
- ++ size_t len)
- ++{
- ++ u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
- ++ u8 dialog_token;
- ++
- ++ /* extract session parameters from addba request frame */
- ++ dialog_token = mgmt->u.action.u.addba_req.dialog_token;
- ++ timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
- ++ start_seq_num =
- ++ le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
- ++
- ++ capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
- ++ ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
- ++ tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
- ++ buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
- ++
- ++ __ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
- ++ start_seq_num, ba_policy, tid,
- ++ buf_size, true);
- ++}
- ++
- ++void ieee80211_start_rx_ba_session_offl(struct ieee80211_vif *vif,
- ++ const u8 *addr, u16 tid)
- ++{
- ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
- ++ struct ieee80211_local *local = sdata->local;
- ++ struct ieee80211_rx_agg *rx_agg;
- ++ struct sk_buff *skb = dev_alloc_skb(0);
- ++
- ++ if (unlikely(!skb))
- ++ return;
- ++
- ++ rx_agg = (struct ieee80211_rx_agg *) &skb->cb;
- ++ memcpy(&rx_agg->addr, addr, ETH_ALEN);
- ++ rx_agg->tid = tid;
- ++
- ++ skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_START;
- ++ skb_queue_tail(&sdata->skb_queue, skb);
- ++ ieee80211_queue_work(&local->hw, &sdata->work);
- ++}
- ++EXPORT_SYMBOL(ieee80211_start_rx_ba_session_offl);
- ++
- ++void ieee80211_stop_rx_ba_session_offl(struct ieee80211_vif *vif,
- ++ const u8 *addr, u16 tid)
- ++{
- ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
- ++ struct ieee80211_local *local = sdata->local;
- ++ struct ieee80211_rx_agg *rx_agg;
- ++ struct sk_buff *skb = dev_alloc_skb(0);
- ++
- ++ if (unlikely(!skb))
- ++ return;
- ++
- ++ rx_agg = (struct ieee80211_rx_agg *) &skb->cb;
- ++ memcpy(&rx_agg->addr, addr, ETH_ALEN);
- ++ rx_agg->tid = tid;
- ++
- ++ skb->pkt_type = IEEE80211_SDATA_QUEUE_RX_AGG_STOP;
- ++ skb_queue_tail(&sdata->skb_queue, skb);
- ++ ieee80211_queue_work(&local->hw, &sdata->work);
- + }
- ++EXPORT_SYMBOL(ieee80211_stop_rx_ba_session_offl);
- +--- a/net/mac80211/ieee80211_i.h
- ++++ b/net/mac80211/ieee80211_i.h
- +@@ -902,10 +902,17 @@ ieee80211_vif_get_shift(struct ieee80211
- + return shift;
- + }
- +
- ++struct ieee80211_rx_agg {
- ++ u8 addr[ETH_ALEN];
- ++ u16 tid;
- ++};
- ++
- + enum sdata_queue_type {
- + IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0,
- + IEEE80211_SDATA_QUEUE_AGG_START = 1,
- + IEEE80211_SDATA_QUEUE_AGG_STOP = 2,
- ++ IEEE80211_SDATA_QUEUE_RX_AGG_START = 3,
- ++ IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4,
- + };
- +
- + enum {
- +@@ -1554,6 +1561,10 @@ void ___ieee80211_stop_rx_ba_session(str
- + u16 initiator, u16 reason, bool stop);
- + void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
- + u16 initiator, u16 reason, bool stop);
- ++void __ieee80211_start_rx_ba_session(struct sta_info *sta,
- ++ u8 dialog_token, u16 timeout,
- ++ u16 start_seq_num, u16 ba_policy, u16 tid,
- ++ u16 buf_size, bool tx);
- + void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
- + enum ieee80211_agg_stop_reason reason);
- + void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
- +--- a/net/mac80211/iface.c
- ++++ b/net/mac80211/iface.c
- +@@ -1154,6 +1154,7 @@ static void ieee80211_iface_work(struct
- + struct sk_buff *skb;
- + struct sta_info *sta;
- + struct ieee80211_ra_tid *ra_tid;
- ++ struct ieee80211_rx_agg *rx_agg;
- +
- + if (!ieee80211_sdata_running(sdata))
- + return;
- +@@ -1181,6 +1182,34 @@ static void ieee80211_iface_work(struct
- + ra_tid = (void *)&skb->cb;
- + ieee80211_stop_tx_ba_cb(&sdata->vif, ra_tid->ra,
- + ra_tid->tid);
- ++ } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_START) {
- ++ rx_agg = (void *)&skb->cb;
- ++ mutex_lock(&local->sta_mtx);
- ++ sta = sta_info_get_bss(sdata, rx_agg->addr);
- ++ if (sta) {
- ++ u16 last_seq;
- ++
- ++ last_seq = le16_to_cpu(
- ++ sta->last_seq_ctrl[rx_agg->tid]);
- ++
- ++ __ieee80211_start_rx_ba_session(sta,
- ++ 0, 0,
- ++ ieee80211_sn_inc(last_seq),
- ++ 1, rx_agg->tid,
- ++ IEEE80211_MAX_AMPDU_BUF,
- ++ false);
- ++ }
- ++ mutex_unlock(&local->sta_mtx);
- ++ } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_STOP) {
- ++ rx_agg = (void *)&skb->cb;
- ++ mutex_lock(&local->sta_mtx);
- ++ sta = sta_info_get_bss(sdata, rx_agg->addr);
- ++ if (sta)
- ++ __ieee80211_stop_rx_ba_session(sta,
- ++ rx_agg->tid,
- ++ WLAN_BACK_RECIPIENT, 0,
- ++ false);
- ++ mutex_unlock(&local->sta_mtx);
- + } else if (ieee80211_is_action(mgmt->frame_control) &&
- + mgmt->u.action.category == WLAN_CATEGORY_BACK) {
- + int len = skb->len;
- diff --git a/package/kernel/mac80211/patches/918-ath-spectral-debugfs.patch b/package/kernel/mac80211/patches/918-ath-spectral-debugfs.patch
- new file mode 100644
- index 0000000..d0c1bbd
- --- /dev/null
- +++ b/package/kernel/mac80211/patches/918-ath-spectral-debugfs.patch
- @@ -0,0 +1,192 @@
- +--- a/drivers/net/wireless/ath/ath9k/spectral.h
- ++++ b/drivers/net/wireless/ath/ath9k/spectral.h
- +@@ -17,6 +17,8 @@
- + #ifndef SPECTRAL_H
- + #define SPECTRAL_H
- +
- ++#include "../spectral_common.h"
- ++
- + /* enum spectral_mode:
- + *
- + * @SPECTRAL_DISABLED: spectral mode is disabled
- +@@ -54,8 +56,6 @@ struct ath_ht20_mag_info {
- + u8 max_exp;
- + } __packed;
- +
- +-#define SPECTRAL_HT20_NUM_BINS 56
- +-
- + /* WARNING: don't actually use this struct! MAC may vary the amount of
- + * data by -1/+2. This struct is for reference only.
- + */
- +@@ -83,8 +83,6 @@ struct ath_ht20_40_mag_info {
- + u8 max_exp;
- + } __packed;
- +
- +-#define SPECTRAL_HT20_40_NUM_BINS 128
- +-
- + /* WARNING: don't actually use this struct! MAC may vary the amount of
- + * data. This struct is for reference only.
- + */
- +@@ -125,71 +123,6 @@ static inline u8 spectral_bitmap_weight(
- + return bins[0] & 0x3f;
- + }
- +
- +-/* FFT sample format given to userspace via debugfs.
- +- *
- +- * Please keep the type/length at the front position and change
- +- * other fields after adding another sample type
- +- *
- +- * TODO: this might need rework when switching to nl80211-based
- +- * interface.
- +- */
- +-enum ath_fft_sample_type {
- +- ATH_FFT_SAMPLE_HT20 = 1,
- +- ATH_FFT_SAMPLE_HT20_40,
- +-};
- +-
- +-struct fft_sample_tlv {
- +- u8 type; /* see ath_fft_sample */
- +- __be16 length;
- +- /* type dependent data follows */
- +-} __packed;
- +-
- +-struct fft_sample_ht20 {
- +- struct fft_sample_tlv tlv;
- +-
- +- u8 max_exp;
- +-
- +- __be16 freq;
- +- s8 rssi;
- +- s8 noise;
- +-
- +- __be16 max_magnitude;
- +- u8 max_index;
- +- u8 bitmap_weight;
- +-
- +- __be64 tsf;
- +-
- +- u8 data[SPECTRAL_HT20_NUM_BINS];
- +-} __packed;
- +-
- +-struct fft_sample_ht20_40 {
- +- struct fft_sample_tlv tlv;
- +-
- +- u8 channel_type;
- +- __be16 freq;
- +-
- +- s8 lower_rssi;
- +- s8 upper_rssi;
- +-
- +- __be64 tsf;
- +-
- +- s8 lower_noise;
- +- s8 upper_noise;
- +-
- +- __be16 lower_max_magnitude;
- +- __be16 upper_max_magnitude;
- +-
- +- u8 lower_max_index;
- +- u8 upper_max_index;
- +-
- +- u8 lower_bitmap_weight;
- +- u8 upper_bitmap_weight;
- +-
- +- u8 max_exp;
- +-
- +- u8 data[SPECTRAL_HT20_40_NUM_BINS];
- +-} __packed;
- +-
- + void ath9k_spectral_init_debug(struct ath_softc *sc);
- + void ath9k_spectral_deinit_debug(struct ath_softc *sc);
- +
- +--- /dev/null
- ++++ b/drivers/net/wireless/ath/spectral_common.h
- +@@ -0,0 +1,88 @@
- ++/*
- ++ * Copyright (c) 2013 Qualcomm Atheros, Inc.
- ++ *
- ++ * Permission to use, copy, modify, and/or distribute this software for any
- ++ * purpose with or without fee is hereby granted, provided that the above
- ++ * copyright notice and this permission notice appear in all copies.
- ++ *
- ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ++ */
- ++
- ++#ifndef SPECTRAL_COMMON_H
- ++#define SPECTRAL_COMMON_H
- ++
- ++#define SPECTRAL_HT20_NUM_BINS 56
- ++#define SPECTRAL_HT20_40_NUM_BINS 128
- ++
- ++/* FFT sample format given to userspace via debugfs.
- ++ *
- ++ * Please keep the type/length at the front position and change
- ++ * other fields after adding another sample type
- ++ *
- ++ * TODO: this might need rework when switching to nl80211-based
- ++ * interface.
- ++ */
- ++enum ath_fft_sample_type {
- ++ ATH_FFT_SAMPLE_HT20 = 1,
- ++ ATH_FFT_SAMPLE_HT20_40,
- ++};
- ++
- ++struct fft_sample_tlv {
- ++ u8 type; /* see ath_fft_sample */
- ++ __be16 length;
- ++ /* type dependent data follows */
- ++} __packed;
- ++
- ++struct fft_sample_ht20 {
- ++ struct fft_sample_tlv tlv;
- ++
- ++ u8 max_exp;
- ++
- ++ __be16 freq;
- ++ s8 rssi;
- ++ s8 noise;
- ++
- ++ __be16 max_magnitude;
- ++ u8 max_index;
- ++ u8 bitmap_weight;
- ++
- ++ __be64 tsf;
- ++
- ++ u8 data[SPECTRAL_HT20_NUM_BINS];
- ++} __packed;
- ++
- ++struct fft_sample_ht20_40 {
- ++ struct fft_sample_tlv tlv;
- ++
- ++ u8 channel_type;
- ++ __be16 freq;
- ++
- ++ s8 lower_rssi;
- ++ s8 upper_rssi;
- ++
- ++ __be64 tsf;
- ++
- ++ s8 lower_noise;
- ++ s8 upper_noise;
- ++
- ++ __be16 lower_max_magnitude;
- ++ __be16 upper_max_magnitude;
- ++
- ++ u8 lower_max_index;
- ++ u8 upper_max_index;
- ++
- ++ u8 lower_bitmap_weight;
- ++ u8 upper_bitmap_weight;
- ++
- ++ u8 max_exp;
- ++
- ++ u8 data[SPECTRAL_HT20_40_NUM_BINS];
- ++} __packed;
- ++
- ++#endif /* SPECTRAL_COMMON_H */
- diff --git a/package/kernel/mac80211/patches/919-update-ath10k.patch b/package/kernel/mac80211/patches/919-update-ath10k.patch
- new file mode 100644
- index 0000000..0f5d87a
- --- /dev/null
- +++ b/package/kernel/mac80211/patches/919-update-ath10k.patch
- @@ -0,0 +1,32869 @@
- +--- a/drivers/net/wireless/ath/ath10k/Kconfig
- ++++ b/drivers/net/wireless/ath/ath10k/Kconfig
- +@@ -26,13 +26,15 @@ config ATH10K_DEBUG
- +
- + config ATH10K_DEBUGFS
- + bool "Atheros ath10k debugfs support"
- +- depends on ATH10K
- ++ depends on ATH10K && DEBUG_FS
- ++ depends on RELAY
- + ---help---
- + Enabled debugfs support
- +
- + If unsure, say Y to make it easier to debug problems.
- +
- + config ATH10K_TRACING
- ++ depends on !KERNEL_3_4
- + bool "Atheros ath10k tracing support"
- + depends on ATH10K
- + depends on EVENT_TRACING
- +--- a/drivers/net/wireless/ath/ath10k/Makefile
- ++++ b/drivers/net/wireless/ath/ath10k/Makefile
- +@@ -8,9 +8,15 @@ ath10k_core-y += mac.o \
- + htt_tx.o \
- + txrx.o \
- + wmi.o \
- +- bmi.o
- ++ wmi-tlv.o \
- ++ bmi.o \
- ++ hw.o
- +
- ++ath10k_core-$(CPTCFG_ATH10K_DEBUGFS) += spectral.o
- ++ath10k_core-$(CPTCFG_NL80211_TESTMODE) += testmode.o
- + ath10k_core-$(CPTCFG_ATH10K_TRACING) += trace.o
- ++ath10k_core-$(CONFIG_THERMAL) += thermal.o
- ++ath10k_core-$(CPTCFG_MAC80211_DEBUGFS) += debugfs_sta.o
- +
- + obj-$(CPTCFG_ATH10K_PCI) += ath10k_pci.o
- + ath10k_pci-y += pci.o \
- +--- a/drivers/net/wireless/ath/ath10k/bmi.c
- ++++ b/drivers/net/wireless/ath/ath10k/bmi.c
- +@@ -22,7 +22,7 @@
- +
- + void ath10k_bmi_start(struct ath10k *ar)
- + {
- +- ath10k_dbg(ATH10K_DBG_BMI, "bmi start\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n");
- +
- + ar->bmi.done_sent = false;
- + }
- +@@ -33,10 +33,10 @@ int ath10k_bmi_done(struct ath10k *ar)
- + u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
- + int ret;
- +
- +- ath10k_dbg(ATH10K_DBG_BMI, "bmi done\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi done\n");
- +
- + if (ar->bmi.done_sent) {
- +- ath10k_dbg(ATH10K_DBG_BMI, "bmi skipped\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi skipped\n");
- + return 0;
- + }
- +
- +@@ -45,7 +45,7 @@ int ath10k_bmi_done(struct ath10k *ar)
- +
- + ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
- + if (ret) {
- +- ath10k_warn("unable to write to the device: %d\n", ret);
- ++ ath10k_warn(ar, "unable to write to the device: %d\n", ret);
- + return ret;
- + }
- +
- +@@ -61,10 +61,10 @@ int ath10k_bmi_get_target_info(struct at
- + u32 resplen = sizeof(resp.get_target_info);
- + int ret;
- +
- +- ath10k_dbg(ATH10K_DBG_BMI, "bmi get target info\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info\n");
- +
- + if (ar->bmi.done_sent) {
- +- ath10k_warn("BMI Get Target Info Command disallowed\n");
- ++ ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
- + return -EBUSY;
- + }
- +
- +@@ -72,12 +72,12 @@ int ath10k_bmi_get_target_info(struct at
- +
- + ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
- + if (ret) {
- +- ath10k_warn("unable to get target info from device\n");
- ++ ath10k_warn(ar, "unable to get target info from device\n");
- + return ret;
- + }
- +
- + if (resplen < sizeof(resp.get_target_info)) {
- +- ath10k_warn("invalid get_target_info response length (%d)\n",
- ++ ath10k_warn(ar, "invalid get_target_info response length (%d)\n",
- + resplen);
- + return -EIO;
- + }
- +@@ -97,11 +97,11 @@ int ath10k_bmi_read_memory(struct ath10k
- + u32 rxlen;
- + int ret;
- +
- +- ath10k_dbg(ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
- + address, length);
- +
- + if (ar->bmi.done_sent) {
- +- ath10k_warn("command disallowed\n");
- ++ ath10k_warn(ar, "command disallowed\n");
- + return -EBUSY;
- + }
- +
- +@@ -115,7 +115,7 @@ int ath10k_bmi_read_memory(struct ath10k
- + ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
- + &resp, &rxlen);
- + if (ret) {
- +- ath10k_warn("unable to read from the device (%d)\n",
- ++ ath10k_warn(ar, "unable to read from the device (%d)\n",
- + ret);
- + return ret;
- + }
- +@@ -137,11 +137,11 @@ int ath10k_bmi_write_memory(struct ath10
- + u32 txlen;
- + int ret;
- +
- +- ath10k_dbg(ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
- + address, length);
- +
- + if (ar->bmi.done_sent) {
- +- ath10k_warn("command disallowed\n");
- ++ ath10k_warn(ar, "command disallowed\n");
- + return -EBUSY;
- + }
- +
- +@@ -159,7 +159,7 @@ int ath10k_bmi_write_memory(struct ath10
- + ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
- + NULL, NULL);
- + if (ret) {
- +- ath10k_warn("unable to write to the device (%d)\n",
- ++ ath10k_warn(ar, "unable to write to the device (%d)\n",
- + ret);
- + return ret;
- + }
- +@@ -183,11 +183,11 @@ int ath10k_bmi_execute(struct ath10k *ar
- + u32 resplen = sizeof(resp.execute);
- + int ret;
- +
- +- ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
- + address, param);
- +
- + if (ar->bmi.done_sent) {
- +- ath10k_warn("command disallowed\n");
- ++ ath10k_warn(ar, "command disallowed\n");
- + return -EBUSY;
- + }
- +
- +@@ -197,19 +197,19 @@ int ath10k_bmi_execute(struct ath10k *ar
- +
- + ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
- + if (ret) {
- +- ath10k_warn("unable to read from the device\n");
- ++ ath10k_warn(ar, "unable to read from the device\n");
- + return ret;
- + }
- +
- + if (resplen < sizeof(resp.execute)) {
- +- ath10k_warn("invalid execute response length (%d)\n",
- ++ ath10k_warn(ar, "invalid execute response length (%d)\n",
- + resplen);
- + return -EIO;
- + }
- +
- + *result = __le32_to_cpu(resp.execute.result);
- +
- +- ath10k_dbg(ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
- ++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
- +
- + return 0;
- + }
- +@@ -221,11 +221,11 @@ int ath10k_bmi_lz_data(struct ath10k *ar
- + u32 txlen;
- + int ret;
- +
- +- ath10k_dbg(ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n",
- + buffer, length);
- +
- + if (ar->bmi.done_sent) {
- +- ath10k_warn("command disallowed\n");
- ++ ath10k_warn(ar, "command disallowed\n");
- + return -EBUSY;
- + }
- +
- +@@ -241,7 +241,7 @@ int ath10k_bmi_lz_data(struct ath10k *ar
- + ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
- + NULL, NULL);
- + if (ret) {
- +- ath10k_warn("unable to write to the device\n");
- ++ ath10k_warn(ar, "unable to write to the device\n");
- + return ret;
- + }
- +
- +@@ -258,11 +258,11 @@ int ath10k_bmi_lz_stream_start(struct at
- + u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
- + int ret;
- +
- +- ath10k_dbg(ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
- + address);
- +
- + if (ar->bmi.done_sent) {
- +- ath10k_warn("command disallowed\n");
- ++ ath10k_warn(ar, "command disallowed\n");
- + return -EBUSY;
- + }
- +
- +@@ -271,7 +271,7 @@ int ath10k_bmi_lz_stream_start(struct at
- +
- + ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
- + if (ret) {
- +- ath10k_warn("unable to Start LZ Stream to the device\n");
- ++ ath10k_warn(ar, "unable to Start LZ Stream to the device\n");
- + return ret;
- + }
- +
- +@@ -286,7 +286,7 @@ int ath10k_bmi_fast_download(struct ath1
- + u32 trailer_len = length - head_len;
- + int ret;
- +
- +- ath10k_dbg(ATH10K_DBG_BMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_BMI,
- + "bmi fast download address 0x%x buffer 0x%p length %d\n",
- + address, buffer, length);
- +
- +--- a/drivers/net/wireless/ath/ath10k/bmi.h
- ++++ b/drivers/net/wireless/ath/ath10k/bmi.h
- +@@ -177,7 +177,6 @@ struct bmi_target_info {
- + u32 type;
- + };
- +
- +-
- + /* in msec */
- + #define BMI_COMMUNICATION_TIMEOUT_HZ (1*HZ)
- +
- +@@ -201,7 +200,8 @@ int ath10k_bmi_write_memory(struct ath10
- + \
- + addr = host_interest_item_address(HI_ITEM(item)); \
- + ret = ath10k_bmi_read_memory(ar, addr, (u8 *)&tmp, 4); \
- +- *val = __le32_to_cpu(tmp); \
- ++ if (!ret) \
- ++ *val = __le32_to_cpu(tmp); \
- + ret; \
- + })
- +
- +--- a/drivers/net/wireless/ath/ath10k/ce.c
- ++++ b/drivers/net/wireless/ath/ath10k/ce.c
- +@@ -260,7 +260,6 @@ static inline void ath10k_ce_engine_int_
- + ath10k_pci_write32(ar, ce_ctrl_addr + HOST_IS_ADDRESS, mask);
- + }
- +
- +-
- + /*
- + * Guts of ath10k_ce_send, used by both ath10k_ce_send and
- + * ath10k_ce_sendlist_send.
- +@@ -284,13 +283,9 @@ int ath10k_ce_send_nolock(struct ath10k_
- + int ret = 0;
- +
- + if (nbytes > ce_state->src_sz_max)
- +- ath10k_warn("%s: send more we can (nbytes: %d, max: %d)\n",
- ++ ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n",
- + __func__, nbytes, ce_state->src_sz_max);
- +
- +- ret = ath10k_pci_wake(ar);
- +- if (ret)
- +- return ret;
- +-
- + if (unlikely(CE_RING_DELTA(nentries_mask,
- + write_index, sw_index - 1) <= 0)) {
- + ret = -ENOSR;
- +@@ -325,10 +320,36 @@ int ath10k_ce_send_nolock(struct ath10k_
- +
- + src_ring->write_index = write_index;
- + exit:
- +- ath10k_pci_sleep(ar);
- + return ret;
- + }
- +
- ++void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe)
- ++{
- ++ struct ath10k *ar = pipe->ar;
- ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++ struct ath10k_ce_ring *src_ring = pipe->src_ring;
- ++ u32 ctrl_addr = pipe->ctrl_addr;
- ++
- ++ lockdep_assert_held(&ar_pci->ce_lock);
- ++
- ++ /*
- ++ * This function must be called only if there is an incomplete
- ++ * scatter-gather transfer (before index register is updated)
- ++ * that needs to be cleaned up.
- ++ */
- ++ if (WARN_ON_ONCE(src_ring->write_index == src_ring->sw_index))
- ++ return;
- ++
- ++ if (WARN_ON_ONCE(src_ring->write_index ==
- ++ ath10k_ce_src_ring_write_index_get(ar, ctrl_addr)))
- ++ return;
- ++
- ++ src_ring->write_index--;
- ++ src_ring->write_index &= src_ring->nentries_mask;
- ++
- ++ src_ring->per_transfer_context[src_ring->write_index] = NULL;
- ++}
- ++
- + int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
- + void *per_transfer_context,
- + u32 buffer,
- +@@ -363,49 +384,56 @@ int ath10k_ce_num_free_src_entries(struc
- + return delta;
- + }
- +
- +-int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
- +- void *per_recv_context,
- +- u32 buffer)
- ++int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe)
- + {
- +- struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
- +- u32 ctrl_addr = ce_state->ctrl_addr;
- +- struct ath10k *ar = ce_state->ar;
- ++ struct ath10k *ar = pipe->ar;
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++ struct ath10k_ce_ring *dest_ring = pipe->dest_ring;
- + unsigned int nentries_mask = dest_ring->nentries_mask;
- +- unsigned int write_index;
- +- unsigned int sw_index;
- +- int ret;
- ++ unsigned int write_index = dest_ring->write_index;
- ++ unsigned int sw_index = dest_ring->sw_index;
- +
- +- spin_lock_bh(&ar_pci->ce_lock);
- +- write_index = dest_ring->write_index;
- +- sw_index = dest_ring->sw_index;
- ++ lockdep_assert_held(&ar_pci->ce_lock);
- +
- +- ret = ath10k_pci_wake(ar);
- +- if (ret)
- +- goto out;
- ++ return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1);
- ++}
- +
- +- if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) {
- +- struct ce_desc *base = dest_ring->base_addr_owner_space;
- +- struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index);
- ++int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
- ++{
- ++ struct ath10k *ar = pipe->ar;
- ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++ struct ath10k_ce_ring *dest_ring = pipe->dest_ring;
- ++ unsigned int nentries_mask = dest_ring->nentries_mask;
- ++ unsigned int write_index = dest_ring->write_index;
- ++ unsigned int sw_index = dest_ring->sw_index;
- ++ struct ce_desc *base = dest_ring->base_addr_owner_space;
- ++ struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index);
- ++ u32 ctrl_addr = pipe->ctrl_addr;
- +
- +- /* Update destination descriptor */
- +- desc->addr = __cpu_to_le32(buffer);
- +- desc->nbytes = 0;
- ++ lockdep_assert_held(&ar_pci->ce_lock);
- +
- +- dest_ring->per_transfer_context[write_index] =
- +- per_recv_context;
- ++ if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0)
- ++ return -EIO;
- +
- +- /* Update Destination Ring Write Index */
- +- write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
- +- ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index);
- +- dest_ring->write_index = write_index;
- +- ret = 0;
- +- } else {
- +- ret = -EIO;
- +- }
- +- ath10k_pci_sleep(ar);
- ++ desc->addr = __cpu_to_le32(paddr);
- ++ desc->nbytes = 0;
- ++
- ++ dest_ring->per_transfer_context[write_index] = ctx;
- ++ write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
- ++ ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index);
- ++ dest_ring->write_index = write_index;
- ++
- ++ return 0;
- ++}
- +
- +-out:
- ++int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
- ++{
- ++ struct ath10k *ar = pipe->ar;
- ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++ int ret;
- ++
- ++ spin_lock_bh(&ar_pci->ce_lock);
- ++ ret = __ath10k_ce_rx_post_buf(pipe, ctx, paddr);
- + spin_unlock_bh(&ar_pci->ce_lock);
- +
- + return ret;
- +@@ -415,12 +443,12 @@ out:
- + * Guts of ath10k_ce_completed_recv_next.
- + * The caller takes responsibility for any necessary locking.
- + */
- +-static int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
- +- void **per_transfer_contextp,
- +- u32 *bufferp,
- +- unsigned int *nbytesp,
- +- unsigned int *transfer_idp,
- +- unsigned int *flagsp)
- ++int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
- ++ void **per_transfer_contextp,
- ++ u32 *bufferp,
- ++ unsigned int *nbytesp,
- ++ unsigned int *transfer_idp,
- ++ unsigned int *flagsp)
- + {
- + struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
- + unsigned int nentries_mask = dest_ring->nentries_mask;
- +@@ -530,6 +558,7 @@ int ath10k_ce_revoke_recv_next(struct at
- +
- + /* sanity */
- + dest_ring->per_transfer_context[sw_index] = NULL;
- ++ desc->nbytes = 0;
- +
- + /* Update sw_index */
- + sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
- +@@ -548,11 +577,11 @@ int ath10k_ce_revoke_recv_next(struct at
- + * Guts of ath10k_ce_completed_send_next.
- + * The caller takes responsibility for any necessary locking.
- + */
- +-static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
- +- void **per_transfer_contextp,
- +- u32 *bufferp,
- +- unsigned int *nbytesp,
- +- unsigned int *transfer_idp)
- ++int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
- ++ void **per_transfer_contextp,
- ++ u32 *bufferp,
- ++ unsigned int *nbytesp,
- ++ unsigned int *transfer_idp)
- + {
- + struct ath10k_ce_ring *src_ring = ce_state->src_ring;
- + u32 ctrl_addr = ce_state->ctrl_addr;
- +@@ -561,7 +590,6 @@ static int ath10k_ce_completed_send_next
- + unsigned int sw_index = src_ring->sw_index;
- + struct ce_desc *sdesc, *sbase;
- + unsigned int read_index;
- +- int ret;
- +
- + if (src_ring->hw_index == sw_index) {
- + /*
- +@@ -572,20 +600,17 @@ static int ath10k_ce_completed_send_next
- + * value of the HW index has become stale.
- + */
- +
- +- ret = ath10k_pci_wake(ar);
- +- if (ret)
- +- return ret;
- +-
- +- src_ring->hw_index =
- +- ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
- +- src_ring->hw_index &= nentries_mask;
- ++ read_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
- ++ if (read_index == 0xffffffff)
- ++ return -ENODEV;
- +
- +- ath10k_pci_sleep(ar);
- ++ read_index &= nentries_mask;
- ++ src_ring->hw_index = read_index;
- + }
- +
- + read_index = src_ring->hw_index;
- +
- +- if ((read_index == sw_index) || (read_index == 0xffffffff))
- ++ if (read_index == sw_index)
- + return -EIO;
- +
- + sbase = src_ring->shadow_base;
- +@@ -701,11 +726,6 @@ void ath10k_ce_per_engine_service(struct
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
- + u32 ctrl_addr = ce_state->ctrl_addr;
- +- int ret;
- +-
- +- ret = ath10k_pci_wake(ar);
- +- if (ret)
- +- return;
- +
- + spin_lock_bh(&ar_pci->ce_lock);
- +
- +@@ -730,7 +750,6 @@ void ath10k_ce_per_engine_service(struct
- + ath10k_ce_engine_int_status_clear(ar, ctrl_addr, CE_WATERMARK_MASK);
- +
- + spin_unlock_bh(&ar_pci->ce_lock);
- +- ath10k_pci_sleep(ar);
- + }
- +
- + /*
- +@@ -741,13 +760,9 @@ void ath10k_ce_per_engine_service(struct
- +
- + void ath10k_ce_per_engine_service_any(struct ath10k *ar)
- + {
- +- int ce_id, ret;
- ++ int ce_id;
- + u32 intr_summary;
- +
- +- ret = ath10k_pci_wake(ar);
- +- if (ret)
- +- return;
- +-
- + intr_summary = CE_INTERRUPT_SUMMARY(ar);
- +
- + for (ce_id = 0; intr_summary && (ce_id < CE_COUNT); ce_id++) {
- +@@ -759,8 +774,6 @@ void ath10k_ce_per_engine_service_any(st
- +
- + ath10k_ce_per_engine_service(ar, ce_id);
- + }
- +-
- +- ath10k_pci_sleep(ar);
- + }
- +
- + /*
- +@@ -770,16 +783,11 @@ void ath10k_ce_per_engine_service_any(st
- + *
- + * Called with ce_lock held.
- + */
- +-static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
- +- int disable_copy_compl_intr)
- ++static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state)
- + {
- + u32 ctrl_addr = ce_state->ctrl_addr;
- + struct ath10k *ar = ce_state->ar;
- +- int ret;
- +-
- +- ret = ath10k_pci_wake(ar);
- +- if (ret)
- +- return;
- ++ bool disable_copy_compl_intr = ce_state->attr_flags & CE_ATTR_DIS_INTR;
- +
- + if ((!disable_copy_compl_intr) &&
- + (ce_state->send_cb || ce_state->recv_cb))
- +@@ -788,54 +796,33 @@ static void ath10k_ce_per_engine_handler
- + ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
- +
- + ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
- +-
- +- ath10k_pci_sleep(ar);
- + }
- +
- + int ath10k_ce_disable_interrupts(struct ath10k *ar)
- + {
- +- int ce_id, ret;
- +-
- +- ret = ath10k_pci_wake(ar);
- +- if (ret)
- +- return ret;
- ++ int ce_id;
- +
- + for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
- +- u32 ctrl_addr = ath10k_ce_base_address(ce_id);
- ++ u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id);
- +
- + ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
- + ath10k_ce_error_intr_disable(ar, ctrl_addr);
- + ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
- + }
- +
- +- ath10k_pci_sleep(ar);
- +-
- + return 0;
- + }
- +
- +-void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
- +- void (*send_cb)(struct ath10k_ce_pipe *),
- +- int disable_interrupts)
- ++void ath10k_ce_enable_interrupts(struct ath10k *ar)
- + {
- +- struct ath10k *ar = ce_state->ar;
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++ int ce_id;
- +
- +- spin_lock_bh(&ar_pci->ce_lock);
- +- ce_state->send_cb = send_cb;
- +- ath10k_ce_per_engine_handler_adjust(ce_state, disable_interrupts);
- +- spin_unlock_bh(&ar_pci->ce_lock);
- +-}
- +-
- +-void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
- +- void (*recv_cb)(struct ath10k_ce_pipe *))
- +-{
- +- struct ath10k *ar = ce_state->ar;
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +-
- +- spin_lock_bh(&ar_pci->ce_lock);
- +- ce_state->recv_cb = recv_cb;
- +- ath10k_ce_per_engine_handler_adjust(ce_state, 0);
- +- spin_unlock_bh(&ar_pci->ce_lock);
- ++ /* Skip the last copy engine, CE7 the diagnostic window, as that
- ++ * uses polling and isn't initialized for interrupts.
- ++ */
- ++ for (ce_id = 0; ce_id < CE_COUNT - 1; ce_id++)
- ++ ath10k_ce_per_engine_handler_adjust(&ar_pci->ce_states[ce_id]);
- + }
- +
- + static int ath10k_ce_init_src_ring(struct ath10k *ar,
- +@@ -845,12 +832,12 @@ static int ath10k_ce_init_src_ring(struc
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
- + struct ath10k_ce_ring *src_ring = ce_state->src_ring;
- +- u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id);
- ++ u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id);
- +
- + nentries = roundup_pow_of_two(attr->src_nentries);
- +
- +- memset(src_ring->per_transfer_context, 0,
- +- nentries * sizeof(*src_ring->per_transfer_context));
- ++ memset(src_ring->base_addr_owner_space, 0,
- ++ nentries * sizeof(struct ce_desc));
- +
- + src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
- + src_ring->sw_index &= src_ring->nentries_mask;
- +@@ -868,7 +855,7 @@ static int ath10k_ce_init_src_ring(struc
- + ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0);
- + ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries);
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT,
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- + "boot init ce src ring id %d entries %d base_addr %p\n",
- + ce_id, nentries, src_ring->base_addr_owner_space);
- +
- +@@ -882,12 +869,12 @@ static int ath10k_ce_init_dest_ring(stru
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
- + struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
- +- u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id);
- ++ u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id);
- +
- + nentries = roundup_pow_of_two(attr->dest_nentries);
- +
- +- memset(dest_ring->per_transfer_context, 0,
- +- nentries * sizeof(*dest_ring->per_transfer_context));
- ++ memset(dest_ring->base_addr_owner_space, 0,
- ++ nentries * sizeof(struct ce_desc));
- +
- + dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr);
- + dest_ring->sw_index &= dest_ring->nentries_mask;
- +@@ -902,7 +889,7 @@ static int ath10k_ce_init_dest_ring(stru
- + ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0);
- + ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries);
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT,
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- + "boot ce dest ring id %d entries %d base_addr %p\n",
- + ce_id, nentries, dest_ring->base_addr_owner_space);
- +
- +@@ -1039,59 +1026,32 @@ ath10k_ce_alloc_dest_ring(struct ath10k
- + int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
- + const struct ce_attr *attr)
- + {
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +- struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
- + int ret;
- +
- +- /*
- +- * Make sure there's enough CE ringbuffer entries for HTT TX to avoid
- +- * additional TX locking checks.
- +- *
- +- * For the lack of a better place do the check here.
- +- */
- +- BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC >
- +- (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
- +- BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
- +- (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
- +-
- +- ret = ath10k_pci_wake(ar);
- +- if (ret)
- +- return ret;
- +-
- +- spin_lock_bh(&ar_pci->ce_lock);
- +- ce_state->ar = ar;
- +- ce_state->id = ce_id;
- +- ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
- +- ce_state->attr_flags = attr->flags;
- +- ce_state->src_sz_max = attr->src_sz_max;
- +- spin_unlock_bh(&ar_pci->ce_lock);
- +-
- + if (attr->src_nentries) {
- + ret = ath10k_ce_init_src_ring(ar, ce_id, attr);
- + if (ret) {
- +- ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n",
- ++ ath10k_err(ar, "Failed to initialize CE src ring for ID: %d (%d)\n",
- + ce_id, ret);
- +- goto out;
- ++ return ret;
- + }
- + }
- +
- + if (attr->dest_nentries) {
- + ret = ath10k_ce_init_dest_ring(ar, ce_id, attr);
- + if (ret) {
- +- ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n",
- ++ ath10k_err(ar, "Failed to initialize CE dest ring for ID: %d (%d)\n",
- + ce_id, ret);
- +- goto out;
- ++ return ret;
- + }
- + }
- +
- +-out:
- +- ath10k_pci_sleep(ar);
- +- return ret;
- ++ return 0;
- + }
- +
- + static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id)
- + {
- +- u32 ctrl_addr = ath10k_ce_base_address(ce_id);
- ++ u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id);
- +
- + ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, 0);
- + ath10k_ce_src_ring_size_set(ar, ctrl_addr, 0);
- +@@ -1101,7 +1061,7 @@ static void ath10k_ce_deinit_src_ring(st
- +
- + static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id)
- + {
- +- u32 ctrl_addr = ath10k_ce_base_address(ce_id);
- ++ u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id);
- +
- + ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, 0);
- + ath10k_ce_dest_ring_size_set(ar, ctrl_addr, 0);
- +@@ -1110,30 +1070,49 @@ static void ath10k_ce_deinit_dest_ring(s
- +
- + void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id)
- + {
- +- int ret;
- +-
- +- ret = ath10k_pci_wake(ar);
- +- if (ret)
- +- return;
- +-
- + ath10k_ce_deinit_src_ring(ar, ce_id);
- + ath10k_ce_deinit_dest_ring(ar, ce_id);
- +-
- +- ath10k_pci_sleep(ar);
- + }
- +
- + int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
- +- const struct ce_attr *attr)
- ++ const struct ce_attr *attr,
- ++ void (*send_cb)(struct ath10k_ce_pipe *),
- ++ void (*recv_cb)(struct ath10k_ce_pipe *))
- + {
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- + struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
- + int ret;
- +
- ++ /*
- ++ * Make sure there's enough CE ringbuffer entries for HTT TX to avoid
- ++ * additional TX locking checks.
- ++ *
- ++ * For the lack of a better place do the check here.
- ++ */
- ++ BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC >
- ++ (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
- ++ BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
- ++ (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
- ++ BUILD_BUG_ON(2*TARGET_TLV_NUM_MSDU_DESC >
- ++ (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
- ++
- ++ ce_state->ar = ar;
- ++ ce_state->id = ce_id;
- ++ ce_state->ctrl_addr = ath10k_ce_base_address(ar, ce_id);
- ++ ce_state->attr_flags = attr->flags;
- ++ ce_state->src_sz_max = attr->src_sz_max;
- ++
- ++ if (attr->src_nentries)
- ++ ce_state->send_cb = send_cb;
- ++
- ++ if (attr->dest_nentries)
- ++ ce_state->recv_cb = recv_cb;
- ++
- + if (attr->src_nentries) {
- + ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr);
- + if (IS_ERR(ce_state->src_ring)) {
- + ret = PTR_ERR(ce_state->src_ring);
- +- ath10k_err("failed to allocate copy engine source ring %d: %d\n",
- ++ ath10k_err(ar, "failed to allocate copy engine source ring %d: %d\n",
- + ce_id, ret);
- + ce_state->src_ring = NULL;
- + return ret;
- +@@ -1145,7 +1124,7 @@ int ath10k_ce_alloc_pipe(struct ath10k *
- + attr);
- + if (IS_ERR(ce_state->dest_ring)) {
- + ret = PTR_ERR(ce_state->dest_ring);
- +- ath10k_err("failed to allocate copy engine destination ring %d: %d\n",
- ++ ath10k_err(ar, "failed to allocate copy engine destination ring %d: %d\n",
- + ce_id, ret);
- + ce_state->dest_ring = NULL;
- + return ret;
- +--- a/drivers/net/wireless/ath/ath10k/ce.h
- ++++ b/drivers/net/wireless/ath/ath10k/ce.h
- +@@ -20,7 +20,6 @@
- +
- + #include "hif.h"
- +
- +-
- + /* Maximum number of Copy Engine's supported */
- + #define CE_COUNT_MAX 8
- + #define CE_HTT_H2T_MSG_SRC_NENTRIES 4096
- +@@ -37,11 +36,10 @@
- +
- + struct ath10k_ce_pipe;
- +
- +-
- + #define CE_DESC_FLAGS_GATHER (1 << 0)
- + #define CE_DESC_FLAGS_BYTE_SWAP (1 << 1)
- + #define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC
- +-#define CE_DESC_FLAGS_META_DATA_LSB 3
- ++#define CE_DESC_FLAGS_META_DATA_LSB 2
- +
- + struct ce_desc {
- + __le32 addr;
- +@@ -160,30 +158,15 @@ int ath10k_ce_send_nolock(struct ath10k_
- + unsigned int transfer_id,
- + unsigned int flags);
- +
- +-void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
- +- void (*send_cb)(struct ath10k_ce_pipe *),
- +- int disable_interrupts);
- ++void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe);
- +
- + int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe);
- +
- + /*==================Recv=======================*/
- +
- +-/*
- +- * Make a buffer available to receive. The buffer must be at least of a
- +- * minimal size appropriate for this copy engine (src_sz_max attribute).
- +- * ce - which copy engine to use
- +- * per_transfer_recv_context - context passed back to caller's recv_cb
- +- * buffer - address of buffer in CE space
- +- * Returns 0 on success; otherwise an error status.
- +- *
- +- * Implemenation note: Pushes a buffer to Dest ring.
- +- */
- +-int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
- +- void *per_transfer_recv_context,
- +- u32 buffer);
- +-
- +-void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
- +- void (*recv_cb)(struct ath10k_ce_pipe *));
- ++int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe);
- ++int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
- ++int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
- +
- + /* recv flags */
- + /* Data is byte-swapped */
- +@@ -204,10 +187,16 @@ int ath10k_ce_completed_recv_next(struct
- + * Pops 1 completed send buffer from Source ring.
- + */
- + int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
- +- void **per_transfer_contextp,
- +- u32 *bufferp,
- +- unsigned int *nbytesp,
- +- unsigned int *transfer_idp);
- ++ void **per_transfer_contextp,
- ++ u32 *bufferp,
- ++ unsigned int *nbytesp,
- ++ unsigned int *transfer_idp);
- ++
- ++int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
- ++ void **per_transfer_contextp,
- ++ u32 *bufferp,
- ++ unsigned int *nbytesp,
- ++ unsigned int *transfer_idp);
- +
- + /*==================CE Engine Initialization=======================*/
- +
- +@@ -215,7 +204,9 @@ int ath10k_ce_init_pipe(struct ath10k *a
- + const struct ce_attr *attr);
- + void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id);
- + int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
- +- const struct ce_attr *attr);
- ++ const struct ce_attr *attr,
- ++ void (*send_cb)(struct ath10k_ce_pipe *),
- ++ void (*recv_cb)(struct ath10k_ce_pipe *));
- + void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);
- +
- + /*==================CE Engine Shutdown=======================*/
- +@@ -228,6 +219,13 @@ int ath10k_ce_revoke_recv_next(struct at
- + void **per_transfer_contextp,
- + u32 *bufferp);
- +
- ++int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
- ++ void **per_transfer_contextp,
- ++ u32 *bufferp,
- ++ unsigned int *nbytesp,
- ++ unsigned int *transfer_idp,
- ++ unsigned int *flagsp);
- ++
- + /*
- + * Support clean shutdown by allowing the caller to cancel
- + * pending sends. Target DMA must be stopped before using
- +@@ -243,6 +241,7 @@ int ath10k_ce_cancel_send_next(struct at
- + void ath10k_ce_per_engine_service_any(struct ath10k *ar);
- + void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
- + int ath10k_ce_disable_interrupts(struct ath10k *ar);
- ++void ath10k_ce_enable_interrupts(struct ath10k *ar);
- +
- + /* ce_attr.flags values */
- + /* Use NonSnooping PCIe accesses? */
- +@@ -395,8 +394,7 @@ struct ce_attr {
- + #define DST_WATERMARK_HIGH_RESET 0
- + #define DST_WATERMARK_ADDRESS 0x0050
- +
- +-
- +-static inline u32 ath10k_ce_base_address(unsigned int ce_id)
- ++static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id)
- + {
- + return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id;
- + }
- +--- a/drivers/net/wireless/ath/ath10k/core.c
- ++++ b/drivers/net/wireless/ath/ath10k/core.c
- +@@ -17,6 +17,7 @@
- +
- + #include <linux/module.h>
- + #include <linux/firmware.h>
- ++#include <linux/of.h>
- +
- + #include "core.h"
- + #include "mac.h"
- +@@ -26,68 +27,88 @@
- + #include "bmi.h"
- + #include "debug.h"
- + #include "htt.h"
- ++#include "testmode.h"
- ++#include "wmi-ops.h"
- +
- + unsigned int ath10k_debug_mask;
- + static bool uart_print;
- +-static unsigned int ath10k_p2p;
- ++static bool skip_otp;
- ++
- + module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);
- + module_param(uart_print, bool, 0644);
- +-module_param_named(p2p, ath10k_p2p, uint, 0644);
- ++module_param(skip_otp, bool, 0644);
- ++
- + MODULE_PARM_DESC(debug_mask, "Debugging mask");
- + MODULE_PARM_DESC(uart_print, "Uart target debugging");
- +-MODULE_PARM_DESC(p2p, "Enable ath10k P2P support");
- ++MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");
- +
- + static const struct ath10k_hw_params ath10k_hw_params_list[] = {
- + {
- + .id = QCA988X_HW_2_0_VERSION,
- + .name = "qca988x hw2.0",
- + .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
- ++ .uart_pin = 7,
- + .fw = {
- + .dir = QCA988X_HW_2_0_FW_DIR,
- + .fw = QCA988X_HW_2_0_FW_FILE,
- + .otp = QCA988X_HW_2_0_OTP_FILE,
- + .board = QCA988X_HW_2_0_BOARD_DATA_FILE,
- ++ .board_size = QCA988X_BOARD_DATA_SZ,
- ++ .board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,
- ++ },
- ++ },
- ++ {
- ++ .id = QCA6174_HW_2_1_VERSION,
- ++ .name = "qca6174 hw2.1",
- ++ .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,
- ++ .uart_pin = 6,
- ++ .fw = {
- ++ .dir = QCA6174_HW_2_1_FW_DIR,
- ++ .fw = QCA6174_HW_2_1_FW_FILE,
- ++ .otp = QCA6174_HW_2_1_OTP_FILE,
- ++ .board = QCA6174_HW_2_1_BOARD_DATA_FILE,
- ++ .board_size = QCA6174_BOARD_DATA_SZ,
- ++ .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
- ++ },
- ++ },
- ++ {
- ++ .id = QCA6174_HW_3_0_VERSION,
- ++ .name = "qca6174 hw3.0",
- ++ .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
- ++ .uart_pin = 6,
- ++ .fw = {
- ++ .dir = QCA6174_HW_3_0_FW_DIR,
- ++ .fw = QCA6174_HW_3_0_FW_FILE,
- ++ .otp = QCA6174_HW_3_0_OTP_FILE,
- ++ .board = QCA6174_HW_3_0_BOARD_DATA_FILE,
- ++ .board_size = QCA6174_BOARD_DATA_SZ,
- ++ .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
- ++ },
- ++ },
- ++ {
- ++ .id = QCA6174_HW_3_2_VERSION,
- ++ .name = "qca6174 hw3.2",
- ++ .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
- ++ .uart_pin = 6,
- ++ .fw = {
- ++ /* uses same binaries as hw3.0 */
- ++ .dir = QCA6174_HW_3_0_FW_DIR,
- ++ .fw = QCA6174_HW_3_0_FW_FILE,
- ++ .otp = QCA6174_HW_3_0_OTP_FILE,
- ++ .board = QCA6174_HW_3_0_BOARD_DATA_FILE,
- ++ .board_size = QCA6174_BOARD_DATA_SZ,
- ++ .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
- + },
- + },
- + };
- +
- + static void ath10k_send_suspend_complete(struct ath10k *ar)
- + {
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n");
- +
- + complete(&ar->target_suspend);
- + }
- +
- +-static int ath10k_init_connect_htc(struct ath10k *ar)
- +-{
- +- int status;
- +-
- +- status = ath10k_wmi_connect_htc_service(ar);
- +- if (status)
- +- goto conn_fail;
- +-
- +- /* Start HTC */
- +- status = ath10k_htc_start(&ar->htc);
- +- if (status)
- +- goto conn_fail;
- +-
- +- /* Wait for WMI event to be ready */
- +- status = ath10k_wmi_wait_for_service_ready(ar);
- +- if (status <= 0) {
- +- ath10k_warn("wmi service ready event not received");
- +- status = -ETIMEDOUT;
- +- goto timeout;
- +- }
- +-
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot wmi ready\n");
- +- return 0;
- +-
- +-timeout:
- +- ath10k_htc_stop(&ar->htc);
- +-conn_fail:
- +- return status;
- +-}
- +-
- + static int ath10k_init_configure_target(struct ath10k *ar)
- + {
- + u32 param_host;
- +@@ -97,14 +118,14 @@ static int ath10k_init_configure_target(
- + ret = ath10k_bmi_write32(ar, hi_app_host_interest,
- + HTC_PROTOCOL_VERSION);
- + if (ret) {
- +- ath10k_err("settings HTC version failed\n");
- ++ ath10k_err(ar, "settings HTC version failed\n");
- + return ret;
- + }
- +
- + /* set the firmware mode to STA/IBSS/AP */
- + ret = ath10k_bmi_read32(ar, hi_option_flag, ¶m_host);
- + if (ret) {
- +- ath10k_err("setting firmware mode (1/2) failed\n");
- ++ ath10k_err(ar, "setting firmware mode (1/2) failed\n");
- + return ret;
- + }
- +
- +@@ -123,14 +144,14 @@ static int ath10k_init_configure_target(
- +
- + ret = ath10k_bmi_write32(ar, hi_option_flag, param_host);
- + if (ret) {
- +- ath10k_err("setting firmware mode (2/2) failed\n");
- ++ ath10k_err(ar, "setting firmware mode (2/2) failed\n");
- + return ret;
- + }
- +
- + /* We do all byte-swapping on the host */
- + ret = ath10k_bmi_write32(ar, hi_be, 0);
- + if (ret) {
- +- ath10k_err("setting host CPU BE mode failed\n");
- ++ ath10k_err(ar, "setting host CPU BE mode failed\n");
- + return ret;
- + }
- +
- +@@ -138,7 +159,7 @@ static int ath10k_init_configure_target(
- + ret = ath10k_bmi_write32(ar, hi_fw_swap, 0);
- +
- + if (ret) {
- +- ath10k_err("setting FW data/desc swap flags failed\n");
- ++ ath10k_err(ar, "setting FW data/desc swap flags failed\n");
- + return ret;
- + }
- +
- +@@ -167,79 +188,83 @@ static const struct firmware *ath10k_fet
- + return fw;
- + }
- +
- +-static int ath10k_push_board_ext_data(struct ath10k *ar)
- ++static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,
- ++ size_t data_len)
- + {
- +- u32 board_data_size = QCA988X_BOARD_DATA_SZ;
- +- u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ;
- ++ u32 board_data_size = ar->hw_params.fw.board_size;
- ++ u32 board_ext_data_size = ar->hw_params.fw.board_ext_size;
- + u32 board_ext_data_addr;
- + int ret;
- +
- + ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr);
- + if (ret) {
- +- ath10k_err("could not read board ext data addr (%d)\n", ret);
- ++ ath10k_err(ar, "could not read board ext data addr (%d)\n",
- ++ ret);
- + return ret;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT,
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- + "boot push board extended data addr 0x%x\n",
- + board_ext_data_addr);
- +
- + if (board_ext_data_addr == 0)
- + return 0;
- +
- +- if (ar->board_len != (board_data_size + board_ext_data_size)) {
- +- ath10k_err("invalid board (ext) data sizes %zu != %d+%d\n",
- +- ar->board_len, board_data_size, board_ext_data_size);
- ++ if (data_len != (board_data_size + board_ext_data_size)) {
- ++ ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n",
- ++ data_len, board_data_size, board_ext_data_size);
- + return -EINVAL;
- + }
- +
- + ret = ath10k_bmi_write_memory(ar, board_ext_data_addr,
- +- ar->board_data + board_data_size,
- ++ data + board_data_size,
- + board_ext_data_size);
- + if (ret) {
- +- ath10k_err("could not write board ext data (%d)\n", ret);
- ++ ath10k_err(ar, "could not write board ext data (%d)\n", ret);
- + return ret;
- + }
- +
- + ret = ath10k_bmi_write32(ar, hi_board_ext_data_config,
- + (board_ext_data_size << 16) | 1);
- + if (ret) {
- +- ath10k_err("could not write board ext data bit (%d)\n", ret);
- ++ ath10k_err(ar, "could not write board ext data bit (%d)\n",
- ++ ret);
- + return ret;
- + }
- +
- + return 0;
- + }
- +
- +-static int ath10k_download_board_data(struct ath10k *ar)
- ++static int ath10k_download_board_data(struct ath10k *ar, const void *data,
- ++ size_t data_len)
- + {
- +- u32 board_data_size = QCA988X_BOARD_DATA_SZ;
- ++ u32 board_data_size = ar->hw_params.fw.board_size;
- + u32 address;
- + int ret;
- +
- +- ret = ath10k_push_board_ext_data(ar);
- ++ ret = ath10k_push_board_ext_data(ar, data, data_len);
- + if (ret) {
- +- ath10k_err("could not push board ext data (%d)\n", ret);
- ++ ath10k_err(ar, "could not push board ext data (%d)\n", ret);
- + goto exit;
- + }
- +
- + ret = ath10k_bmi_read32(ar, hi_board_data, &address);
- + if (ret) {
- +- ath10k_err("could not read board data addr (%d)\n", ret);
- ++ ath10k_err(ar, "could not read board data addr (%d)\n", ret);
- + goto exit;
- + }
- +
- +- ret = ath10k_bmi_write_memory(ar, address, ar->board_data,
- ++ ret = ath10k_bmi_write_memory(ar, address, data,
- + min_t(u32, board_data_size,
- +- ar->board_len));
- ++ data_len));
- + if (ret) {
- +- ath10k_err("could not write board data (%d)\n", ret);
- ++ ath10k_err(ar, "could not write board data (%d)\n", ret);
- + goto exit;
- + }
- +
- + ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1);
- + if (ret) {
- +- ath10k_err("could not write board data bit (%d)\n", ret);
- ++ ath10k_err(ar, "could not write board data bit (%d)\n", ret);
- + goto exit;
- + }
- +
- +@@ -247,73 +272,182 @@ exit:
- + return ret;
- + }
- +
- ++static int ath10k_download_cal_file(struct ath10k *ar)
- ++{
- ++ int ret;
- ++
- ++ if (!ar->cal_file)
- ++ return -ENOENT;
- ++
- ++ if (IS_ERR(ar->cal_file))
- ++ return PTR_ERR(ar->cal_file);
- ++
- ++ ret = ath10k_download_board_data(ar, ar->cal_file->data,
- ++ ar->cal_file->size);
- ++ if (ret) {
- ++ ath10k_err(ar, "failed to download cal_file data: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n");
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_download_cal_dt(struct ath10k *ar)
- ++{
- ++ struct device_node *node;
- ++ int data_len;
- ++ void *data;
- ++ int ret;
- ++
- ++ node = ar->dev->of_node;
- ++ if (!node)
- ++ /* Device Tree is optional, don't print any warnings if
- ++ * there's no node for ath10k.
- ++ */
- ++ return -ENOENT;
- ++
- ++ if (!of_get_property(node, "qcom,ath10k-calibration-data",
- ++ &data_len)) {
- ++ /* The calibration data node is optional */
- ++ return -ENOENT;
- ++ }
- ++
- ++ if (data_len != QCA988X_CAL_DATA_LEN) {
- ++ ath10k_warn(ar, "invalid calibration data length in DT: %d\n",
- ++ data_len);
- ++ ret = -EMSGSIZE;
- ++ goto out;
- ++ }
- ++
- ++ data = kmalloc(data_len, GFP_KERNEL);
- ++ if (!data) {
- ++ ret = -ENOMEM;
- ++ goto out;
- ++ }
- ++
- ++ ret = of_property_read_u8_array(node, "qcom,ath10k-calibration-data",
- ++ data, data_len);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to read calibration data from DT: %d\n",
- ++ ret);
- ++ goto out_free;
- ++ }
- ++
- ++ ret = ath10k_download_board_data(ar, data, data_len);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n",
- ++ ret);
- ++ goto out_free;
- ++ }
- ++
- ++ ret = 0;
- ++
- ++out_free:
- ++ kfree(data);
- ++
- ++out:
- ++ return ret;
- ++}
- ++
- + static int ath10k_download_and_run_otp(struct ath10k *ar)
- + {
- + u32 result, address = ar->hw_params.patch_load_addr;
- + int ret;
- +
- ++ ret = ath10k_download_board_data(ar, ar->board_data, ar->board_len);
- ++ if (ret) {
- ++ ath10k_err(ar, "failed to download board data: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- + /* OTP is optional */
- +
- + if (!ar->otp_data || !ar->otp_len) {
- +- ath10k_warn("Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",
- ++ ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",
- + ar->otp_data, ar->otp_len);
- + return 0;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
- + address, ar->otp_len);
- +
- + ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len);
- + if (ret) {
- +- ath10k_err("could not write otp (%d)\n", ret);
- ++ ath10k_err(ar, "could not write otp (%d)\n", ret);
- + return ret;
- + }
- +
- + ret = ath10k_bmi_execute(ar, address, 0, &result);
- + if (ret) {
- +- ath10k_err("could not execute otp (%d)\n", ret);
- ++ ath10k_err(ar, "could not execute otp (%d)\n", ret);
- + return ret;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
- +
- +- if (result != 0) {
- +- ath10k_err("otp calibration failed: %d", result);
- ++ if (!skip_otp && result != 0) {
- ++ ath10k_err(ar, "otp calibration failed: %d", result);
- + return -EINVAL;
- + }
- +
- + return 0;
- + }
- +
- +-static int ath10k_download_fw(struct ath10k *ar)
- ++static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode)
- + {
- +- u32 address;
- ++ u32 address, data_len;
- ++ const char *mode_name;
- ++ const void *data;
- + int ret;
- +
- + address = ar->hw_params.patch_load_addr;
- +
- +- ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data,
- +- ar->firmware_len);
- ++ switch (mode) {
- ++ case ATH10K_FIRMWARE_MODE_NORMAL:
- ++ data = ar->firmware_data;
- ++ data_len = ar->firmware_len;
- ++ mode_name = "normal";
- ++ break;
- ++ case ATH10K_FIRMWARE_MODE_UTF:
- ++ data = ar->testmode.utf->data;
- ++ data_len = ar->testmode.utf->size;
- ++ mode_name = "utf";
- ++ break;
- ++ default:
- ++ ath10k_err(ar, "unknown firmware mode: %d\n", mode);
- ++ return -EINVAL;
- ++ }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- ++ "boot uploading firmware image %p len %d mode %s\n",
- ++ data, data_len, mode_name);
- ++
- ++ ret = ath10k_bmi_fast_download(ar, address, data, data_len);
- + if (ret) {
- +- ath10k_err("could not write fw (%d)\n", ret);
- +- goto exit;
- ++ ath10k_err(ar, "failed to download %s firmware: %d\n",
- ++ mode_name, ret);
- ++ return ret;
- + }
- +
- +-exit:
- + return ret;
- + }
- +
- + static void ath10k_core_free_firmware_files(struct ath10k *ar)
- + {
- +- if (ar->board && !IS_ERR(ar->board))
- ++ if (!IS_ERR(ar->board))
- + release_firmware(ar->board);
- +
- +- if (ar->otp && !IS_ERR(ar->otp))
- ++ if (!IS_ERR(ar->otp))
- + release_firmware(ar->otp);
- +
- +- if (ar->firmware && !IS_ERR(ar->firmware))
- ++ if (!IS_ERR(ar->firmware))
- + release_firmware(ar->firmware);
- +
- ++ if (!IS_ERR(ar->cal_file))
- ++ release_firmware(ar->cal_file);
- ++
- + ar->board = NULL;
- + ar->board_data = NULL;
- + ar->board_len = 0;
- +@@ -325,6 +459,27 @@ static void ath10k_core_free_firmware_fi
- + ar->firmware = NULL;
- + ar->firmware_data = NULL;
- + ar->firmware_len = 0;
- ++
- ++ ar->cal_file = NULL;
- ++}
- ++
- ++static int ath10k_fetch_cal_file(struct ath10k *ar)
- ++{
- ++ char filename[100];
- ++
- ++ /* cal-<bus>-<id>.bin */
- ++ scnprintf(filename, sizeof(filename), "cal-%s-%s.bin",
- ++ ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));
- ++
- ++ ar->cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename);
- ++ if (IS_ERR(ar->cal_file))
- ++ /* calibration file is optional, don't print any warnings */
- ++ return PTR_ERR(ar->cal_file);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found calibration file %s/%s\n",
- ++ ATH10K_FW_DIR, filename);
- ++
- ++ return 0;
- + }
- +
- + static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
- +@@ -332,12 +487,12 @@ static int ath10k_core_fetch_firmware_ap
- + int ret = 0;
- +
- + if (ar->hw_params.fw.fw == NULL) {
- +- ath10k_err("firmware file not defined\n");
- ++ ath10k_err(ar, "firmware file not defined\n");
- + return -EINVAL;
- + }
- +
- + if (ar->hw_params.fw.board == NULL) {
- +- ath10k_err("board data file not defined");
- ++ ath10k_err(ar, "board data file not defined");
- + return -EINVAL;
- + }
- +
- +@@ -346,7 +501,7 @@ static int ath10k_core_fetch_firmware_ap
- + ar->hw_params.fw.board);
- + if (IS_ERR(ar->board)) {
- + ret = PTR_ERR(ar->board);
- +- ath10k_err("could not fetch board data (%d)\n", ret);
- ++ ath10k_err(ar, "could not fetch board data (%d)\n", ret);
- + goto err;
- + }
- +
- +@@ -358,7 +513,7 @@ static int ath10k_core_fetch_firmware_ap
- + ar->hw_params.fw.fw);
- + if (IS_ERR(ar->firmware)) {
- + ret = PTR_ERR(ar->firmware);
- +- ath10k_err("could not fetch firmware (%d)\n", ret);
- ++ ath10k_err(ar, "could not fetch firmware (%d)\n", ret);
- + goto err;
- + }
- +
- +@@ -374,7 +529,7 @@ static int ath10k_core_fetch_firmware_ap
- + ar->hw_params.fw.otp);
- + if (IS_ERR(ar->otp)) {
- + ret = PTR_ERR(ar->otp);
- +- ath10k_err("could not fetch otp (%d)\n", ret);
- ++ ath10k_err(ar, "could not fetch otp (%d)\n", ret);
- + goto err;
- + }
- +
- +@@ -394,12 +549,12 @@ static int ath10k_core_fetch_firmware_ap
- + int ie_id, i, index, bit, ret;
- + struct ath10k_fw_ie *hdr;
- + const u8 *data;
- +- __le32 *timestamp;
- ++ __le32 *timestamp, *version;
- +
- + /* first fetch the firmware file (firmware-*.bin) */
- + ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name);
- + if (IS_ERR(ar->firmware)) {
- +- ath10k_err("could not fetch firmware file '%s/%s': %ld\n",
- ++ ath10k_err(ar, "could not fetch firmware file '%s/%s': %ld\n",
- + ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware));
- + return PTR_ERR(ar->firmware);
- + }
- +@@ -411,14 +566,14 @@ static int ath10k_core_fetch_firmware_ap
- + magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
- +
- + if (len < magic_len) {
- +- ath10k_err("firmware file '%s/%s' too small to contain magic: %zu\n",
- ++ ath10k_err(ar, "firmware file '%s/%s' too small to contain magic: %zu\n",
- + ar->hw_params.fw.dir, name, len);
- + ret = -EINVAL;
- + goto err;
- + }
- +
- + if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
- +- ath10k_err("invalid firmware magic\n");
- ++ ath10k_err(ar, "invalid firmware magic\n");
- + ret = -EINVAL;
- + goto err;
- + }
- +@@ -440,7 +595,7 @@ static int ath10k_core_fetch_firmware_ap
- + data += sizeof(*hdr);
- +
- + if (len < ie_len) {
- +- ath10k_err("invalid length for FW IE %d (%zu < %zu)\n",
- ++ ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n",
- + ie_id, len, ie_len);
- + ret = -EINVAL;
- + goto err;
- +@@ -454,7 +609,7 @@ static int ath10k_core_fetch_firmware_ap
- + memcpy(ar->hw->wiphy->fw_version, data, ie_len);
- + ar->hw->wiphy->fw_version[ie_len] = '\0';
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT,
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- + "found fw version %s\n",
- + ar->hw->wiphy->fw_version);
- + break;
- +@@ -464,11 +619,11 @@ static int ath10k_core_fetch_firmware_ap
- +
- + timestamp = (__le32 *)data;
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw timestamp %d\n",
- + le32_to_cpup(timestamp));
- + break;
- + case ATH10K_FW_IE_FEATURES:
- +- ath10k_dbg(ATH10K_DBG_BOOT,
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- + "found firmware features ie (%zd B)\n",
- + ie_len);
- +
- +@@ -480,19 +635,19 @@ static int ath10k_core_fetch_firmware_ap
- + break;
- +
- + if (data[index] & (1 << bit)) {
- +- ath10k_dbg(ATH10K_DBG_BOOT,
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- + "Enabling feature bit: %i\n",
- + i);
- + __set_bit(i, ar->fw_features);
- + }
- + }
- +
- +- ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "",
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "features", "",
- + ar->fw_features,
- + sizeof(ar->fw_features));
- + break;
- + case ATH10K_FW_IE_FW_IMAGE:
- +- ath10k_dbg(ATH10K_DBG_BOOT,
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- + "found fw image ie (%zd B)\n",
- + ie_len);
- +
- +@@ -501,7 +656,7 @@ static int ath10k_core_fetch_firmware_ap
- +
- + break;
- + case ATH10K_FW_IE_OTP_IMAGE:
- +- ath10k_dbg(ATH10K_DBG_BOOT,
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- + "found otp image ie (%zd B)\n",
- + ie_len);
- +
- +@@ -509,8 +664,19 @@ static int ath10k_core_fetch_firmware_ap
- + ar->otp_len = ie_len;
- +
- + break;
- ++ case ATH10K_FW_IE_WMI_OP_VERSION:
- ++ if (ie_len != sizeof(u32))
- ++ break;
- ++
- ++ version = (__le32 *)data;
- ++
- ++ ar->wmi.op_version = le32_to_cpup(version);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie wmi op version %d\n",
- ++ ar->wmi.op_version);
- ++ break;
- + default:
- +- ath10k_warn("Unknown FW IE: %u\n",
- ++ ath10k_warn(ar, "Unknown FW IE: %u\n",
- + le32_to_cpu(hdr->id));
- + break;
- + }
- +@@ -523,7 +689,7 @@ static int ath10k_core_fetch_firmware_ap
- + }
- +
- + if (!ar->firmware_data || !ar->firmware_len) {
- +- ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
- ++ ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
- + ar->hw_params.fw.dir, name);
- + ret = -ENOMEDIUM;
- + goto err;
- +@@ -531,7 +697,7 @@ static int ath10k_core_fetch_firmware_ap
- +
- + /* now fetch the board file */
- + if (ar->hw_params.fw.board == NULL) {
- +- ath10k_err("board data file not defined");
- ++ ath10k_err(ar, "board data file not defined");
- + ret = -EINVAL;
- + goto err;
- + }
- +@@ -541,7 +707,7 @@ static int ath10k_core_fetch_firmware_ap
- + ar->hw_params.fw.board);
- + if (IS_ERR(ar->board)) {
- + ret = PTR_ERR(ar->board);
- +- ath10k_err("could not fetch board data '%s/%s' (%d)\n",
- ++ ath10k_err(ar, "could not fetch board data '%s/%s' (%d)\n",
- + ar->hw_params.fw.dir, ar->hw_params.fw.board,
- + ret);
- + goto err;
- +@@ -561,49 +727,79 @@ static int ath10k_core_fetch_firmware_fi
- + {
- + int ret;
- +
- ++ /* calibration file is optional, don't check for any errors */
- ++ ath10k_fetch_cal_file(ar);
- ++
- ++ ar->fw_api = 4;
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
- ++
- ++ ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API4_FILE);
- ++ if (ret == 0)
- ++ goto success;
- ++
- ++ ar->fw_api = 3;
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
- ++
- ++ ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE);
- ++ if (ret == 0)
- ++ goto success;
- ++
- + ar->fw_api = 2;
- +- ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
- +
- + ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE);
- + if (ret == 0)
- + goto success;
- +
- + ar->fw_api = 1;
- +- ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
- +
- + ret = ath10k_core_fetch_firmware_api_1(ar);
- + if (ret)
- + return ret;
- +
- + success:
- +- ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
- +
- + return 0;
- + }
- +
- +-static int ath10k_init_download_firmware(struct ath10k *ar)
- ++static int ath10k_download_cal_data(struct ath10k *ar)
- + {
- + int ret;
- +
- +- ret = ath10k_download_board_data(ar);
- +- if (ret) {
- +- ath10k_err("failed to download board data: %d\n", ret);
- +- return ret;
- ++ ret = ath10k_download_cal_file(ar);
- ++ if (ret == 0) {
- ++ ar->cal_mode = ATH10K_CAL_MODE_FILE;
- ++ goto done;
- + }
- +
- +- ret = ath10k_download_and_run_otp(ar);
- +- if (ret) {
- +- ath10k_err("failed to run otp: %d\n", ret);
- +- return ret;
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- ++ "boot did not find a calibration file, try DT next: %d\n",
- ++ ret);
- ++
- ++ ret = ath10k_download_cal_dt(ar);
- ++ if (ret == 0) {
- ++ ar->cal_mode = ATH10K_CAL_MODE_DT;
- ++ goto done;
- + }
- +
- +- ret = ath10k_download_fw(ar);
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- ++ "boot did not find DT entry, try OTP next: %d\n",
- ++ ret);
- ++
- ++ ret = ath10k_download_and_run_otp(ar);
- + if (ret) {
- +- ath10k_err("failed to download firmware: %d\n", ret);
- ++ ath10k_err(ar, "failed to run otp: %d\n", ret);
- + return ret;
- + }
- +
- +- return ret;
- ++ ar->cal_mode = ATH10K_CAL_MODE_OTP;
- ++
- ++done:
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using calibration mode %s\n",
- ++ ath10k_cal_mode_str(ar->cal_mode));
- ++ return 0;
- + }
- +
- + static int ath10k_init_uart(struct ath10k *ar)
- +@@ -616,33 +812,33 @@ static int ath10k_init_uart(struct ath10
- + */
- + ret = ath10k_bmi_write32(ar, hi_serial_enable, 0);
- + if (ret) {
- +- ath10k_warn("could not disable UART prints (%d)\n", ret);
- ++ ath10k_warn(ar, "could not disable UART prints (%d)\n", ret);
- + return ret;
- + }
- +
- + if (!uart_print)
- + return 0;
- +
- +- ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7);
- ++ ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin);
- + if (ret) {
- +- ath10k_warn("could not enable UART prints (%d)\n", ret);
- ++ ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);
- + return ret;
- + }
- +
- + ret = ath10k_bmi_write32(ar, hi_serial_enable, 1);
- + if (ret) {
- +- ath10k_warn("could not enable UART prints (%d)\n", ret);
- ++ ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);
- + return ret;
- + }
- +
- + /* Set the UART baud rate to 19200. */
- + ret = ath10k_bmi_write32(ar, hi_desired_baud_rate, 19200);
- + if (ret) {
- +- ath10k_warn("could not set the baud rate (%d)\n", ret);
- ++ ath10k_warn(ar, "could not set the baud rate (%d)\n", ret);
- + return ret;
- + }
- +
- +- ath10k_info("UART prints enabled\n");
- ++ ath10k_info(ar, "UART prints enabled\n");
- + return 0;
- + }
- +
- +@@ -659,14 +855,14 @@ static int ath10k_init_hw_params(struct
- + }
- +
- + if (i == ARRAY_SIZE(ath10k_hw_params_list)) {
- +- ath10k_err("Unsupported hardware version: 0x%x\n",
- ++ ath10k_err(ar, "Unsupported hardware version: 0x%x\n",
- + ar->target_version);
- + return -EINVAL;
- + }
- +
- + ar->hw_params = *hw_params;
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",
- + ar->hw_params.name, ar->target_version);
- +
- + return 0;
- +@@ -676,101 +872,124 @@ static void ath10k_core_restart(struct w
- + {
- + struct ath10k *ar = container_of(work, struct ath10k, restart_work);
- +
- ++ set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);
- ++
- ++ /* Place a barrier to make sure the compiler doesn't reorder
- ++ * CRASH_FLUSH and calling other functions.
- ++ */
- ++ barrier();
- ++
- ++ ieee80211_stop_queues(ar->hw);
- ++ ath10k_drain_tx(ar);
- ++ complete_all(&ar->scan.started);
- ++ complete_all(&ar->scan.completed);
- ++ complete_all(&ar->scan.on_channel);
- ++ complete_all(&ar->offchan_tx_completed);
- ++ complete_all(&ar->install_key_done);
- ++ complete_all(&ar->vdev_setup_done);
- ++ complete_all(&ar->thermal.wmi_sync);
- ++ wake_up(&ar->htt.empty_tx_wq);
- ++ wake_up(&ar->wmi.tx_credits_wq);
- ++ wake_up(&ar->peer_mapping_wq);
- ++
- + mutex_lock(&ar->conf_mutex);
- +
- + switch (ar->state) {
- + case ATH10K_STATE_ON:
- + ar->state = ATH10K_STATE_RESTARTING;
- +- ath10k_halt(ar);
- ++ ath10k_hif_stop(ar);
- ++ ath10k_scan_finish(ar);
- + ieee80211_restart_hw(ar->hw);
- + break;
- + case ATH10K_STATE_OFF:
- + /* this can happen if driver is being unloaded
- + * or if the crash happens during FW probing */
- +- ath10k_warn("cannot restart a device that hasn't been started\n");
- ++ ath10k_warn(ar, "cannot restart a device that hasn't been started\n");
- + break;
- + case ATH10K_STATE_RESTARTING:
- ++ /* hw restart might be requested from multiple places */
- ++ break;
- + case ATH10K_STATE_RESTARTED:
- + ar->state = ATH10K_STATE_WEDGED;
- + /* fall through */
- + case ATH10K_STATE_WEDGED:
- +- ath10k_warn("device is wedged, will not restart\n");
- ++ ath10k_warn(ar, "device is wedged, will not restart\n");
- ++ break;
- ++ case ATH10K_STATE_UTF:
- ++ ath10k_warn(ar, "firmware restart in UTF mode not supported\n");
- + break;
- + }
- +
- + mutex_unlock(&ar->conf_mutex);
- + }
- +
- +-struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
- +- const struct ath10k_hif_ops *hif_ops)
- ++static int ath10k_core_init_firmware_features(struct ath10k *ar)
- + {
- +- struct ath10k *ar;
- +-
- +- ar = ath10k_mac_create();
- +- if (!ar)
- +- return NULL;
- +-
- +- ar->ath_common.priv = ar;
- +- ar->ath_common.hw = ar->hw;
- +-
- +- ar->p2p = !!ath10k_p2p;
- +- ar->dev = dev;
- +-
- +- ar->hif.priv = hif_priv;
- +- ar->hif.ops = hif_ops;
- +-
- +- init_completion(&ar->scan.started);
- +- init_completion(&ar->scan.completed);
- +- init_completion(&ar->scan.on_channel);
- +- init_completion(&ar->target_suspend);
- +-
- +- init_completion(&ar->install_key_done);
- +- init_completion(&ar->vdev_setup_done);
- +-
- +- setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar);
- +-
- +- ar->workqueue = create_singlethread_workqueue("ath10k_wq");
- +- if (!ar->workqueue)
- +- goto err_wq;
- +-
- +- mutex_init(&ar->conf_mutex);
- +- spin_lock_init(&ar->data_lock);
- +-
- +- INIT_LIST_HEAD(&ar->peers);
- +- init_waitqueue_head(&ar->peer_mapping_wq);
- +-
- +- init_completion(&ar->offchan_tx_completed);
- +- INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);
- +- skb_queue_head_init(&ar->offchan_tx_queue);
- +-
- +- INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);
- +- skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
- +-
- +- INIT_WORK(&ar->restart_work, ath10k_core_restart);
- ++ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) &&
- ++ !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- ++ ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well");
- ++ return -EINVAL;
- ++ }
- +
- +- return ar;
- ++ if (ar->wmi.op_version >= ATH10K_FW_WMI_OP_VERSION_MAX) {
- ++ ath10k_err(ar, "unsupported WMI OP version (max %d): %d\n",
- ++ ATH10K_FW_WMI_OP_VERSION_MAX, ar->wmi.op_version);
- ++ return -EINVAL;
- ++ }
- +
- +-err_wq:
- +- ath10k_mac_destroy(ar);
- +- return NULL;
- +-}
- +-EXPORT_SYMBOL(ath10k_core_create);
- ++ /* Backwards compatibility for firmwares without
- ++ * ATH10K_FW_IE_WMI_OP_VERSION.
- ++ */
- ++ if (ar->wmi.op_version == ATH10K_FW_WMI_OP_VERSION_UNSET) {
- ++ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- ++ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2,
- ++ ar->fw_features))
- ++ ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_2;
- ++ else
- ++ ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
- ++ } else {
- ++ ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_MAIN;
- ++ }
- ++ }
- +
- +-void ath10k_core_destroy(struct ath10k *ar)
- +-{
- +- flush_workqueue(ar->workqueue);
- +- destroy_workqueue(ar->workqueue);
- ++ switch (ar->wmi.op_version) {
- ++ case ATH10K_FW_WMI_OP_VERSION_MAIN:
- ++ ar->max_num_peers = TARGET_NUM_PEERS;
- ++ ar->max_num_stations = TARGET_NUM_STATIONS;
- ++ ar->max_num_vdevs = TARGET_NUM_VDEVS;
- ++ ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC;
- ++ break;
- ++ case ATH10K_FW_WMI_OP_VERSION_10_1:
- ++ case ATH10K_FW_WMI_OP_VERSION_10_2:
- ++ case ATH10K_FW_WMI_OP_VERSION_10_2_4:
- ++ ar->max_num_peers = TARGET_10X_NUM_PEERS;
- ++ ar->max_num_stations = TARGET_10X_NUM_STATIONS;
- ++ ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
- ++ ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
- ++ break;
- ++ case ATH10K_FW_WMI_OP_VERSION_TLV:
- ++ ar->max_num_peers = TARGET_TLV_NUM_PEERS;
- ++ ar->max_num_stations = TARGET_TLV_NUM_STATIONS;
- ++ ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS;
- ++ ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC;
- ++ break;
- ++ case ATH10K_FW_WMI_OP_VERSION_UNSET:
- ++ case ATH10K_FW_WMI_OP_VERSION_MAX:
- ++ WARN_ON(1);
- ++ return -EINVAL;
- ++ }
- +
- +- ath10k_mac_destroy(ar);
- ++ return 0;
- + }
- +-EXPORT_SYMBOL(ath10k_core_destroy);
- +
- +-int ath10k_core_start(struct ath10k *ar)
- ++int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
- + {
- + int status;
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- ++ clear_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);
- ++
- + ath10k_bmi_start(ar);
- +
- + if (ath10k_init_configure_target(ar)) {
- +@@ -778,7 +997,11 @@ int ath10k_core_start(struct ath10k *ar)
- + goto err;
- + }
- +
- +- status = ath10k_init_download_firmware(ar);
- ++ status = ath10k_download_cal_data(ar);
- ++ if (status)
- ++ goto err;
- ++
- ++ status = ath10k_download_fw(ar, mode);
- + if (status)
- + goto err;
- +
- +@@ -791,7 +1014,7 @@ int ath10k_core_start(struct ath10k *ar)
- +
- + status = ath10k_htc_init(ar);
- + if (status) {
- +- ath10k_err("could not init HTC (%d)\n", status);
- ++ ath10k_err(ar, "could not init HTC (%d)\n", status);
- + goto err;
- + }
- +
- +@@ -801,79 +1024,123 @@ int ath10k_core_start(struct ath10k *ar)
- +
- + status = ath10k_wmi_attach(ar);
- + if (status) {
- +- ath10k_err("WMI attach failed: %d\n", status);
- ++ ath10k_err(ar, "WMI attach failed: %d\n", status);
- + goto err;
- + }
- +
- +- status = ath10k_hif_start(ar);
- ++ status = ath10k_htt_init(ar);
- ++ if (status) {
- ++ ath10k_err(ar, "failed to init htt: %d\n", status);
- ++ goto err_wmi_detach;
- ++ }
- ++
- ++ status = ath10k_htt_tx_alloc(&ar->htt);
- + if (status) {
- +- ath10k_err("could not start HIF: %d\n", status);
- ++ ath10k_err(ar, "failed to alloc htt tx: %d\n", status);
- + goto err_wmi_detach;
- + }
- +
- ++ status = ath10k_htt_rx_alloc(&ar->htt);
- ++ if (status) {
- ++ ath10k_err(ar, "failed to alloc htt rx: %d\n", status);
- ++ goto err_htt_tx_detach;
- ++ }
- ++
- ++ status = ath10k_hif_start(ar);
- ++ if (status) {
- ++ ath10k_err(ar, "could not start HIF: %d\n", status);
- ++ goto err_htt_rx_detach;
- ++ }
- ++
- + status = ath10k_htc_wait_target(&ar->htc);
- + if (status) {
- +- ath10k_err("failed to connect to HTC: %d\n", status);
- ++ ath10k_err(ar, "failed to connect to HTC: %d\n", status);
- + goto err_hif_stop;
- + }
- +
- +- status = ath10k_htt_attach(ar);
- ++ if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
- ++ status = ath10k_htt_connect(&ar->htt);
- ++ if (status) {
- ++ ath10k_err(ar, "failed to connect htt (%d)\n", status);
- ++ goto err_hif_stop;
- ++ }
- ++ }
- ++
- ++ status = ath10k_wmi_connect(ar);
- + if (status) {
- +- ath10k_err("could not attach htt (%d)\n", status);
- ++ ath10k_err(ar, "could not connect wmi: %d\n", status);
- + goto err_hif_stop;
- + }
- +
- +- status = ath10k_init_connect_htc(ar);
- +- if (status)
- +- goto err_htt_detach;
- ++ status = ath10k_htc_start(&ar->htc);
- ++ if (status) {
- ++ ath10k_err(ar, "failed to start htc: %d\n", status);
- ++ goto err_hif_stop;
- ++ }
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n",
- ++ if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
- ++ status = ath10k_wmi_wait_for_service_ready(ar);
- ++ if (status <= 0) {
- ++ ath10k_warn(ar, "wmi service ready event not received");
- ++ status = -ETIMEDOUT;
- ++ goto err_hif_stop;
- ++ }
- ++ }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n",
- + ar->hw->wiphy->fw_version);
- +
- + status = ath10k_wmi_cmd_init(ar);
- + if (status) {
- +- ath10k_err("could not send WMI init command (%d)\n", status);
- +- goto err_disconnect_htc;
- ++ ath10k_err(ar, "could not send WMI init command (%d)\n",
- ++ status);
- ++ goto err_hif_stop;
- + }
- +
- + status = ath10k_wmi_wait_for_unified_ready(ar);
- + if (status <= 0) {
- +- ath10k_err("wmi unified ready event not received\n");
- ++ ath10k_err(ar, "wmi unified ready event not received\n");
- + status = -ETIMEDOUT;
- +- goto err_disconnect_htc;
- ++ goto err_hif_stop;
- + }
- +
- +- status = ath10k_htt_attach_target(&ar->htt);
- +- if (status)
- +- goto err_disconnect_htc;
- ++ /* If firmware indicates Full Rx Reorder support it must be used in a
- ++ * slightly different manner. Let HTT code know.
- ++ */
- ++ ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER,
- ++ ar->wmi.svc_map));
- ++
- ++ status = ath10k_htt_rx_ring_refill(ar);
- ++ if (status) {
- ++ ath10k_err(ar, "failed to refill htt rx ring: %d\n", status);
- ++ goto err_hif_stop;
- ++ }
- ++
- ++ /* we don't care about HTT in UTF mode */
- ++ if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
- ++ status = ath10k_htt_setup(&ar->htt);
- ++ if (status) {
- ++ ath10k_err(ar, "failed to setup htt: %d\n", status);
- ++ goto err_hif_stop;
- ++ }
- ++ }
- +
- + status = ath10k_debug_start(ar);
- + if (status)
- +- goto err_disconnect_htc;
- +-
- +- ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
- +- INIT_LIST_HEAD(&ar->arvifs);
- ++ goto err_hif_stop;
- +
- +- if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
- +- ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
- +- ar->hw_params.name,
- +- ar->target_version,
- +- ar->chip_id,
- +- ar->hw->wiphy->fw_version,
- +- ar->fw_api,
- +- ar->htt.target_version_major,
- +- ar->htt.target_version_minor);
- ++ ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;
- +
- +- __set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags);
- ++ INIT_LIST_HEAD(&ar->arvifs);
- +
- + return 0;
- +
- +-err_disconnect_htc:
- +- ath10k_htc_stop(&ar->htc);
- +-err_htt_detach:
- +- ath10k_htt_detach(&ar->htt);
- + err_hif_stop:
- + ath10k_hif_stop(ar);
- ++err_htt_rx_detach:
- ++ ath10k_htt_rx_free(&ar->htt);
- ++err_htt_tx_detach:
- ++ ath10k_htt_tx_free(&ar->htt);
- + err_wmi_detach:
- + ath10k_wmi_detach(ar);
- + err:
- +@@ -889,14 +1156,14 @@ int ath10k_wait_for_suspend(struct ath10
- +
- + ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt);
- + if (ret) {
- +- ath10k_warn("could not suspend target (%d)\n", ret);
- ++ ath10k_warn(ar, "could not suspend target (%d)\n", ret);
- + return ret;
- + }
- +
- + ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
- +
- + if (ret == 0) {
- +- ath10k_warn("suspend timed out - target pause event never came\n");
- ++ ath10k_warn(ar, "suspend timed out - target pause event never came\n");
- + return -ETIMEDOUT;
- + }
- +
- +@@ -908,12 +1175,14 @@ void ath10k_core_stop(struct ath10k *ar)
- + lockdep_assert_held(&ar->conf_mutex);
- +
- + /* try to suspend target */
- +- if (ar->state != ATH10K_STATE_RESTARTING)
- ++ if (ar->state != ATH10K_STATE_RESTARTING &&
- ++ ar->state != ATH10K_STATE_UTF)
- + ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
- +
- + ath10k_debug_stop(ar);
- +- ath10k_htc_stop(&ar->htc);
- +- ath10k_htt_detach(&ar->htt);
- ++ ath10k_hif_stop(ar);
- ++ ath10k_htt_tx_free(&ar->htt);
- ++ ath10k_htt_rx_free(&ar->htt);
- + ath10k_wmi_detach(ar);
- + }
- + EXPORT_SYMBOL(ath10k_core_stop);
- +@@ -929,16 +1198,15 @@ static int ath10k_core_probe_fw(struct a
- +
- + ret = ath10k_hif_power_up(ar);
- + if (ret) {
- +- ath10k_err("could not start pci hif (%d)\n", ret);
- ++ ath10k_err(ar, "could not start pci hif (%d)\n", ret);
- + return ret;
- + }
- +
- + memset(&target_info, 0, sizeof(target_info));
- + ret = ath10k_bmi_get_target_info(ar, &target_info);
- + if (ret) {
- +- ath10k_err("could not get target info (%d)\n", ret);
- +- ath10k_hif_power_down(ar);
- +- return ret;
- ++ ath10k_err(ar, "could not get target info (%d)\n", ret);
- ++ goto err_power_down;
- + }
- +
- + ar->target_version = target_info.version;
- +@@ -946,118 +1214,233 @@ static int ath10k_core_probe_fw(struct a
- +
- + ret = ath10k_init_hw_params(ar);
- + if (ret) {
- +- ath10k_err("could not get hw params (%d)\n", ret);
- +- ath10k_hif_power_down(ar);
- +- return ret;
- ++ ath10k_err(ar, "could not get hw params (%d)\n", ret);
- ++ goto err_power_down;
- + }
- +
- + ret = ath10k_core_fetch_firmware_files(ar);
- + if (ret) {
- +- ath10k_err("could not fetch firmware files (%d)\n", ret);
- +- ath10k_hif_power_down(ar);
- +- return ret;
- ++ ath10k_err(ar, "could not fetch firmware files (%d)\n", ret);
- ++ goto err_power_down;
- ++ }
- ++
- ++ ret = ath10k_core_init_firmware_features(ar);
- ++ if (ret) {
- ++ ath10k_err(ar, "fatal problem with firmware features: %d\n",
- ++ ret);
- ++ goto err_free_firmware_files;
- + }
- +
- + mutex_lock(&ar->conf_mutex);
- +
- +- ret = ath10k_core_start(ar);
- ++ ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
- + if (ret) {
- +- ath10k_err("could not init core (%d)\n", ret);
- +- ath10k_core_free_firmware_files(ar);
- +- ath10k_hif_power_down(ar);
- +- mutex_unlock(&ar->conf_mutex);
- +- return ret;
- ++ ath10k_err(ar, "could not init core (%d)\n", ret);
- ++ goto err_unlock;
- + }
- +
- ++ ath10k_print_driver_info(ar);
- + ath10k_core_stop(ar);
- +
- + mutex_unlock(&ar->conf_mutex);
- +
- + ath10k_hif_power_down(ar);
- + return 0;
- +-}
- +-
- +-static int ath10k_core_check_chip_id(struct ath10k *ar)
- +-{
- +- u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV);
- +-
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
- +- ar->chip_id, hw_revision);
- +
- +- /* Check that we are not using hw1.0 (some of them have same pci id
- +- * as hw2.0) before doing anything else as ath10k crashes horribly
- +- * due to missing hw1.0 workarounds. */
- +- switch (hw_revision) {
- +- case QCA988X_HW_1_0_CHIP_ID_REV:
- +- ath10k_err("ERROR: qca988x hw1.0 is not supported\n");
- +- return -EOPNOTSUPP;
- ++err_unlock:
- ++ mutex_unlock(&ar->conf_mutex);
- +
- +- case QCA988X_HW_2_0_CHIP_ID_REV:
- +- /* known hardware revision, continue normally */
- +- return 0;
- ++err_free_firmware_files:
- ++ ath10k_core_free_firmware_files(ar);
- +
- +- default:
- +- ath10k_warn("Warning: hardware revision unknown (0x%x), expect problems\n",
- +- ar->chip_id);
- +- return 0;
- +- }
- ++err_power_down:
- ++ ath10k_hif_power_down(ar);
- +
- +- return 0;
- ++ return ret;
- + }
- +
- +-int ath10k_core_register(struct ath10k *ar, u32 chip_id)
- ++static void ath10k_core_register_work(struct work_struct *work)
- + {
- ++ struct ath10k *ar = container_of(work, struct ath10k, register_work);
- + int status;
- +
- +- ar->chip_id = chip_id;
- +-
- +- status = ath10k_core_check_chip_id(ar);
- +- if (status) {
- +- ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id);
- +- return status;
- +- }
- +-
- + status = ath10k_core_probe_fw(ar);
- + if (status) {
- +- ath10k_err("could not probe fw (%d)\n", status);
- +- return status;
- ++ ath10k_err(ar, "could not probe fw (%d)\n", status);
- ++ goto err;
- + }
- +
- + status = ath10k_mac_register(ar);
- + if (status) {
- +- ath10k_err("could not register to mac80211 (%d)\n", status);
- ++ ath10k_err(ar, "could not register to mac80211 (%d)\n", status);
- + goto err_release_fw;
- + }
- +
- +- status = ath10k_debug_create(ar);
- ++ status = ath10k_debug_register(ar);
- + if (status) {
- +- ath10k_err("unable to initialize debugfs\n");
- ++ ath10k_err(ar, "unable to initialize debugfs\n");
- + goto err_unregister_mac;
- + }
- +
- +- return 0;
- ++ status = ath10k_spectral_create(ar);
- ++ if (status) {
- ++ ath10k_err(ar, "failed to initialize spectral\n");
- ++ goto err_debug_destroy;
- ++ }
- +
- ++ status = ath10k_thermal_register(ar);
- ++ if (status) {
- ++ ath10k_err(ar, "could not register thermal device: %d\n",
- ++ status);
- ++ goto err_spectral_destroy;
- ++ }
- ++
- ++ set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags);
- ++ return;
- ++
- ++err_spectral_destroy:
- ++ ath10k_spectral_destroy(ar);
- ++err_debug_destroy:
- ++ ath10k_debug_destroy(ar);
- + err_unregister_mac:
- + ath10k_mac_unregister(ar);
- + err_release_fw:
- + ath10k_core_free_firmware_files(ar);
- +- return status;
- ++err:
- ++ /* TODO: It's probably a good idea to release device from the driver
- ++ * but calling device_release_driver() here will cause a deadlock.
- ++ */
- ++ return;
- ++}
- ++
- ++int ath10k_core_register(struct ath10k *ar, u32 chip_id)
- ++{
- ++ ar->chip_id = chip_id;
- ++ queue_work(ar->workqueue, &ar->register_work);
- ++
- ++ return 0;
- + }
- + EXPORT_SYMBOL(ath10k_core_register);
- +
- + void ath10k_core_unregister(struct ath10k *ar)
- + {
- ++ cancel_work_sync(&ar->register_work);
- ++
- ++ if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
- ++ return;
- ++
- ++ ath10k_thermal_unregister(ar);
- ++ /* Stop spectral before unregistering from mac80211 to remove the
- ++ * relayfs debugfs file cleanly. Otherwise the parent debugfs tree
- ++ * would be already be free'd recursively, leading to a double free.
- ++ */
- ++ ath10k_spectral_destroy(ar);
- ++
- + /* We must unregister from mac80211 before we stop HTC and HIF.
- + * Otherwise we will fail to submit commands to FW and mac80211 will be
- + * unhappy about callback failures. */
- + ath10k_mac_unregister(ar);
- +
- ++ ath10k_testmode_destroy(ar);
- ++
- + ath10k_core_free_firmware_files(ar);
- +
- +- ath10k_debug_destroy(ar);
- ++ ath10k_debug_unregister(ar);
- + }
- + EXPORT_SYMBOL(ath10k_core_unregister);
- +
- ++struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
- ++ enum ath10k_bus bus,
- ++ enum ath10k_hw_rev hw_rev,
- ++ const struct ath10k_hif_ops *hif_ops)
- ++{
- ++ struct ath10k *ar;
- ++ int ret;
- ++
- ++ ar = ath10k_mac_create(priv_size);
- ++ if (!ar)
- ++ return NULL;
- ++
- ++ ar->ath_common.priv = ar;
- ++ ar->ath_common.hw = ar->hw;
- ++ ar->dev = dev;
- ++ ar->hw_rev = hw_rev;
- ++ ar->hif.ops = hif_ops;
- ++ ar->hif.bus = bus;
- ++
- ++ switch (hw_rev) {
- ++ case ATH10K_HW_QCA988X:
- ++ ar->regs = &qca988x_regs;
- ++ break;
- ++ case ATH10K_HW_QCA6174:
- ++ ar->regs = &qca6174_regs;
- ++ break;
- ++ default:
- ++ ath10k_err(ar, "unsupported core hardware revision %d\n",
- ++ hw_rev);
- ++ ret = -ENOTSUPP;
- ++ goto err_free_mac;
- ++ }
- ++
- ++ init_completion(&ar->scan.started);
- ++ init_completion(&ar->scan.completed);
- ++ init_completion(&ar->scan.on_channel);
- ++ init_completion(&ar->target_suspend);
- ++
- ++ init_completion(&ar->install_key_done);
- ++ init_completion(&ar->vdev_setup_done);
- ++ init_completion(&ar->thermal.wmi_sync);
- ++
- ++ INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
- ++
- ++ ar->workqueue = create_singlethread_workqueue("ath10k_wq");
- ++ if (!ar->workqueue)
- ++ goto err_free_mac;
- ++
- ++ mutex_init(&ar->conf_mutex);
- ++ spin_lock_init(&ar->data_lock);
- ++
- ++ INIT_LIST_HEAD(&ar->peers);
- ++ init_waitqueue_head(&ar->peer_mapping_wq);
- ++ init_waitqueue_head(&ar->htt.empty_tx_wq);
- ++ init_waitqueue_head(&ar->wmi.tx_credits_wq);
- ++
- ++ init_completion(&ar->offchan_tx_completed);
- ++ INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);
- ++ skb_queue_head_init(&ar->offchan_tx_queue);
- ++
- ++ INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);
- ++ skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
- ++
- ++ INIT_WORK(&ar->register_work, ath10k_core_register_work);
- ++ INIT_WORK(&ar->restart_work, ath10k_core_restart);
- ++
- ++ ret = ath10k_debug_create(ar);
- ++ if (ret)
- ++ goto err_free_wq;
- ++
- ++ return ar;
- ++
- ++err_free_wq:
- ++ destroy_workqueue(ar->workqueue);
- ++
- ++err_free_mac:
- ++ ath10k_mac_destroy(ar);
- ++
- ++ return NULL;
- ++}
- ++EXPORT_SYMBOL(ath10k_core_create);
- ++
- ++void ath10k_core_destroy(struct ath10k *ar)
- ++{
- ++ flush_workqueue(ar->workqueue);
- ++ destroy_workqueue(ar->workqueue);
- ++
- ++ ath10k_debug_destroy(ar);
- ++ ath10k_mac_destroy(ar);
- ++}
- ++EXPORT_SYMBOL(ath10k_core_destroy);
- ++
- + MODULE_AUTHOR("Qualcomm Atheros");
- + MODULE_DESCRIPTION("Core module for QCA988X PCIe devices.");
- + MODULE_LICENSE("Dual BSD/GPL");
- +--- a/drivers/net/wireless/ath/ath10k/core.h
- ++++ b/drivers/net/wireless/ath/ath10k/core.h
- +@@ -22,6 +22,8 @@
- + #include <linux/if_ether.h>
- + #include <linux/types.h>
- + #include <linux/pci.h>
- ++#include <linux/uuid.h>
- ++#include <linux/time.h>
- +
- + #include "htt.h"
- + #include "htc.h"
- +@@ -31,6 +33,8 @@
- + #include "../ath.h"
- + #include "../regd.h"
- + #include "../dfs_pattern_detector.h"
- ++#include "spectral.h"
- ++#include "thermal.h"
- +
- + #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
- + #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
- +@@ -60,12 +64,28 @@
- +
- + struct ath10k;
- +
- ++enum ath10k_bus {
- ++ ATH10K_BUS_PCI,
- ++};
- ++
- ++static inline const char *ath10k_bus_str(enum ath10k_bus bus)
- ++{
- ++ switch (bus) {
- ++ case ATH10K_BUS_PCI:
- ++ return "pci";
- ++ }
- ++
- ++ return "unknown";
- ++}
- ++
- + struct ath10k_skb_cb {
- + dma_addr_t paddr;
- ++ u8 eid;
- + u8 vdev_id;
- +
- + struct {
- + u8 tid;
- ++ u16 freq;
- + bool is_offchan;
- + struct ath10k_htt_txbuf *txbuf;
- + u32 txbuf_paddr;
- +@@ -77,6 +97,11 @@ struct ath10k_skb_cb {
- + } bcn;
- + } __packed;
- +
- ++struct ath10k_skb_rxcb {
- ++ dma_addr_t paddr;
- ++ struct hlist_node hlist;
- ++};
- ++
- + static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
- + {
- + BUILD_BUG_ON(sizeof(struct ath10k_skb_cb) >
- +@@ -84,6 +109,15 @@ static inline struct ath10k_skb_cb *ATH1
- + return (struct ath10k_skb_cb *)&IEEE80211_SKB_CB(skb)->driver_data;
- + }
- +
- ++static inline struct ath10k_skb_rxcb *ATH10K_SKB_RXCB(struct sk_buff *skb)
- ++{
- ++ BUILD_BUG_ON(sizeof(struct ath10k_skb_rxcb) > sizeof(skb->cb));
- ++ return (struct ath10k_skb_rxcb *)skb->cb;
- ++}
- ++
- ++#define ATH10K_RXCB_SKB(rxcb) \
- ++ container_of((void *)rxcb, struct sk_buff, cb)
- ++
- + static inline u32 host_interest_item_address(u32 item_offset)
- + {
- + return QCA988X_HOST_INTEREST_ADDRESS + item_offset;
- +@@ -93,8 +127,6 @@ struct ath10k_bmi {
- + bool done_sent;
- + };
- +
- +-#define ATH10K_MAX_MEM_REQS 16
- +-
- + struct ath10k_mem_chunk {
- + void *vaddr;
- + dma_addr_t paddr;
- +@@ -103,26 +135,52 @@ struct ath10k_mem_chunk {
- + };
- +
- + struct ath10k_wmi {
- ++ enum ath10k_fw_wmi_op_version op_version;
- + enum ath10k_htc_ep_id eid;
- + struct completion service_ready;
- + struct completion unified_ready;
- + wait_queue_head_t tx_credits_wq;
- ++ DECLARE_BITMAP(svc_map, WMI_SERVICE_MAX);
- + struct wmi_cmd_map *cmd;
- + struct wmi_vdev_param_map *vdev_param;
- + struct wmi_pdev_param_map *pdev_param;
- ++ const struct wmi_ops *ops;
- +
- + u32 num_mem_chunks;
- +- struct ath10k_mem_chunk mem_chunks[ATH10K_MAX_MEM_REQS];
- ++ struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];
- + };
- +
- +-struct ath10k_peer_stat {
- ++struct ath10k_fw_stats_peer {
- ++ struct list_head list;
- ++
- + u8 peer_macaddr[ETH_ALEN];
- + u32 peer_rssi;
- + u32 peer_tx_rate;
- + u32 peer_rx_rate; /* 10x only */
- + };
- +
- +-struct ath10k_target_stats {
- ++struct ath10k_fw_stats_vdev {
- ++ struct list_head list;
- ++
- ++ u32 vdev_id;
- ++ u32 beacon_snr;
- ++ u32 data_snr;
- ++ u32 num_tx_frames[4];
- ++ u32 num_rx_frames;
- ++ u32 num_tx_frames_retries[4];
- ++ u32 num_tx_frames_failures[4];
- ++ u32 num_rts_fail;
- ++ u32 num_rts_success;
- ++ u32 num_rx_err;
- ++ u32 num_rx_discard;
- ++ u32 num_tx_not_acked;
- ++ u32 tx_rate_history[10];
- ++ u32 beacon_rssi_history[10];
- ++};
- ++
- ++struct ath10k_fw_stats_pdev {
- ++ struct list_head list;
- ++
- + /* PDEV stats */
- + s32 ch_noise_floor;
- + u32 tx_frame_count;
- +@@ -177,15 +235,12 @@ struct ath10k_target_stats {
- + s32 phy_errs;
- + s32 phy_err_drop;
- + s32 mpdu_errs;
- ++};
- +
- +- /* VDEV STATS */
- +-
- +- /* PEER STATS */
- +- u8 peers;
- +- struct ath10k_peer_stat peer_stat[TARGET_NUM_PEERS];
- +-
- +- /* TODO: Beacon filter stats */
- +-
- ++struct ath10k_fw_stats {
- ++ struct list_head pdevs;
- ++ struct list_head vdevs;
- ++ struct list_head peers;
- + };
- +
- + struct ath10k_dfs_stats {
- +@@ -203,6 +258,8 @@ struct ath10k_peer {
- + int vdev_id;
- + u8 addr[ETH_ALEN];
- + DECLARE_BITMAP(peer_ids, ATH10K_MAX_NUM_PEER_IDS);
- ++
- ++ /* protected by ar->data_lock */
- + struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
- + };
- +
- +@@ -216,10 +273,21 @@ struct ath10k_sta {
- + u32 smps;
- +
- + struct work_struct update_wk;
- ++
- ++#ifdef CPTCFG_MAC80211_DEBUGFS
- ++ /* protected by conf_mutex */
- ++ bool aggr_mode;
- ++#endif
- + };
- +
- + #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
- +
- ++enum ath10k_beacon_state {
- ++ ATH10K_BEACON_SCHEDULED = 0,
- ++ ATH10K_BEACON_SENDING,
- ++ ATH10K_BEACON_SENT,
- ++};
- ++
- + struct ath10k_vif {
- + struct list_head list;
- +
- +@@ -230,20 +298,22 @@ struct ath10k_vif {
- + u32 dtim_period;
- + struct sk_buff *beacon;
- + /* protected by data_lock */
- +- bool beacon_sent;
- ++ enum ath10k_beacon_state beacon_state;
- ++ void *beacon_buf;
- ++ dma_addr_t beacon_paddr;
- +
- + struct ath10k *ar;
- + struct ieee80211_vif *vif;
- +
- + bool is_started;
- + bool is_up;
- ++ bool spectral_enabled;
- ++ bool ps;
- + u32 aid;
- + u8 bssid[ETH_ALEN];
- +
- +- struct work_struct wep_key_work;
- + struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1];
- +- u8 def_wep_key_idx;
- +- u8 def_wep_key_newidx;
- ++ s8 def_wep_key_idx;
- +
- + u16 tx_seq_no;
- +
- +@@ -269,6 +339,8 @@ struct ath10k_vif {
- + u8 force_sgi;
- + bool use_cts_prot;
- + int num_legacy_stations;
- ++ int txpower;
- ++ struct wmi_wmm_params_all_arg wmm_params;
- + };
- +
- + struct ath10k_vif_iter {
- +@@ -276,20 +348,38 @@ struct ath10k_vif_iter {
- + struct ath10k_vif *arvif;
- + };
- +
- ++/* used for crash-dump storage, protected by data-lock */
- ++struct ath10k_fw_crash_data {
- ++ bool crashed_since_read;
- ++
- ++ uuid_le uuid;
- ++ struct timespec timestamp;
- ++ __le32 registers[REG_DUMP_COUNT_QCA988X];
- ++};
- ++
- + struct ath10k_debug {
- + struct dentry *debugfs_phy;
- +
- +- struct ath10k_target_stats target_stats;
- +- u32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE];
- +-
- +- struct completion event_stats_compl;
- ++ struct ath10k_fw_stats fw_stats;
- ++ struct completion fw_stats_complete;
- ++ bool fw_stats_done;
- +
- + unsigned long htt_stats_mask;
- + struct delayed_work htt_stats_dwork;
- + struct ath10k_dfs_stats dfs_stats;
- + struct ath_dfs_pool_stats dfs_pool_stats;
- +
- ++ /* protected by conf_mutex */
- + u32 fw_dbglog_mask;
- ++ u32 fw_dbglog_level;
- ++ u32 pktlog_filter;
- ++ u32 reg_addr;
- ++ u32 nf_cal_period;
- ++
- ++ u8 htt_max_amsdu;
- ++ u8 htt_max_ampdu;
- ++
- ++ struct ath10k_fw_crash_data *fw_crash_data;
- + };
- +
- + enum ath10k_state {
- +@@ -312,13 +402,24 @@ enum ath10k_state {
- + * prevents completion timeouts and makes the driver more responsive to
- + * userspace commands. This is also prevents recursive recovery. */
- + ATH10K_STATE_WEDGED,
- ++
- ++ /* factory tests */
- ++ ATH10K_STATE_UTF,
- ++};
- ++
- ++enum ath10k_firmware_mode {
- ++ /* the default mode, standard 802.11 functionality */
- ++ ATH10K_FIRMWARE_MODE_NORMAL,
- ++
- ++ /* factory tests etc */
- ++ ATH10K_FIRMWARE_MODE_UTF,
- + };
- +
- + enum ath10k_fw_features {
- + /* wmi_mgmt_rx_hdr contains extra RSSI information */
- + ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0,
- +
- +- /* firmware from 10X branch */
- ++ /* Firmware from 10X branch. Deprecated, don't use in new code. */
- + ATH10K_FW_FEATURE_WMI_10X = 1,
- +
- + /* firmware support tx frame management over WMI, otherwise it's HTT */
- +@@ -327,6 +428,18 @@ enum ath10k_fw_features {
- + /* Firmware does not support P2P */
- + ATH10K_FW_FEATURE_NO_P2P = 3,
- +
- ++ /* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature
- ++ * bit is required to be set as well. Deprecated, don't use in new
- ++ * code.
- ++ */
- ++ ATH10K_FW_FEATURE_WMI_10_2 = 4,
- ++
- ++ /* Some firmware revisions lack proper multi-interface client powersave
- ++ * implementation. Enabling PS could result in connection drops,
- ++ * traffic stalls, etc.
- ++ */
- ++ ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT = 5,
- ++
- + /* keep last */
- + ATH10K_FW_FEATURE_COUNT,
- + };
- +@@ -334,15 +447,64 @@ enum ath10k_fw_features {
- + enum ath10k_dev_flags {
- + /* Indicates that ath10k device is during CAC phase of DFS */
- + ATH10K_CAC_RUNNING,
- +- ATH10K_FLAG_FIRST_BOOT_DONE,
- ++ ATH10K_FLAG_CORE_REGISTERED,
- ++
- ++ /* Device has crashed and needs to restart. This indicates any pending
- ++ * waiters should immediately cancel instead of waiting for a time out.
- ++ */
- ++ ATH10K_FLAG_CRASH_FLUSH,
- ++};
- ++
- ++enum ath10k_cal_mode {
- ++ ATH10K_CAL_MODE_FILE,
- ++ ATH10K_CAL_MODE_OTP,
- ++ ATH10K_CAL_MODE_DT,
- ++};
- ++
- ++static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
- ++{
- ++ switch (mode) {
- ++ case ATH10K_CAL_MODE_FILE:
- ++ return "file";
- ++ case ATH10K_CAL_MODE_OTP:
- ++ return "otp";
- ++ case ATH10K_CAL_MODE_DT:
- ++ return "dt";
- ++ }
- ++
- ++ return "unknown";
- ++}
- ++
- ++enum ath10k_scan_state {
- ++ ATH10K_SCAN_IDLE,
- ++ ATH10K_SCAN_STARTING,
- ++ ATH10K_SCAN_RUNNING,
- ++ ATH10K_SCAN_ABORTING,
- + };
- +
- ++static inline const char *ath10k_scan_state_str(enum ath10k_scan_state state)
- ++{
- ++ switch (state) {
- ++ case ATH10K_SCAN_IDLE:
- ++ return "idle";
- ++ case ATH10K_SCAN_STARTING:
- ++ return "starting";
- ++ case ATH10K_SCAN_RUNNING:
- ++ return "running";
- ++ case ATH10K_SCAN_ABORTING:
- ++ return "aborting";
- ++ }
- ++
- ++ return "unknown";
- ++}
- ++
- + struct ath10k {
- + struct ath_common ath_common;
- + struct ieee80211_hw *hw;
- + struct device *dev;
- + u8 mac_addr[ETH_ALEN];
- +
- ++ enum ath10k_hw_rev hw_rev;
- + u32 chip_id;
- + u32 target_version;
- + u8 fw_version_major;
- +@@ -358,18 +520,16 @@ struct ath10k {
- +
- + DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
- +
- +- struct targetdef *targetdef;
- +- struct hostdef *hostdef;
- +-
- + bool p2p;
- +
- + struct {
- +- void *priv;
- ++ enum ath10k_bus bus;
- + const struct ath10k_hif_ops *ops;
- + } hif;
- +
- + struct completion target_suspend;
- +
- ++ const struct ath10k_hw_regs *regs;
- + struct ath10k_bmi bmi;
- + struct ath10k_wmi wmi;
- + struct ath10k_htc htc;
- +@@ -379,12 +539,15 @@ struct ath10k {
- + u32 id;
- + const char *name;
- + u32 patch_load_addr;
- ++ int uart_pin;
- +
- + struct ath10k_hw_params_fw {
- + const char *dir;
- + const char *fw;
- + const char *otp;
- + const char *board;
- ++ size_t board_size;
- ++ size_t board_ext_size;
- + } fw;
- + } hw_params;
- +
- +@@ -400,16 +563,18 @@ struct ath10k {
- + const void *firmware_data;
- + size_t firmware_len;
- +
- ++ const struct firmware *cal_file;
- ++
- + int fw_api;
- ++ enum ath10k_cal_mode cal_mode;
- +
- + struct {
- + struct completion started;
- + struct completion completed;
- + struct completion on_channel;
- +- struct timer_list timeout;
- ++ struct delayed_work timeout;
- ++ enum ath10k_scan_state state;
- + bool is_roc;
- +- bool in_progress;
- +- bool aborting;
- + int vdev_id;
- + int roc_freq;
- + } scan;
- +@@ -427,8 +592,7 @@ struct ath10k {
- + /* current operating channel definition */
- + struct cfg80211_chan_def chandef;
- +
- +- int free_vdev_map;
- +- bool promisc;
- ++ unsigned long long free_vdev_map;
- + bool monitor;
- + int monitor_vdev_id;
- + bool monitor_started;
- +@@ -440,7 +604,12 @@ struct ath10k {
- + bool radar_enabled;
- + int num_started_vdevs;
- +
- +- struct wmi_pdev_set_wmm_params_arg wmm_params;
- ++ /* Protected by conf-mutex */
- ++ u8 supp_tx_chainmask;
- ++ u8 supp_rx_chainmask;
- ++ u8 cfg_tx_chainmask;
- ++ u8 cfg_rx_chainmask;
- ++
- + struct completion install_key_done;
- +
- + struct completion vdev_setup_done;
- +@@ -457,8 +626,13 @@ struct ath10k {
- + struct list_head peers;
- + wait_queue_head_t peer_mapping_wq;
- +
- +- /* number of created peers; protected by data_lock */
- ++ /* protected by conf_mutex */
- + int num_peers;
- ++ int num_stations;
- ++
- ++ int max_num_peers;
- ++ int max_num_stations;
- ++ int max_num_vdevs;
- +
- + struct work_struct offchan_tx_work;
- + struct sk_buff_head offchan_tx_queue;
- +@@ -470,6 +644,7 @@ struct ath10k {
- +
- + enum ath10k_state state;
- +
- ++ struct work_struct register_work;
- + struct work_struct restart_work;
- +
- + /* cycle count is reported twice for each visited channel during scan.
- +@@ -483,13 +658,46 @@ struct ath10k {
- + #ifdef CPTCFG_ATH10K_DEBUGFS
- + struct ath10k_debug debug;
- + #endif
- ++
- ++ struct {
- ++ /* relay(fs) channel for spectral scan */
- ++ struct rchan *rfs_chan_spec_scan;
- ++
- ++ /* spectral_mode and spec_config are protected by conf_mutex */
- ++ enum ath10k_spectral_mode mode;
- ++ struct ath10k_spec_scan config;
- ++ } spectral;
- ++
- ++ struct {
- ++ /* protected by conf_mutex */
- ++ const struct firmware *utf;
- ++ DECLARE_BITMAP(orig_fw_features, ATH10K_FW_FEATURE_COUNT);
- ++ enum ath10k_fw_wmi_op_version orig_wmi_op_version;
- ++
- ++ /* protected by data_lock */
- ++ bool utf_monitor;
- ++ } testmode;
- ++
- ++ struct {
- ++ /* protected by data_lock */
- ++ u32 fw_crash_counter;
- ++ u32 fw_warm_reset_counter;
- ++ u32 fw_cold_reset_counter;
- ++ } stats;
- ++
- ++ struct ath10k_thermal thermal;
- ++
- ++ /* must be last */
- ++ u8 drv_priv[0] __aligned(sizeof(void *));
- + };
- +
- +-struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
- ++struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
- ++ enum ath10k_bus bus,
- ++ enum ath10k_hw_rev hw_rev,
- + const struct ath10k_hif_ops *hif_ops);
- + void ath10k_core_destroy(struct ath10k *ar);
- +
- +-int ath10k_core_start(struct ath10k *ar);
- ++int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode);
- + int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);
- + void ath10k_core_stop(struct ath10k *ar);
- + int ath10k_core_register(struct ath10k *ar, u32 chip_id);
- +--- a/drivers/net/wireless/ath/ath10k/debug.c
- ++++ b/drivers/net/wireless/ath/ath10k/debug.c
- +@@ -17,107 +17,176 @@
- +
- + #include <linux/module.h>
- + #include <linux/debugfs.h>
- ++#include <linux/vmalloc.h>
- ++#include <linux/utsname.h>
- +
- + #include "core.h"
- + #include "debug.h"
- ++#include "hif.h"
- ++#include "wmi-ops.h"
- +
- + /* ms */
- + #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
- +
- +-static int ath10k_printk(const char *level, const char *fmt, ...)
- +-{
- +- struct va_format vaf;
- +- va_list args;
- +- int rtn;
- ++#define ATH10K_FW_CRASH_DUMP_VERSION 1
- +
- +- va_start(args, fmt);
- ++/**
- ++ * enum ath10k_fw_crash_dump_type - types of data in the dump file
- ++ * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
- ++ */
- ++enum ath10k_fw_crash_dump_type {
- ++ ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
- +
- +- vaf.fmt = fmt;
- +- vaf.va = &args;
- ++ ATH10K_FW_CRASH_DUMP_MAX,
- ++};
- +
- +- rtn = printk("%sath10k: %pV", level, &vaf);
- ++struct ath10k_tlv_dump_data {
- ++ /* see ath10k_fw_crash_dump_type above */
- ++ __le32 type;
- +
- +- va_end(args);
- ++ /* in bytes */
- ++ __le32 tlv_len;
- +
- +- return rtn;
- +-}
- ++ /* pad to 32-bit boundaries as needed */
- ++ u8 tlv_data[];
- ++} __packed;
- ++
- ++struct ath10k_dump_file_data {
- ++ /* dump file information */
- ++
- ++ /* "ATH10K-FW-DUMP" */
- ++ char df_magic[16];
- ++
- ++ __le32 len;
- ++
- ++ /* file dump version */
- ++ __le32 version;
- ++
- ++ /* some info we can get from ath10k struct that might help */
- ++
- ++ u8 uuid[16];
- ++
- ++ __le32 chip_id;
- ++
- ++ /* 0 for now, in place for later hardware */
- ++ __le32 bus_type;
- ++
- ++ __le32 target_version;
- ++ __le32 fw_version_major;
- ++ __le32 fw_version_minor;
- ++ __le32 fw_version_release;
- ++ __le32 fw_version_build;
- ++ __le32 phy_capability;
- ++ __le32 hw_min_tx_power;
- ++ __le32 hw_max_tx_power;
- ++ __le32 ht_cap_info;
- ++ __le32 vht_cap_info;
- ++ __le32 num_rf_chains;
- ++
- ++ /* firmware version string */
- ++ char fw_ver[ETHTOOL_FWVERS_LEN];
- ++
- ++ /* Kernel related information */
- ++
- ++ /* time-of-day stamp */
- ++ __le64 tv_sec;
- ++
- ++ /* time-of-day stamp, nano-seconds */
- ++ __le64 tv_nsec;
- ++
- ++ /* LINUX_VERSION_CODE */
- ++ __le32 kernel_ver_code;
- ++
- ++ /* VERMAGIC_STRING */
- ++ char kernel_ver[64];
- +
- +-int ath10k_info(const char *fmt, ...)
- ++ /* room for growth w/out changing binary format */
- ++ u8 unused[128];
- ++
- ++ /* struct ath10k_tlv_dump_data + more */
- ++ u8 data[0];
- ++} __packed;
- ++
- ++void ath10k_info(struct ath10k *ar, const char *fmt, ...)
- + {
- + struct va_format vaf = {
- + .fmt = fmt,
- + };
- + va_list args;
- +- int ret;
- +
- + va_start(args, fmt);
- + vaf.va = &args;
- +- ret = ath10k_printk(KERN_INFO, "%pV", &vaf);
- +- trace_ath10k_log_info(&vaf);
- ++ dev_info(ar->dev, "%pV", &vaf);
- ++ trace_ath10k_log_info(ar, &vaf);
- + va_end(args);
- +-
- +- return ret;
- + }
- + EXPORT_SYMBOL(ath10k_info);
- +
- +-int ath10k_err(const char *fmt, ...)
- ++void ath10k_print_driver_info(struct ath10k *ar)
- ++{
- ++ ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n",
- ++ ar->hw_params.name,
- ++ ar->target_version,
- ++ ar->chip_id,
- ++ ar->hw->wiphy->fw_version,
- ++ ar->fw_api,
- ++ ar->htt.target_version_major,
- ++ ar->htt.target_version_minor,
- ++ ar->wmi.op_version,
- ++ ath10k_cal_mode_str(ar->cal_mode),
- ++ ar->max_num_stations);
- ++ ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",
- ++ config_enabled(CPTCFG_ATH10K_DEBUG),
- ++ config_enabled(CPTCFG_ATH10K_DEBUGFS),
- ++ config_enabled(CPTCFG_ATH10K_TRACING),
- ++ config_enabled(CPTCFG_ATH10K_DFS_CERTIFIED),
- ++ config_enabled(CPTCFG_NL80211_TESTMODE));
- ++}
- ++EXPORT_SYMBOL(ath10k_print_driver_info);
- ++
- ++void ath10k_err(struct ath10k *ar, const char *fmt, ...)
- + {
- + struct va_format vaf = {
- + .fmt = fmt,
- + };
- + va_list args;
- +- int ret;
- +
- + va_start(args, fmt);
- + vaf.va = &args;
- +- ret = ath10k_printk(KERN_ERR, "%pV", &vaf);
- +- trace_ath10k_log_err(&vaf);
- ++ dev_err(ar->dev, "%pV", &vaf);
- ++ trace_ath10k_log_err(ar, &vaf);
- + va_end(args);
- +-
- +- return ret;
- + }
- + EXPORT_SYMBOL(ath10k_err);
- +
- +-int ath10k_warn(const char *fmt, ...)
- ++void ath10k_warn(struct ath10k *ar, const char *fmt, ...)
- + {
- + struct va_format vaf = {
- + .fmt = fmt,
- + };
- + va_list args;
- +- int ret = 0;
- +
- + va_start(args, fmt);
- + vaf.va = &args;
- +-
- +- if (net_ratelimit())
- +- ret = ath10k_printk(KERN_WARNING, "%pV", &vaf);
- +-
- +- trace_ath10k_log_warn(&vaf);
- ++ dev_warn_ratelimited(ar->dev, "%pV", &vaf);
- ++ trace_ath10k_log_warn(ar, &vaf);
- +
- + va_end(args);
- +-
- +- return ret;
- + }
- + EXPORT_SYMBOL(ath10k_warn);
- +
- + #ifdef CPTCFG_ATH10K_DEBUGFS
- +
- +-void ath10k_debug_read_service_map(struct ath10k *ar,
- +- void *service_map,
- +- size_t map_size)
- +-{
- +- memcpy(ar->debug.wmi_service_bitmap, service_map, map_size);
- +-}
- +-
- + static ssize_t ath10k_read_wmi_services(struct file *file,
- + char __user *user_buf,
- + size_t count, loff_t *ppos)
- + {
- + struct ath10k *ar = file->private_data;
- + char *buf;
- +- unsigned int len = 0, buf_len = 1500;
- +- const char *status;
- ++ unsigned int len = 0, buf_len = 4096;
- ++ const char *name;
- + ssize_t ret_cnt;
- ++ bool enabled;
- + int i;
- +
- + buf = kzalloc(buf_len, GFP_KERNEL);
- +@@ -129,16 +198,25 @@ static ssize_t ath10k_read_wmi_services(
- + if (len > buf_len)
- + len = buf_len;
- +
- +- for (i = 0; i < WMI_SERVICE_LAST; i++) {
- +- if (WMI_SERVICE_IS_ENABLED(ar->debug.wmi_service_bitmap, i))
- +- status = "enabled";
- +- else
- +- status = "disabled";
- ++ spin_lock_bh(&ar->data_lock);
- ++ for (i = 0; i < WMI_SERVICE_MAX; i++) {
- ++ enabled = test_bit(i, ar->wmi.svc_map);
- ++ name = wmi_service_name(i);
- ++
- ++ if (!name) {
- ++ if (enabled)
- ++ len += scnprintf(buf + len, buf_len - len,
- ++ "%-40s %s (bit %d)\n",
- ++ "unknown", "enabled", i);
- ++
- ++ continue;
- ++ }
- +
- + len += scnprintf(buf + len, buf_len - len,
- +- "0x%02x - %20s - %s\n",
- +- i, wmi_service_name(i), status);
- ++ "%-40s %s\n",
- ++ name, enabled ? "enabled" : "-");
- + }
- ++ spin_unlock_bh(&ar->data_lock);
- +
- + ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
- +
- +@@ -155,169 +233,221 @@ static const struct file_operations fops
- + .llseek = default_llseek,
- + };
- +
- +-void ath10k_debug_read_target_stats(struct ath10k *ar,
- +- struct wmi_stats_event *ev)
- ++static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head)
- + {
- +- u8 *tmp = ev->data;
- +- struct ath10k_target_stats *stats;
- +- int num_pdev_stats, num_vdev_stats, num_peer_stats;
- +- struct wmi_pdev_stats_10x *ps;
- +- int i;
- ++ struct ath10k_fw_stats_pdev *i, *tmp;
- +
- ++ list_for_each_entry_safe(i, tmp, head, list) {
- ++ list_del(&i->list);
- ++ kfree(i);
- ++ }
- ++}
- ++
- ++static void ath10k_debug_fw_stats_vdevs_free(struct list_head *head)
- ++{
- ++ struct ath10k_fw_stats_vdev *i, *tmp;
- ++
- ++ list_for_each_entry_safe(i, tmp, head, list) {
- ++ list_del(&i->list);
- ++ kfree(i);
- ++ }
- ++}
- ++
- ++static void ath10k_debug_fw_stats_peers_free(struct list_head *head)
- ++{
- ++ struct ath10k_fw_stats_peer *i, *tmp;
- ++
- ++ list_for_each_entry_safe(i, tmp, head, list) {
- ++ list_del(&i->list);
- ++ kfree(i);
- ++ }
- ++}
- ++
- ++static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
- ++{
- + spin_lock_bh(&ar->data_lock);
- ++ ar->debug.fw_stats_done = false;
- ++ ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
- ++ ath10k_debug_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
- ++ ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers);
- ++ spin_unlock_bh(&ar->data_lock);
- ++}
- +
- +- stats = &ar->debug.target_stats;
- ++static size_t ath10k_debug_fw_stats_num_peers(struct list_head *head)
- ++{
- ++ struct ath10k_fw_stats_peer *i;
- ++ size_t num = 0;
- +
- +- num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); /* 0 or 1 */
- +- num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); /* 0 or max vdevs */
- +- num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */
- +-
- +- if (num_pdev_stats) {
- +- ps = (struct wmi_pdev_stats_10x *)tmp;
- +-
- +- stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf);
- +- stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count);
- +- stats->rx_frame_count = __le32_to_cpu(ps->rx_frame_count);
- +- stats->rx_clear_count = __le32_to_cpu(ps->rx_clear_count);
- +- stats->cycle_count = __le32_to_cpu(ps->cycle_count);
- +- stats->phy_err_count = __le32_to_cpu(ps->phy_err_count);
- +- stats->chan_tx_power = __le32_to_cpu(ps->chan_tx_pwr);
- +-
- +- stats->comp_queued = __le32_to_cpu(ps->wal.tx.comp_queued);
- +- stats->comp_delivered =
- +- __le32_to_cpu(ps->wal.tx.comp_delivered);
- +- stats->msdu_enqued = __le32_to_cpu(ps->wal.tx.msdu_enqued);
- +- stats->mpdu_enqued = __le32_to_cpu(ps->wal.tx.mpdu_enqued);
- +- stats->wmm_drop = __le32_to_cpu(ps->wal.tx.wmm_drop);
- +- stats->local_enqued = __le32_to_cpu(ps->wal.tx.local_enqued);
- +- stats->local_freed = __le32_to_cpu(ps->wal.tx.local_freed);
- +- stats->hw_queued = __le32_to_cpu(ps->wal.tx.hw_queued);
- +- stats->hw_reaped = __le32_to_cpu(ps->wal.tx.hw_reaped);
- +- stats->underrun = __le32_to_cpu(ps->wal.tx.underrun);
- +- stats->tx_abort = __le32_to_cpu(ps->wal.tx.tx_abort);
- +- stats->mpdus_requed = __le32_to_cpu(ps->wal.tx.mpdus_requed);
- +- stats->tx_ko = __le32_to_cpu(ps->wal.tx.tx_ko);
- +- stats->data_rc = __le32_to_cpu(ps->wal.tx.data_rc);
- +- stats->self_triggers = __le32_to_cpu(ps->wal.tx.self_triggers);
- +- stats->sw_retry_failure =
- +- __le32_to_cpu(ps->wal.tx.sw_retry_failure);
- +- stats->illgl_rate_phy_err =
- +- __le32_to_cpu(ps->wal.tx.illgl_rate_phy_err);
- +- stats->pdev_cont_xretry =
- +- __le32_to_cpu(ps->wal.tx.pdev_cont_xretry);
- +- stats->pdev_tx_timeout =
- +- __le32_to_cpu(ps->wal.tx.pdev_tx_timeout);
- +- stats->pdev_resets = __le32_to_cpu(ps->wal.tx.pdev_resets);
- +- stats->phy_underrun = __le32_to_cpu(ps->wal.tx.phy_underrun);
- +- stats->txop_ovf = __le32_to_cpu(ps->wal.tx.txop_ovf);
- +-
- +- stats->mid_ppdu_route_change =
- +- __le32_to_cpu(ps->wal.rx.mid_ppdu_route_change);
- +- stats->status_rcvd = __le32_to_cpu(ps->wal.rx.status_rcvd);
- +- stats->r0_frags = __le32_to_cpu(ps->wal.rx.r0_frags);
- +- stats->r1_frags = __le32_to_cpu(ps->wal.rx.r1_frags);
- +- stats->r2_frags = __le32_to_cpu(ps->wal.rx.r2_frags);
- +- stats->r3_frags = __le32_to_cpu(ps->wal.rx.r3_frags);
- +- stats->htt_msdus = __le32_to_cpu(ps->wal.rx.htt_msdus);
- +- stats->htt_mpdus = __le32_to_cpu(ps->wal.rx.htt_mpdus);
- +- stats->loc_msdus = __le32_to_cpu(ps->wal.rx.loc_msdus);
- +- stats->loc_mpdus = __le32_to_cpu(ps->wal.rx.loc_mpdus);
- +- stats->oversize_amsdu =
- +- __le32_to_cpu(ps->wal.rx.oversize_amsdu);
- +- stats->phy_errs = __le32_to_cpu(ps->wal.rx.phy_errs);
- +- stats->phy_err_drop = __le32_to_cpu(ps->wal.rx.phy_err_drop);
- +- stats->mpdu_errs = __le32_to_cpu(ps->wal.rx.mpdu_errs);
- +-
- +- if (test_bit(ATH10K_FW_FEATURE_WMI_10X,
- +- ar->fw_features)) {
- +- stats->ack_rx_bad = __le32_to_cpu(ps->ack_rx_bad);
- +- stats->rts_bad = __le32_to_cpu(ps->rts_bad);
- +- stats->rts_good = __le32_to_cpu(ps->rts_good);
- +- stats->fcs_bad = __le32_to_cpu(ps->fcs_bad);
- +- stats->no_beacons = __le32_to_cpu(ps->no_beacons);
- +- stats->mib_int_count = __le32_to_cpu(ps->mib_int_count);
- +- tmp += sizeof(struct wmi_pdev_stats_10x);
- +- } else {
- +- tmp += sizeof(struct wmi_pdev_stats_old);
- +- }
- ++ list_for_each_entry(i, head, list)
- ++ ++num;
- ++
- ++ return num;
- ++}
- ++
- ++static size_t ath10k_debug_fw_stats_num_vdevs(struct list_head *head)
- ++{
- ++ struct ath10k_fw_stats_vdev *i;
- ++ size_t num = 0;
- ++
- ++ list_for_each_entry(i, head, list)
- ++ ++num;
- ++
- ++ return num;
- ++}
- ++
- ++void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
- ++{
- ++ struct ath10k_fw_stats stats = {};
- ++ bool is_start, is_started, is_end;
- ++ size_t num_peers;
- ++ size_t num_vdevs;
- ++ int ret;
- ++
- ++ INIT_LIST_HEAD(&stats.pdevs);
- ++ INIT_LIST_HEAD(&stats.vdevs);
- ++ INIT_LIST_HEAD(&stats.peers);
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++ ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to pull fw stats: %d\n", ret);
- ++ goto unlock;
- + }
- +
- +- /* 0 or max vdevs */
- +- /* Currently firmware does not support VDEV stats */
- +- if (num_vdev_stats) {
- +- struct wmi_vdev_stats *vdev_stats;
- +-
- +- for (i = 0; i < num_vdev_stats; i++) {
- +- vdev_stats = (struct wmi_vdev_stats *)tmp;
- +- tmp += sizeof(struct wmi_vdev_stats);
- +- }
- ++ /* Stat data may exceed htc-wmi buffer limit. In such case firmware
- ++ * splits the stats data and delivers it in a ping-pong fashion of
- ++ * request cmd-update event.
- ++ *
- ++ * However there is no explicit end-of-data. Instead start-of-data is
- ++ * used as an implicit one. This works as follows:
- ++ * a) discard stat update events until one with pdev stats is
- ++ * delivered - this skips session started at end of (b)
- ++ * b) consume stat update events until another one with pdev stats is
- ++ * delivered which is treated as end-of-data and is itself discarded
- ++ */
- ++
- ++ if (ar->debug.fw_stats_done) {
- ++ ath10k_warn(ar, "received unsolicited stats update event\n");
- ++ goto free;
- + }
- +
- +- if (num_peer_stats) {
- +- struct wmi_peer_stats_10x *peer_stats;
- +- struct ath10k_peer_stat *s;
- +-
- +- stats->peers = num_peer_stats;
- +-
- +- for (i = 0; i < num_peer_stats; i++) {
- +- peer_stats = (struct wmi_peer_stats_10x *)tmp;
- +- s = &stats->peer_stat[i];
- +-
- +- memcpy(s->peer_macaddr, &peer_stats->peer_macaddr.addr,
- +- ETH_ALEN);
- +- s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi);
- +- s->peer_tx_rate =
- +- __le32_to_cpu(peer_stats->peer_tx_rate);
- +- if (test_bit(ATH10K_FW_FEATURE_WMI_10X,
- +- ar->fw_features)) {
- +- s->peer_rx_rate =
- +- __le32_to_cpu(peer_stats->peer_rx_rate);
- +- tmp += sizeof(struct wmi_peer_stats_10x);
- +-
- +- } else {
- +- tmp += sizeof(struct wmi_peer_stats_old);
- +- }
- ++ num_peers = ath10k_debug_fw_stats_num_peers(&ar->debug.fw_stats.peers);
- ++ num_vdevs = ath10k_debug_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs);
- ++ is_start = (list_empty(&ar->debug.fw_stats.pdevs) &&
- ++ !list_empty(&stats.pdevs));
- ++ is_end = (!list_empty(&ar->debug.fw_stats.pdevs) &&
- ++ !list_empty(&stats.pdevs));
- ++
- ++ if (is_start)
- ++ list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);
- ++
- ++ if (is_end)
- ++ ar->debug.fw_stats_done = true;
- ++
- ++ is_started = !list_empty(&ar->debug.fw_stats.pdevs);
- ++
- ++ if (is_started && !is_end) {
- ++ if (num_peers >= ATH10K_MAX_NUM_PEER_IDS) {
- ++ /* Although this is unlikely impose a sane limit to
- ++ * prevent firmware from DoS-ing the host.
- ++ */
- ++ ath10k_warn(ar, "dropping fw peer stats\n");
- ++ goto free;
- + }
- ++
- ++ if (num_vdevs >= BITS_PER_LONG) {
- ++ ath10k_warn(ar, "dropping fw vdev stats\n");
- ++ goto free;
- ++ }
- ++
- ++ list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);
- ++ list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs);
- + }
- +
- ++ complete(&ar->debug.fw_stats_complete);
- ++
- ++free:
- ++ /* In some cases lists have been spliced and cleared. Free up
- ++ * resources if that is not the case.
- ++ */
- ++ ath10k_debug_fw_stats_pdevs_free(&stats.pdevs);
- ++ ath10k_debug_fw_stats_vdevs_free(&stats.vdevs);
- ++ ath10k_debug_fw_stats_peers_free(&stats.peers);
- ++
- ++unlock:
- + spin_unlock_bh(&ar->data_lock);
- +- complete(&ar->debug.event_stats_compl);
- + }
- +
- +-static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
- +- size_t count, loff_t *ppos)
- ++static int ath10k_debug_fw_stats_request(struct ath10k *ar)
- + {
- +- struct ath10k *ar = file->private_data;
- +- struct ath10k_target_stats *fw_stats;
- +- char *buf = NULL;
- +- unsigned int len = 0, buf_len = 8000;
- +- ssize_t ret_cnt = 0;
- +- long left;
- +- int i;
- ++ unsigned long timeout;
- + int ret;
- +
- +- fw_stats = &ar->debug.target_stats;
- ++ lockdep_assert_held(&ar->conf_mutex);
- +
- +- mutex_lock(&ar->conf_mutex);
- ++ timeout = jiffies + msecs_to_jiffies(1*HZ);
- +
- +- if (ar->state != ATH10K_STATE_ON)
- +- goto exit;
- ++ ath10k_debug_fw_stats_reset(ar);
- +
- +- buf = kzalloc(buf_len, GFP_KERNEL);
- +- if (!buf)
- +- goto exit;
- ++ for (;;) {
- ++ if (time_after(jiffies, timeout))
- ++ return -ETIMEDOUT;
- +
- +- ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
- +- if (ret) {
- +- ath10k_warn("could not request stats (%d)\n", ret);
- +- goto exit;
- ++ reinit_completion(&ar->debug.fw_stats_complete);
- ++
- ++ ret = ath10k_wmi_request_stats(ar,
- ++ WMI_STAT_PDEV |
- ++ WMI_STAT_VDEV |
- ++ WMI_STAT_PEER);
- ++ if (ret) {
- ++ ath10k_warn(ar, "could not request stats (%d)\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ret = wait_for_completion_timeout(&ar->debug.fw_stats_complete,
- ++ 1*HZ);
- ++ if (ret == 0)
- ++ return -ETIMEDOUT;
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++ if (ar->debug.fw_stats_done) {
- ++ spin_unlock_bh(&ar->data_lock);
- ++ break;
- ++ }
- ++ spin_unlock_bh(&ar->data_lock);
- + }
- +
- +- left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ);
- +- if (left <= 0)
- +- goto exit;
- ++ return 0;
- ++}
- ++
- ++/* FIXME: How to calculate the buffer size sanely? */
- ++#define ATH10K_FW_STATS_BUF_SIZE (1024*1024)
- ++
- ++static void ath10k_fw_stats_fill(struct ath10k *ar,
- ++ struct ath10k_fw_stats *fw_stats,
- ++ char *buf)
- ++{
- ++ unsigned int len = 0;
- ++ unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE;
- ++ const struct ath10k_fw_stats_pdev *pdev;
- ++ const struct ath10k_fw_stats_vdev *vdev;
- ++ const struct ath10k_fw_stats_peer *peer;
- ++ size_t num_peers;
- ++ size_t num_vdevs;
- ++ int i;
- +
- + spin_lock_bh(&ar->data_lock);
- ++
- ++ pdev = list_first_entry_or_null(&fw_stats->pdevs,
- ++ struct ath10k_fw_stats_pdev, list);
- ++ if (!pdev) {
- ++ ath10k_warn(ar, "failed to get pdev stats\n");
- ++ goto unlock;
- ++ }
- ++
- ++ num_peers = ath10k_debug_fw_stats_num_peers(&fw_stats->peers);
- ++ num_vdevs = ath10k_debug_fw_stats_num_vdevs(&fw_stats->vdevs);
- ++
- + len += scnprintf(buf + len, buf_len - len, "\n");
- + len += scnprintf(buf + len, buf_len - len, "%30s\n",
- + "ath10k PDEV stats");
- +@@ -325,29 +455,29 @@ static ssize_t ath10k_read_fw_stats(stru
- + "=================");
- +
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "Channel noise floor", fw_stats->ch_noise_floor);
- ++ "Channel noise floor", pdev->ch_noise_floor);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- +- "Channel TX power", fw_stats->chan_tx_power);
- ++ "Channel TX power", pdev->chan_tx_power);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- +- "TX frame count", fw_stats->tx_frame_count);
- ++ "TX frame count", pdev->tx_frame_count);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- +- "RX frame count", fw_stats->rx_frame_count);
- ++ "RX frame count", pdev->rx_frame_count);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- +- "RX clear count", fw_stats->rx_clear_count);
- ++ "RX clear count", pdev->rx_clear_count);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- +- "Cycle count", fw_stats->cycle_count);
- ++ "Cycle count", pdev->cycle_count);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- +- "PHY error count", fw_stats->phy_err_count);
- ++ "PHY error count", pdev->phy_err_count);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- +- "RTS bad count", fw_stats->rts_bad);
- ++ "RTS bad count", pdev->rts_bad);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- +- "RTS good count", fw_stats->rts_good);
- ++ "RTS good count", pdev->rts_good);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- +- "FCS bad count", fw_stats->fcs_bad);
- ++ "FCS bad count", pdev->fcs_bad);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- +- "No beacon count", fw_stats->no_beacons);
- ++ "No beacon count", pdev->no_beacons);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
- +- "MIB int count", fw_stats->mib_int_count);
- ++ "MIB int count", pdev->mib_int_count);
- +
- + len += scnprintf(buf + len, buf_len - len, "\n");
- + len += scnprintf(buf + len, buf_len - len, "%30s\n",
- +@@ -356,51 +486,51 @@ static ssize_t ath10k_read_fw_stats(stru
- + "=================");
- +
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "HTT cookies queued", fw_stats->comp_queued);
- ++ "HTT cookies queued", pdev->comp_queued);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "HTT cookies disp.", fw_stats->comp_delivered);
- ++ "HTT cookies disp.", pdev->comp_delivered);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "MSDU queued", fw_stats->msdu_enqued);
- ++ "MSDU queued", pdev->msdu_enqued);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "MPDU queued", fw_stats->mpdu_enqued);
- ++ "MPDU queued", pdev->mpdu_enqued);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "MSDUs dropped", fw_stats->wmm_drop);
- ++ "MSDUs dropped", pdev->wmm_drop);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "Local enqued", fw_stats->local_enqued);
- ++ "Local enqued", pdev->local_enqued);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "Local freed", fw_stats->local_freed);
- ++ "Local freed", pdev->local_freed);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "HW queued", fw_stats->hw_queued);
- ++ "HW queued", pdev->hw_queued);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "PPDUs reaped", fw_stats->hw_reaped);
- ++ "PPDUs reaped", pdev->hw_reaped);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "Num underruns", fw_stats->underrun);
- ++ "Num underruns", pdev->underrun);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "PPDUs cleaned", fw_stats->tx_abort);
- ++ "PPDUs cleaned", pdev->tx_abort);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "MPDUs requed", fw_stats->mpdus_requed);
- ++ "MPDUs requed", pdev->mpdus_requed);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "Excessive retries", fw_stats->tx_ko);
- ++ "Excessive retries", pdev->tx_ko);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "HW rate", fw_stats->data_rc);
- ++ "HW rate", pdev->data_rc);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "Sched self tiggers", fw_stats->self_triggers);
- ++ "Sched self tiggers", pdev->self_triggers);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- + "Dropped due to SW retries",
- +- fw_stats->sw_retry_failure);
- ++ pdev->sw_retry_failure);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- + "Illegal rate phy errors",
- +- fw_stats->illgl_rate_phy_err);
- ++ pdev->illgl_rate_phy_err);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "Pdev continous xretry", fw_stats->pdev_cont_xretry);
- ++ "Pdev continous xretry", pdev->pdev_cont_xretry);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "TX timeout", fw_stats->pdev_tx_timeout);
- ++ "TX timeout", pdev->pdev_tx_timeout);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "PDEV resets", fw_stats->pdev_resets);
- ++ "PDEV resets", pdev->pdev_resets);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "PHY underrun", fw_stats->phy_underrun);
- ++ "PHY underrun", pdev->phy_underrun);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "MPDU is more than txop limit", fw_stats->txop_ovf);
- ++ "MPDU is more than txop limit", pdev->txop_ovf);
- +
- + len += scnprintf(buf + len, buf_len - len, "\n");
- + len += scnprintf(buf + len, buf_len - len, "%30s\n",
- +@@ -410,84 +540,254 @@ static ssize_t ath10k_read_fw_stats(stru
- +
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- + "Mid PPDU route change",
- +- fw_stats->mid_ppdu_route_change);
- ++ pdev->mid_ppdu_route_change);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "Tot. number of statuses", fw_stats->status_rcvd);
- ++ "Tot. number of statuses", pdev->status_rcvd);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "Extra frags on rings 0", fw_stats->r0_frags);
- ++ "Extra frags on rings 0", pdev->r0_frags);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "Extra frags on rings 1", fw_stats->r1_frags);
- ++ "Extra frags on rings 1", pdev->r1_frags);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "Extra frags on rings 2", fw_stats->r2_frags);
- ++ "Extra frags on rings 2", pdev->r2_frags);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "Extra frags on rings 3", fw_stats->r3_frags);
- ++ "Extra frags on rings 3", pdev->r3_frags);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "MSDUs delivered to HTT", fw_stats->htt_msdus);
- ++ "MSDUs delivered to HTT", pdev->htt_msdus);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "MPDUs delivered to HTT", fw_stats->htt_mpdus);
- ++ "MPDUs delivered to HTT", pdev->htt_mpdus);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "MSDUs delivered to stack", fw_stats->loc_msdus);
- ++ "MSDUs delivered to stack", pdev->loc_msdus);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "MPDUs delivered to stack", fw_stats->loc_mpdus);
- ++ "MPDUs delivered to stack", pdev->loc_mpdus);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "Oversized AMSUs", fw_stats->oversize_amsdu);
- ++ "Oversized AMSUs", pdev->oversize_amsdu);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "PHY errors", fw_stats->phy_errs);
- ++ "PHY errors", pdev->phy_errs);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "PHY errors drops", fw_stats->phy_err_drop);
- ++ "PHY errors drops", pdev->phy_err_drop);
- + len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
- +- "MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs);
- ++ "MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs);
- ++
- ++ len += scnprintf(buf + len, buf_len - len, "\n");
- ++ len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
- ++ "ath10k VDEV stats", num_vdevs);
- ++ len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
- ++ "=================");
- ++
- ++ list_for_each_entry(vdev, &fw_stats->vdevs, list) {
- ++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- ++ "vdev id", vdev->vdev_id);
- ++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- ++ "beacon snr", vdev->beacon_snr);
- ++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- ++ "data snr", vdev->data_snr);
- ++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- ++ "num rx frames", vdev->num_rx_frames);
- ++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- ++ "num rts fail", vdev->num_rts_fail);
- ++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- ++ "num rts success", vdev->num_rts_success);
- ++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- ++ "num rx err", vdev->num_rx_err);
- ++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- ++ "num rx discard", vdev->num_rx_discard);
- ++ len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- ++ "num tx not acked", vdev->num_tx_not_acked);
- ++
- ++ for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames); i++)
- ++ len += scnprintf(buf + len, buf_len - len,
- ++ "%25s [%02d] %u\n",
- ++ "num tx frames", i,
- ++ vdev->num_tx_frames[i]);
- ++
- ++ for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_retries); i++)
- ++ len += scnprintf(buf + len, buf_len - len,
- ++ "%25s [%02d] %u\n",
- ++ "num tx frames retries", i,
- ++ vdev->num_tx_frames_retries[i]);
- ++
- ++ for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_failures); i++)
- ++ len += scnprintf(buf + len, buf_len - len,
- ++ "%25s [%02d] %u\n",
- ++ "num tx frames failures", i,
- ++ vdev->num_tx_frames_failures[i]);
- ++
- ++ for (i = 0 ; i < ARRAY_SIZE(vdev->tx_rate_history); i++)
- ++ len += scnprintf(buf + len, buf_len - len,
- ++ "%25s [%02d] 0x%08x\n",
- ++ "tx rate history", i,
- ++ vdev->tx_rate_history[i]);
- ++
- ++ for (i = 0 ; i < ARRAY_SIZE(vdev->beacon_rssi_history); i++)
- ++ len += scnprintf(buf + len, buf_len - len,
- ++ "%25s [%02d] %u\n",
- ++ "beacon rssi history", i,
- ++ vdev->beacon_rssi_history[i]);
- ++
- ++ len += scnprintf(buf + len, buf_len - len, "\n");
- ++ }
- +
- + len += scnprintf(buf + len, buf_len - len, "\n");
- +- len += scnprintf(buf + len, buf_len - len, "%30s (%d)\n",
- +- "ath10k PEER stats", fw_stats->peers);
- ++ len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
- ++ "ath10k PEER stats", num_peers);
- + len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
- + "=================");
- +
- +- for (i = 0; i < fw_stats->peers; i++) {
- ++ list_for_each_entry(peer, &fw_stats->peers, list) {
- + len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
- +- "Peer MAC address",
- +- fw_stats->peer_stat[i].peer_macaddr);
- ++ "Peer MAC address", peer->peer_macaddr);
- + len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- +- "Peer RSSI", fw_stats->peer_stat[i].peer_rssi);
- ++ "Peer RSSI", peer->peer_rssi);
- + len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- +- "Peer TX rate",
- +- fw_stats->peer_stat[i].peer_tx_rate);
- ++ "Peer TX rate", peer->peer_tx_rate);
- + len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
- +- "Peer RX rate",
- +- fw_stats->peer_stat[i].peer_rx_rate);
- ++ "Peer RX rate", peer->peer_rx_rate);
- + len += scnprintf(buf + len, buf_len - len, "\n");
- + }
- ++
- ++unlock:
- + spin_unlock_bh(&ar->data_lock);
- +
- +- if (len > buf_len)
- +- len = buf_len;
- ++ if (len >= buf_len)
- ++ buf[len - 1] = 0;
- ++ else
- ++ buf[len] = 0;
- ++}
- +
- +- ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
- ++static int ath10k_fw_stats_open(struct inode *inode, struct file *file)
- ++{
- ++ struct ath10k *ar = inode->i_private;
- ++ void *buf = NULL;
- ++ int ret;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ if (ar->state != ATH10K_STATE_ON) {
- ++ ret = -ENETDOWN;
- ++ goto err_unlock;
- ++ }
- ++
- ++ buf = vmalloc(ATH10K_FW_STATS_BUF_SIZE);
- ++ if (!buf) {
- ++ ret = -ENOMEM;
- ++ goto err_unlock;
- ++ }
- ++
- ++ ret = ath10k_debug_fw_stats_request(ar);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to request fw stats: %d\n", ret);
- ++ goto err_free;
- ++ }
- ++
- ++ ath10k_fw_stats_fill(ar, &ar->debug.fw_stats, buf);
- ++ file->private_data = buf;
- +
- +-exit:
- + mutex_unlock(&ar->conf_mutex);
- +- kfree(buf);
- +- return ret_cnt;
- ++ return 0;
- ++
- ++err_free:
- ++ vfree(buf);
- ++
- ++err_unlock:
- ++ mutex_unlock(&ar->conf_mutex);
- ++ return ret;
- ++}
- ++
- ++static int ath10k_fw_stats_release(struct inode *inode, struct file *file)
- ++{
- ++ vfree(file->private_data);
- ++
- ++ return 0;
- ++}
- ++
- ++static ssize_t ath10k_fw_stats_read(struct file *file, char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ const char *buf = file->private_data;
- ++ unsigned int len = strlen(buf);
- ++
- ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
- + }
- +
- + static const struct file_operations fops_fw_stats = {
- +- .read = ath10k_read_fw_stats,
- ++ .open = ath10k_fw_stats_open,
- ++ .release = ath10k_fw_stats_release,
- ++ .read = ath10k_fw_stats_read,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- ++static ssize_t ath10k_debug_fw_reset_stats_read(struct file *file,
- ++ char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ int ret, len, buf_len;
- ++ char *buf;
- ++
- ++ buf_len = 500;
- ++ buf = kmalloc(buf_len, GFP_KERNEL);
- ++ if (!buf)
- ++ return -ENOMEM;
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++
- ++ len = 0;
- ++ len += scnprintf(buf + len, buf_len - len,
- ++ "fw_crash_counter\t\t%d\n", ar->stats.fw_crash_counter);
- ++ len += scnprintf(buf + len, buf_len - len,
- ++ "fw_warm_reset_counter\t\t%d\n",
- ++ ar->stats.fw_warm_reset_counter);
- ++ len += scnprintf(buf + len, buf_len - len,
- ++ "fw_cold_reset_counter\t\t%d\n",
- ++ ar->stats.fw_cold_reset_counter);
- ++
- ++ spin_unlock_bh(&ar->data_lock);
- ++
- ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
- ++
- ++ kfree(buf);
- ++
- ++ return ret;
- ++}
- ++
- ++static const struct file_operations fops_fw_reset_stats = {
- + .open = simple_open,
- ++ .read = ath10k_debug_fw_reset_stats_read,
- + .owner = THIS_MODULE,
- + .llseek = default_llseek,
- + };
- +
- ++/* This is a clean assert crash in firmware. */
- ++static int ath10k_debug_fw_assert(struct ath10k *ar)
- ++{
- ++ struct wmi_vdev_install_key_cmd *cmd;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + 16);
- ++ if (!skb)
- ++ return -ENOMEM;
- ++
- ++ cmd = (struct wmi_vdev_install_key_cmd *)skb->data;
- ++ memset(cmd, 0, sizeof(*cmd));
- ++
- ++ /* big enough number so that firmware asserts */
- ++ cmd->vdev_id = __cpu_to_le32(0x7ffe);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->vdev_install_key_cmdid);
- ++}
- ++
- + static ssize_t ath10k_read_simulate_fw_crash(struct file *file,
- + char __user *user_buf,
- + size_t count, loff_t *ppos)
- + {
- +- const char buf[] = "To simulate firmware crash write one of the"
- +- " keywords to this file:\n `soft` - this will send"
- +- " WMI_FORCE_FW_HANG_ASSERT to firmware if FW"
- +- " supports that command.\n `hard` - this will send"
- +- " to firmware command with illegal parameters"
- +- " causing firmware crash.\n";
- ++ const char buf[] =
- ++ "To simulate firmware crash write one of the keywords to this file:\n"
- ++ "`soft` - this will send WMI_FORCE_FW_HANG_ASSERT to firmware if FW supports that command.\n"
- ++ "`hard` - this will send to firmware command with illegal parameters causing firmware crash.\n"
- ++ "`assert` - this will send special illegal parameter to firmware to cause assert failure and crash.\n"
- ++ "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";
- +
- + return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
- + }
- +@@ -527,19 +827,30 @@ static ssize_t ath10k_write_simulate_fw_
- + }
- +
- + if (!strcmp(buf, "soft")) {
- +- ath10k_info("simulating soft firmware crash\n");
- ++ ath10k_info(ar, "simulating soft firmware crash\n");
- + ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
- + } else if (!strcmp(buf, "hard")) {
- +- ath10k_info("simulating hard firmware crash\n");
- +- ret = ath10k_wmi_vdev_set_param(ar, TARGET_NUM_VDEVS + 1,
- +- ar->wmi.vdev_param->rts_threshold, 0);
- ++ ath10k_info(ar, "simulating hard firmware crash\n");
- ++ /* 0x7fff is vdev id, and it is always out of range for all
- ++ * firmware variants in order to force a firmware crash.
- ++ */
- ++ ret = ath10k_wmi_vdev_set_param(ar, 0x7fff,
- ++ ar->wmi.vdev_param->rts_threshold,
- ++ 0);
- ++ } else if (!strcmp(buf, "assert")) {
- ++ ath10k_info(ar, "simulating firmware assert crash\n");
- ++ ret = ath10k_debug_fw_assert(ar);
- ++ } else if (!strcmp(buf, "hw-restart")) {
- ++ ath10k_info(ar, "user requested hw restart\n");
- ++ queue_work(ar->workqueue, &ar->restart_work);
- ++ ret = 0;
- + } else {
- + ret = -EINVAL;
- + goto exit;
- + }
- +
- + if (ret) {
- +- ath10k_warn("failed to simulate firmware crash: %d\n", ret);
- ++ ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret);
- + goto exit;
- + }
- +
- +@@ -565,13 +876,375 @@ static ssize_t ath10k_read_chip_id(struc
- + unsigned int len;
- + char buf[50];
- +
- +- len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->chip_id);
- ++ len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->chip_id);
- ++
- ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
- ++}
- ++
- ++static const struct file_operations fops_chip_id = {
- ++ .read = ath10k_read_chip_id,
- ++ .open = simple_open,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- ++struct ath10k_fw_crash_data *
- ++ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
- ++{
- ++ struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
- ++
- ++ lockdep_assert_held(&ar->data_lock);
- ++
- ++ crash_data->crashed_since_read = true;
- ++ uuid_le_gen(&crash_data->uuid);
- ++ getnstimeofday(&crash_data->timestamp);
- ++
- ++ return crash_data;
- ++}
- ++EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data);
- ++
- ++static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
- ++{
- ++ struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
- ++ struct ath10k_dump_file_data *dump_data;
- ++ struct ath10k_tlv_dump_data *dump_tlv;
- ++ int hdr_len = sizeof(*dump_data);
- ++ unsigned int len, sofar = 0;
- ++ unsigned char *buf;
- ++
- ++ len = hdr_len;
- ++ len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
- ++
- ++ sofar += hdr_len;
- ++
- ++ /* This is going to get big when we start dumping FW RAM and such,
- ++ * so go ahead and use vmalloc.
- ++ */
- ++ buf = vzalloc(len);
- ++ if (!buf)
- ++ return NULL;
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++
- ++ if (!crash_data->crashed_since_read) {
- ++ spin_unlock_bh(&ar->data_lock);
- ++ vfree(buf);
- ++ return NULL;
- ++ }
- ++
- ++ dump_data = (struct ath10k_dump_file_data *)(buf);
- ++ strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP",
- ++ sizeof(dump_data->df_magic));
- ++ dump_data->len = cpu_to_le32(len);
- ++
- ++ dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION);
- ++
- ++ memcpy(dump_data->uuid, &crash_data->uuid, sizeof(dump_data->uuid));
- ++ dump_data->chip_id = cpu_to_le32(ar->chip_id);
- ++ dump_data->bus_type = cpu_to_le32(0);
- ++ dump_data->target_version = cpu_to_le32(ar->target_version);
- ++ dump_data->fw_version_major = cpu_to_le32(ar->fw_version_major);
- ++ dump_data->fw_version_minor = cpu_to_le32(ar->fw_version_minor);
- ++ dump_data->fw_version_release = cpu_to_le32(ar->fw_version_release);
- ++ dump_data->fw_version_build = cpu_to_le32(ar->fw_version_build);
- ++ dump_data->phy_capability = cpu_to_le32(ar->phy_capability);
- ++ dump_data->hw_min_tx_power = cpu_to_le32(ar->hw_min_tx_power);
- ++ dump_data->hw_max_tx_power = cpu_to_le32(ar->hw_max_tx_power);
- ++ dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info);
- ++ dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info);
- ++ dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);
- ++
- ++ strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
- ++ sizeof(dump_data->fw_ver));
- ++
- ++ dump_data->kernel_ver_code = 0;
- ++ strlcpy(dump_data->kernel_ver, init_utsname()->release,
- ++ sizeof(dump_data->kernel_ver));
- ++
- ++ dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec);
- ++ dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec);
- ++
- ++ /* Gather crash-dump */
- ++ dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
- ++ dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS);
- ++ dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers));
- ++ memcpy(dump_tlv->tlv_data, &crash_data->registers,
- ++ sizeof(crash_data->registers));
- ++ sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers);
- ++
- ++ ar->debug.fw_crash_data->crashed_since_read = false;
- ++
- ++ spin_unlock_bh(&ar->data_lock);
- ++
- ++ return dump_data;
- ++}
- ++
- ++static int ath10k_fw_crash_dump_open(struct inode *inode, struct file *file)
- ++{
- ++ struct ath10k *ar = inode->i_private;
- ++ struct ath10k_dump_file_data *dump;
- ++
- ++ dump = ath10k_build_dump_file(ar);
- ++ if (!dump)
- ++ return -ENODATA;
- ++
- ++ file->private_data = dump;
- ++
- ++ return 0;
- ++}
- ++
- ++static ssize_t ath10k_fw_crash_dump_read(struct file *file,
- ++ char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k_dump_file_data *dump_file = file->private_data;
- ++
- ++ return simple_read_from_buffer(user_buf, count, ppos,
- ++ dump_file,
- ++ le32_to_cpu(dump_file->len));
- ++}
- ++
- ++static int ath10k_fw_crash_dump_release(struct inode *inode,
- ++ struct file *file)
- ++{
- ++ vfree(file->private_data);
- ++
- ++ return 0;
- ++}
- ++
- ++static const struct file_operations fops_fw_crash_dump = {
- ++ .open = ath10k_fw_crash_dump_open,
- ++ .read = ath10k_fw_crash_dump_read,
- ++ .release = ath10k_fw_crash_dump_release,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- ++static ssize_t ath10k_reg_addr_read(struct file *file,
- ++ char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ u8 buf[32];
- ++ unsigned int len = 0;
- ++ u32 reg_addr;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ reg_addr = ar->debug.reg_addr;
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", reg_addr);
- ++
- ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
- ++}
- ++
- ++static ssize_t ath10k_reg_addr_write(struct file *file,
- ++ const char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ u32 reg_addr;
- ++ int ret;
- ++
- ++ ret = kstrtou32_from_user(user_buf, count, 0, ®_addr);
- ++ if (ret)
- ++ return ret;
- ++
- ++ if (!IS_ALIGNED(reg_addr, 4))
- ++ return -EFAULT;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ ar->debug.reg_addr = reg_addr;
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return count;
- ++}
- ++
- ++static const struct file_operations fops_reg_addr = {
- ++ .read = ath10k_reg_addr_read,
- ++ .write = ath10k_reg_addr_write,
- ++ .open = simple_open,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- ++static ssize_t ath10k_reg_value_read(struct file *file,
- ++ char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ u8 buf[48];
- ++ unsigned int len;
- ++ u32 reg_addr, reg_val;
- ++ int ret;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ if (ar->state != ATH10K_STATE_ON &&
- ++ ar->state != ATH10K_STATE_UTF) {
- ++ ret = -ENETDOWN;
- ++ goto exit;
- ++ }
- ++
- ++ reg_addr = ar->debug.reg_addr;
- ++
- ++ reg_val = ath10k_hif_read32(ar, reg_addr);
- ++ len = scnprintf(buf, sizeof(buf), "0x%08x:0x%08x\n", reg_addr, reg_val);
- ++
- ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
- ++
- ++exit:
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return ret;
- ++}
- ++
- ++static ssize_t ath10k_reg_value_write(struct file *file,
- ++ const char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ u32 reg_addr, reg_val;
- ++ int ret;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ if (ar->state != ATH10K_STATE_ON &&
- ++ ar->state != ATH10K_STATE_UTF) {
- ++ ret = -ENETDOWN;
- ++ goto exit;
- ++ }
- ++
- ++ reg_addr = ar->debug.reg_addr;
- ++
- ++ ret = kstrtou32_from_user(user_buf, count, 0, ®_val);
- ++ if (ret)
- ++ goto exit;
- ++
- ++ ath10k_hif_write32(ar, reg_addr, reg_val);
- ++
- ++ ret = count;
- ++
- ++exit:
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return ret;
- ++}
- ++
- ++static const struct file_operations fops_reg_value = {
- ++ .read = ath10k_reg_value_read,
- ++ .write = ath10k_reg_value_write,
- ++ .open = simple_open,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- ++static ssize_t ath10k_mem_value_read(struct file *file,
- ++ char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ u8 *buf;
- ++ int ret;
- ++
- ++ if (*ppos < 0)
- ++ return -EINVAL;
- ++
- ++ if (!count)
- ++ return 0;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ buf = vmalloc(count);
- ++ if (!buf) {
- ++ ret = -ENOMEM;
- ++ goto exit;
- ++ }
- ++
- ++ if (ar->state != ATH10K_STATE_ON &&
- ++ ar->state != ATH10K_STATE_UTF) {
- ++ ret = -ENETDOWN;
- ++ goto exit;
- ++ }
- ++
- ++ ret = ath10k_hif_diag_read(ar, *ppos, buf, count);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to read address 0x%08x via diagnose window fnrom debugfs: %d\n",
- ++ (u32)(*ppos), ret);
- ++ goto exit;
- ++ }
- ++
- ++ ret = copy_to_user(user_buf, buf, count);
- ++ if (ret) {
- ++ ret = -EFAULT;
- ++ goto exit;
- ++ }
- ++
- ++ count -= ret;
- ++ *ppos += count;
- ++ ret = count;
- ++
- ++exit:
- ++ vfree(buf);
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return ret;
- ++}
- ++
- ++static ssize_t ath10k_mem_value_write(struct file *file,
- ++ const char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ u8 *buf;
- ++ int ret;
- ++
- ++ if (*ppos < 0)
- ++ return -EINVAL;
- ++
- ++ if (!count)
- ++ return 0;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ buf = vmalloc(count);
- ++ if (!buf) {
- ++ ret = -ENOMEM;
- ++ goto exit;
- ++ }
- ++
- ++ if (ar->state != ATH10K_STATE_ON &&
- ++ ar->state != ATH10K_STATE_UTF) {
- ++ ret = -ENETDOWN;
- ++ goto exit;
- ++ }
- ++
- ++ ret = copy_from_user(buf, user_buf, count);
- ++ if (ret) {
- ++ ret = -EFAULT;
- ++ goto exit;
- ++ }
- ++
- ++ ret = ath10k_hif_diag_write(ar, *ppos, buf, count);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to write address 0x%08x via diagnose window from debugfs: %d\n",
- ++ (u32)(*ppos), ret);
- ++ goto exit;
- ++ }
- ++
- ++ *ppos += count;
- ++ ret = count;
- +
- +- return simple_read_from_buffer(user_buf, count, ppos, buf, len);
- ++exit:
- ++ vfree(buf);
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return ret;
- + }
- +
- +-static const struct file_operations fops_chip_id = {
- +- .read = ath10k_read_chip_id,
- ++static const struct file_operations fops_mem_value = {
- ++ .read = ath10k_mem_value_read,
- ++ .write = ath10k_mem_value_write,
- + .open = simple_open,
- + .owner = THIS_MODULE,
- + .llseek = default_llseek,
- +@@ -596,7 +1269,7 @@ static int ath10k_debug_htt_stats_req(st
- + ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask,
- + cookie);
- + if (ret) {
- +- ath10k_warn("failed to send htt stats request: %d\n", ret);
- ++ ath10k_warn(ar, "failed to send htt stats request: %d\n", ret);
- + return ret;
- + }
- +
- +@@ -619,8 +1292,8 @@ static void ath10k_debug_htt_stats_dwork
- + }
- +
- + static ssize_t ath10k_read_htt_stats_mask(struct file *file,
- +- char __user *user_buf,
- +- size_t count, loff_t *ppos)
- ++ char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- + {
- + struct ath10k *ar = file->private_data;
- + char buf[32];
- +@@ -632,8 +1305,8 @@ static ssize_t ath10k_read_htt_stats_mas
- + }
- +
- + static ssize_t ath10k_write_htt_stats_mask(struct file *file,
- +- const char __user *user_buf,
- +- size_t count, loff_t *ppos)
- ++ const char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- + {
- + struct ath10k *ar = file->private_data;
- + unsigned long mask;
- +@@ -671,16 +1344,82 @@ static const struct file_operations fops
- + .llseek = default_llseek,
- + };
- +
- ++static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file,
- ++ char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ char buf[64];
- ++ u8 amsdu = 3, ampdu = 64;
- ++ unsigned int len;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ if (ar->debug.htt_max_amsdu)
- ++ amsdu = ar->debug.htt_max_amsdu;
- ++
- ++ if (ar->debug.htt_max_ampdu)
- ++ ampdu = ar->debug.htt_max_ampdu;
- ++
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu);
- ++
- ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
- ++}
- ++
- ++static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file,
- ++ const char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ int res;
- ++ char buf[64];
- ++ unsigned int amsdu, ampdu;
- ++
- ++ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
- ++
- ++ /* make sure that buf is null terminated */
- ++ buf[sizeof(buf) - 1] = 0;
- ++
- ++ res = sscanf(buf, "%u %u", &amsdu, &du);
- ++
- ++ if (res != 2)
- ++ return -EINVAL;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ res = ath10k_htt_h2t_aggr_cfg_msg(&ar->htt, ampdu, amsdu);
- ++ if (res)
- ++ goto out;
- ++
- ++ res = count;
- ++ ar->debug.htt_max_amsdu = amsdu;
- ++ ar->debug.htt_max_ampdu = ampdu;
- ++
- ++out:
- ++ mutex_unlock(&ar->conf_mutex);
- ++ return res;
- ++}
- ++
- ++static const struct file_operations fops_htt_max_amsdu_ampdu = {
- ++ .read = ath10k_read_htt_max_amsdu_ampdu,
- ++ .write = ath10k_write_htt_max_amsdu_ampdu,
- ++ .open = simple_open,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- + static ssize_t ath10k_read_fw_dbglog(struct file *file,
- +- char __user *user_buf,
- +- size_t count, loff_t *ppos)
- ++ char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- + {
- + struct ath10k *ar = file->private_data;
- + unsigned int len;
- +- char buf[32];
- ++ char buf[64];
- +
- +- len = scnprintf(buf, sizeof(buf), "0x%08x\n",
- +- ar->debug.fw_dbglog_mask);
- ++ len = scnprintf(buf, sizeof(buf), "0x%08x %u\n",
- ++ ar->debug.fw_dbglog_mask, ar->debug.fw_dbglog_level);
- +
- + return simple_read_from_buffer(user_buf, count, ppos, buf, len);
- + }
- +@@ -690,21 +1429,34 @@ static ssize_t ath10k_write_fw_dbglog(st
- + size_t count, loff_t *ppos)
- + {
- + struct ath10k *ar = file->private_data;
- +- unsigned long mask;
- + int ret;
- ++ char buf[64];
- ++ unsigned int log_level, mask;
- +
- +- ret = kstrtoul_from_user(user_buf, count, 0, &mask);
- +- if (ret)
- +- return ret;
- ++ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
- ++
- ++ /* make sure that buf is null terminated */
- ++ buf[sizeof(buf) - 1] = 0;
- ++
- ++ ret = sscanf(buf, "%x %u", &mask, &log_level);
- ++
- ++ if (!ret)
- ++ return -EINVAL;
- ++
- ++ if (ret == 1)
- ++ /* default if user did not specify */
- ++ log_level = ATH10K_DBGLOG_LEVEL_WARN;
- +
- + mutex_lock(&ar->conf_mutex);
- +
- + ar->debug.fw_dbglog_mask = mask;
- ++ ar->debug.fw_dbglog_level = log_level;
- +
- + if (ar->state == ATH10K_STATE_ON) {
- +- ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
- ++ ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask,
- ++ ar->debug.fw_dbglog_level);
- + if (ret) {
- +- ath10k_warn("dbglog cfg failed from debugfs: %d\n",
- ++ ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n",
- + ret);
- + goto exit;
- + }
- +@@ -718,6 +1470,166 @@ exit:
- + return ret;
- + }
- +
- ++/* TODO: Would be nice to always support ethtool stats, would need to
- ++ * move the stats storage out of ath10k_debug, or always have ath10k_debug
- ++ * struct available..
- ++ */
- ++
- ++/* This generally cooresponds to the debugfs fw_stats file */
- ++static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
- ++ "tx_pkts_nic",
- ++ "tx_bytes_nic",
- ++ "rx_pkts_nic",
- ++ "rx_bytes_nic",
- ++ "d_noise_floor",
- ++ "d_cycle_count",
- ++ "d_phy_error",
- ++ "d_rts_bad",
- ++ "d_rts_good",
- ++ "d_tx_power", /* in .5 dbM I think */
- ++ "d_rx_crc_err", /* fcs_bad */
- ++ "d_no_beacon",
- ++ "d_tx_mpdus_queued",
- ++ "d_tx_msdu_queued",
- ++ "d_tx_msdu_dropped",
- ++ "d_local_enqued",
- ++ "d_local_freed",
- ++ "d_tx_ppdu_hw_queued",
- ++ "d_tx_ppdu_reaped",
- ++ "d_tx_fifo_underrun",
- ++ "d_tx_ppdu_abort",
- ++ "d_tx_mpdu_requed",
- ++ "d_tx_excessive_retries",
- ++ "d_tx_hw_rate",
- ++ "d_tx_dropped_sw_retries",
- ++ "d_tx_illegal_rate",
- ++ "d_tx_continuous_xretries",
- ++ "d_tx_timeout",
- ++ "d_tx_mpdu_txop_limit",
- ++ "d_pdev_resets",
- ++ "d_rx_mid_ppdu_route_change",
- ++ "d_rx_status",
- ++ "d_rx_extra_frags_ring0",
- ++ "d_rx_extra_frags_ring1",
- ++ "d_rx_extra_frags_ring2",
- ++ "d_rx_extra_frags_ring3",
- ++ "d_rx_msdu_htt",
- ++ "d_rx_mpdu_htt",
- ++ "d_rx_msdu_stack",
- ++ "d_rx_mpdu_stack",
- ++ "d_rx_phy_err",
- ++ "d_rx_phy_err_drops",
- ++ "d_rx_mpdu_errors", /* FCS, MIC, ENC */
- ++ "d_fw_crash_count",
- ++ "d_fw_warm_reset_count",
- ++ "d_fw_cold_reset_count",
- ++};
- ++
- ++#define ATH10K_SSTATS_LEN ARRAY_SIZE(ath10k_gstrings_stats)
- ++
- ++void ath10k_debug_get_et_strings(struct ieee80211_hw *hw,
- ++ struct ieee80211_vif *vif,
- ++ u32 sset, u8 *data)
- ++{
- ++ if (sset == ETH_SS_STATS)
- ++ memcpy(data, *ath10k_gstrings_stats,
- ++ sizeof(ath10k_gstrings_stats));
- ++}
- ++
- ++int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
- ++ struct ieee80211_vif *vif, int sset)
- ++{
- ++ if (sset == ETH_SS_STATS)
- ++ return ATH10K_SSTATS_LEN;
- ++
- ++ return 0;
- ++}
- ++
- ++void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
- ++ struct ieee80211_vif *vif,
- ++ struct ethtool_stats *stats, u64 *data)
- ++{
- ++ struct ath10k *ar = hw->priv;
- ++ static const struct ath10k_fw_stats_pdev zero_stats = {};
- ++ const struct ath10k_fw_stats_pdev *pdev_stats;
- ++ int i = 0, ret;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ if (ar->state == ATH10K_STATE_ON) {
- ++ ret = ath10k_debug_fw_stats_request(ar);
- ++ if (ret) {
- ++ /* just print a warning and try to use older results */
- ++ ath10k_warn(ar,
- ++ "failed to get fw stats for ethtool: %d\n",
- ++ ret);
- ++ }
- ++ }
- ++
- ++ pdev_stats = list_first_entry_or_null(&ar->debug.fw_stats.pdevs,
- ++ struct ath10k_fw_stats_pdev,
- ++ list);
- ++ if (!pdev_stats) {
- ++ /* no results available so just return zeroes */
- ++ pdev_stats = &zero_stats;
- ++ }
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++
- ++ data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */
- ++ data[i++] = 0; /* tx bytes */
- ++ data[i++] = pdev_stats->htt_mpdus;
- ++ data[i++] = 0; /* rx bytes */
- ++ data[i++] = pdev_stats->ch_noise_floor;
- ++ data[i++] = pdev_stats->cycle_count;
- ++ data[i++] = pdev_stats->phy_err_count;
- ++ data[i++] = pdev_stats->rts_bad;
- ++ data[i++] = pdev_stats->rts_good;
- ++ data[i++] = pdev_stats->chan_tx_power;
- ++ data[i++] = pdev_stats->fcs_bad;
- ++ data[i++] = pdev_stats->no_beacons;
- ++ data[i++] = pdev_stats->mpdu_enqued;
- ++ data[i++] = pdev_stats->msdu_enqued;
- ++ data[i++] = pdev_stats->wmm_drop;
- ++ data[i++] = pdev_stats->local_enqued;
- ++ data[i++] = pdev_stats->local_freed;
- ++ data[i++] = pdev_stats->hw_queued;
- ++ data[i++] = pdev_stats->hw_reaped;
- ++ data[i++] = pdev_stats->underrun;
- ++ data[i++] = pdev_stats->tx_abort;
- ++ data[i++] = pdev_stats->mpdus_requed;
- ++ data[i++] = pdev_stats->tx_ko;
- ++ data[i++] = pdev_stats->data_rc;
- ++ data[i++] = pdev_stats->sw_retry_failure;
- ++ data[i++] = pdev_stats->illgl_rate_phy_err;
- ++ data[i++] = pdev_stats->pdev_cont_xretry;
- ++ data[i++] = pdev_stats->pdev_tx_timeout;
- ++ data[i++] = pdev_stats->txop_ovf;
- ++ data[i++] = pdev_stats->pdev_resets;
- ++ data[i++] = pdev_stats->mid_ppdu_route_change;
- ++ data[i++] = pdev_stats->status_rcvd;
- ++ data[i++] = pdev_stats->r0_frags;
- ++ data[i++] = pdev_stats->r1_frags;
- ++ data[i++] = pdev_stats->r2_frags;
- ++ data[i++] = pdev_stats->r3_frags;
- ++ data[i++] = pdev_stats->htt_msdus;
- ++ data[i++] = pdev_stats->htt_mpdus;
- ++ data[i++] = pdev_stats->loc_msdus;
- ++ data[i++] = pdev_stats->loc_mpdus;
- ++ data[i++] = pdev_stats->phy_errs;
- ++ data[i++] = pdev_stats->phy_err_drop;
- ++ data[i++] = pdev_stats->mpdu_errs;
- ++ data[i++] = ar->stats.fw_crash_counter;
- ++ data[i++] = ar->stats.fw_warm_reset_counter;
- ++ data[i++] = ar->stats.fw_cold_reset_counter;
- ++
- ++ spin_unlock_bh(&ar->data_lock);
- ++
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ WARN_ON(i != ATH10K_SSTATS_LEN);
- ++}
- ++
- + static const struct file_operations fops_fw_dbglog = {
- + .read = ath10k_read_fw_dbglog,
- + .write = ath10k_write_fw_dbglog,
- +@@ -726,6 +1638,151 @@ static const struct file_operations fops
- + .llseek = default_llseek,
- + };
- +
- ++static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file)
- ++{
- ++ struct ath10k *ar = inode->i_private;
- ++ void *buf;
- ++ u32 hi_addr;
- ++ __le32 addr;
- ++ int ret;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ if (ar->state != ATH10K_STATE_ON &&
- ++ ar->state != ATH10K_STATE_UTF) {
- ++ ret = -ENETDOWN;
- ++ goto err;
- ++ }
- ++
- ++ buf = vmalloc(QCA988X_CAL_DATA_LEN);
- ++ if (!buf) {
- ++ ret = -ENOMEM;
- ++ goto err;
- ++ }
- ++
- ++ hi_addr = host_interest_item_address(HI_ITEM(hi_board_data));
- ++
- ++ ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr));
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to read hi_board_data address: %d\n", ret);
- ++ goto err_vfree;
- ++ }
- ++
- ++ ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), buf,
- ++ QCA988X_CAL_DATA_LEN);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to read calibration data: %d\n", ret);
- ++ goto err_vfree;
- ++ }
- ++
- ++ file->private_data = buf;
- ++
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return 0;
- ++
- ++err_vfree:
- ++ vfree(buf);
- ++
- ++err:
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return ret;
- ++}
- ++
- ++static ssize_t ath10k_debug_cal_data_read(struct file *file,
- ++ char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ void *buf = file->private_data;
- ++
- ++ return simple_read_from_buffer(user_buf, count, ppos,
- ++ buf, QCA988X_CAL_DATA_LEN);
- ++}
- ++
- ++static int ath10k_debug_cal_data_release(struct inode *inode,
- ++ struct file *file)
- ++{
- ++ vfree(file->private_data);
- ++
- ++ return 0;
- ++}
- ++
- ++static const struct file_operations fops_cal_data = {
- ++ .open = ath10k_debug_cal_data_open,
- ++ .read = ath10k_debug_cal_data_read,
- ++ .release = ath10k_debug_cal_data_release,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- ++static ssize_t ath10k_read_nf_cal_period(struct file *file,
- ++ char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ unsigned int len;
- ++ char buf[32];
- ++
- ++ len = scnprintf(buf, sizeof(buf), "%d\n",
- ++ ar->debug.nf_cal_period);
- ++
- ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
- ++}
- ++
- ++static ssize_t ath10k_write_nf_cal_period(struct file *file,
- ++ const char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ unsigned long period;
- ++ int ret;
- ++
- ++ ret = kstrtoul_from_user(user_buf, count, 0, &period);
- ++ if (ret)
- ++ return ret;
- ++
- ++ if (period > WMI_PDEV_PARAM_CAL_PERIOD_MAX)
- ++ return -EINVAL;
- ++
- ++ /* there's no way to switch back to the firmware default */
- ++ if (period == 0)
- ++ return -EINVAL;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ ar->debug.nf_cal_period = period;
- ++
- ++ if (ar->state != ATH10K_STATE_ON) {
- ++ /* firmware is not running, nothing else to do */
- ++ ret = count;
- ++ goto exit;
- ++ }
- ++
- ++ ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period,
- ++ ar->debug.nf_cal_period);
- ++ if (ret) {
- ++ ath10k_warn(ar, "cal period cfg failed from debugfs: %d\n",
- ++ ret);
- ++ goto exit;
- ++ }
- ++
- ++ ret = count;
- ++
- ++exit:
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return ret;
- ++}
- ++
- ++static const struct file_operations fops_nf_cal_period = {
- ++ .read = ath10k_read_nf_cal_period,
- ++ .write = ath10k_write_nf_cal_period,
- ++ .open = simple_open,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- + int ath10k_debug_start(struct ath10k *ar)
- + {
- + int ret;
- +@@ -735,17 +1792,44 @@ int ath10k_debug_start(struct ath10k *ar
- + ret = ath10k_debug_htt_stats_req(ar);
- + if (ret)
- + /* continue normally anyway, this isn't serious */
- +- ath10k_warn("failed to start htt stats workqueue: %d\n", ret);
- ++ ath10k_warn(ar, "failed to start htt stats workqueue: %d\n",
- ++ ret);
- +
- + if (ar->debug.fw_dbglog_mask) {
- +- ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
- ++ ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask,
- ++ ATH10K_DBGLOG_LEVEL_WARN);
- + if (ret)
- + /* not serious */
- +- ath10k_warn("failed to enable dbglog during start: %d",
- ++ ath10k_warn(ar, "failed to enable dbglog during start: %d",
- + ret);
- + }
- +
- +- return 0;
- ++ if (ar->debug.pktlog_filter) {
- ++ ret = ath10k_wmi_pdev_pktlog_enable(ar,
- ++ ar->debug.pktlog_filter);
- ++ if (ret)
- ++ /* not serious */
- ++ ath10k_warn(ar,
- ++ "failed to enable pktlog filter %x: %d\n",
- ++ ar->debug.pktlog_filter, ret);
- ++ } else {
- ++ ret = ath10k_wmi_pdev_pktlog_disable(ar);
- ++ if (ret)
- ++ /* not serious */
- ++ ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);
- ++ }
- ++
- ++ if (ar->debug.nf_cal_period) {
- ++ ret = ath10k_wmi_pdev_set_param(ar,
- ++ ar->wmi.pdev_param->cal_period,
- ++ ar->debug.nf_cal_period);
- ++ if (ret)
- ++ /* not serious */
- ++ ath10k_warn(ar, "cal period cfg failed from debug start: %d\n",
- ++ ret);
- ++ }
- ++
- ++ return ret;
- + }
- +
- + void ath10k_debug_stop(struct ath10k *ar)
- +@@ -757,6 +1841,11 @@ void ath10k_debug_stop(struct ath10k *ar
- + * warning from del_timer(). */
- + if (ar->debug.htt_stats_mask != 0)
- + cancel_delayed_work(&ar->debug.htt_stats_dwork);
- ++
- ++ ar->debug.htt_max_amsdu = 0;
- ++ ar->debug.htt_max_ampdu = 0;
- ++
- ++ ath10k_wmi_pdev_pktlog_disable(ar);
- + }
- +
- + static ssize_t ath10k_write_simulate_radar(struct file *file,
- +@@ -839,37 +1928,149 @@ static const struct file_operations fops
- + .llseek = default_llseek,
- + };
- +
- ++static ssize_t ath10k_write_pktlog_filter(struct file *file,
- ++ const char __user *ubuf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ u32 filter;
- ++ int ret;
- ++
- ++ if (kstrtouint_from_user(ubuf, count, 0, &filter))
- ++ return -EINVAL;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ if (ar->state != ATH10K_STATE_ON) {
- ++ ar->debug.pktlog_filter = filter;
- ++ ret = count;
- ++ goto out;
- ++ }
- ++
- ++ if (filter && (filter != ar->debug.pktlog_filter)) {
- ++ ret = ath10k_wmi_pdev_pktlog_enable(ar, filter);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n",
- ++ ar->debug.pktlog_filter, ret);
- ++ goto out;
- ++ }
- ++ } else {
- ++ ret = ath10k_wmi_pdev_pktlog_disable(ar);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);
- ++ goto out;
- ++ }
- ++ }
- ++
- ++ ar->debug.pktlog_filter = filter;
- ++ ret = count;
- ++
- ++out:
- ++ mutex_unlock(&ar->conf_mutex);
- ++ return ret;
- ++}
- ++
- ++static ssize_t ath10k_read_pktlog_filter(struct file *file, char __user *ubuf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ char buf[32];
- ++ struct ath10k *ar = file->private_data;
- ++ int len = 0;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
- ++ ar->debug.pktlog_filter);
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
- ++}
- ++
- ++static const struct file_operations fops_pktlog_filter = {
- ++ .read = ath10k_read_pktlog_filter,
- ++ .write = ath10k_write_pktlog_filter,
- ++ .open = simple_open
- ++};
- ++
- + int ath10k_debug_create(struct ath10k *ar)
- + {
- ++ ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data));
- ++ if (!ar->debug.fw_crash_data)
- ++ return -ENOMEM;
- ++
- ++ INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
- ++ INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
- ++ INIT_LIST_HEAD(&ar->debug.fw_stats.peers);
- ++
- ++ return 0;
- ++}
- ++
- ++void ath10k_debug_destroy(struct ath10k *ar)
- ++{
- ++ vfree(ar->debug.fw_crash_data);
- ++ ar->debug.fw_crash_data = NULL;
- ++
- ++ ath10k_debug_fw_stats_reset(ar);
- ++}
- ++
- ++int ath10k_debug_register(struct ath10k *ar)
- ++{
- + ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
- + ar->hw->wiphy->debugfsdir);
- ++ if (IS_ERR_OR_NULL(ar->debug.debugfs_phy)) {
- ++ if (IS_ERR(ar->debug.debugfs_phy))
- ++ return PTR_ERR(ar->debug.debugfs_phy);
- +
- +- if (!ar->debug.debugfs_phy)
- + return -ENOMEM;
- ++ }
- +
- + INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
- + ath10k_debug_htt_stats_dwork);
- +
- +- init_completion(&ar->debug.event_stats_compl);
- ++ init_completion(&ar->debug.fw_stats_complete);
- +
- + debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar,
- + &fops_fw_stats);
- +
- ++ debugfs_create_file("fw_reset_stats", S_IRUSR, ar->debug.debugfs_phy,
- ++ ar, &fops_fw_reset_stats);
- ++
- + debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
- + &fops_wmi_services);
- +
- + debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
- + ar, &fops_simulate_fw_crash);
- +
- ++ debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
- ++ ar, &fops_fw_crash_dump);
- ++
- ++ debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR,
- ++ ar->debug.debugfs_phy, ar, &fops_reg_addr);
- ++
- ++ debugfs_create_file("reg_value", S_IRUSR | S_IWUSR,
- ++ ar->debug.debugfs_phy, ar, &fops_reg_value);
- ++
- ++ debugfs_create_file("mem_value", S_IRUSR | S_IWUSR,
- ++ ar->debug.debugfs_phy, ar, &fops_mem_value);
- ++
- + debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
- + ar, &fops_chip_id);
- +
- + debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy,
- + ar, &fops_htt_stats_mask);
- +
- ++ debugfs_create_file("htt_max_amsdu_ampdu", S_IRUSR | S_IWUSR,
- ++ ar->debug.debugfs_phy, ar,
- ++ &fops_htt_max_amsdu_ampdu);
- ++
- + debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy,
- + ar, &fops_fw_dbglog);
- +
- ++ debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy,
- ++ ar, &fops_cal_data);
- ++
- ++ debugfs_create_file("nf_cal_period", S_IRUSR | S_IWUSR,
- ++ ar->debug.debugfs_phy, ar, &fops_nf_cal_period);
- ++
- + if (config_enabled(CPTCFG_ATH10K_DFS_CERTIFIED)) {
- + debugfs_create_file("dfs_simulate_radar", S_IWUSR,
- + ar->debug.debugfs_phy, ar,
- +@@ -884,10 +2085,13 @@ int ath10k_debug_create(struct ath10k *a
- + &fops_dfs_stats);
- + }
- +
- ++ debugfs_create_file("pktlog_filter", S_IRUGO | S_IWUSR,
- ++ ar->debug.debugfs_phy, ar, &fops_pktlog_filter);
- ++
- + return 0;
- + }
- +
- +-void ath10k_debug_destroy(struct ath10k *ar)
- ++void ath10k_debug_unregister(struct ath10k *ar)
- + {
- + cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
- + }
- +@@ -895,7 +2099,8 @@ void ath10k_debug_destroy(struct ath10k
- + #endif /* CPTCFG_ATH10K_DEBUGFS */
- +
- + #ifdef CPTCFG_ATH10K_DEBUG
- +-void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
- ++void ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask,
- ++ const char *fmt, ...)
- + {
- + struct va_format vaf;
- + va_list args;
- +@@ -906,27 +2111,43 @@ void ath10k_dbg(enum ath10k_debug_mask m
- + vaf.va = &args;
- +
- + if (ath10k_debug_mask & mask)
- +- ath10k_printk(KERN_DEBUG, "%pV", &vaf);
- ++ dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf);
- +
- +- trace_ath10k_log_dbg(mask, &vaf);
- ++ trace_ath10k_log_dbg(ar, mask, &vaf);
- +
- + va_end(args);
- + }
- + EXPORT_SYMBOL(ath10k_dbg);
- +
- +-void ath10k_dbg_dump(enum ath10k_debug_mask mask,
- ++void ath10k_dbg_dump(struct ath10k *ar,
- ++ enum ath10k_debug_mask mask,
- + const char *msg, const char *prefix,
- + const void *buf, size_t len)
- + {
- ++ char linebuf[256];
- ++ unsigned int linebuflen;
- ++ const void *ptr;
- ++
- + if (ath10k_debug_mask & mask) {
- + if (msg)
- +- ath10k_dbg(mask, "%s\n", msg);
- ++ ath10k_dbg(ar, mask, "%s\n", msg);
- +
- +- print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
- ++ for (ptr = buf; (ptr - buf) < len; ptr += 16) {
- ++ linebuflen = 0;
- ++ linebuflen += scnprintf(linebuf + linebuflen,
- ++ sizeof(linebuf) - linebuflen,
- ++ "%s%08x: ",
- ++ (prefix ? prefix : ""),
- ++ (unsigned int)(ptr - buf));
- ++ hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1,
- ++ linebuf + linebuflen,
- ++ sizeof(linebuf) - linebuflen, true);
- ++ dev_printk(KERN_DEBUG, ar->dev, "%s\n", linebuf);
- ++ }
- + }
- +
- + /* tracing code doesn't like null strings :/ */
- +- trace_ath10k_log_dbg_dump(msg ? msg : "", prefix ? prefix : "",
- ++ trace_ath10k_log_dbg_dump(ar, msg ? msg : "", prefix ? prefix : "",
- + buf, len);
- + }
- + EXPORT_SYMBOL(ath10k_dbg_dump);
- +--- a/drivers/net/wireless/ath/ath10k/debug.h
- ++++ b/drivers/net/wireless/ath/ath10k/debug.h
- +@@ -34,28 +34,55 @@ enum ath10k_debug_mask {
- + ATH10K_DBG_DATA = 0x00000200,
- + ATH10K_DBG_BMI = 0x00000400,
- + ATH10K_DBG_REGULATORY = 0x00000800,
- ++ ATH10K_DBG_TESTMODE = 0x00001000,
- ++ ATH10K_DBG_WMI_PRINT = 0x00002000,
- + ATH10K_DBG_ANY = 0xffffffff,
- + };
- +
- ++enum ath10k_pktlog_filter {
- ++ ATH10K_PKTLOG_RX = 0x000000001,
- ++ ATH10K_PKTLOG_TX = 0x000000002,
- ++ ATH10K_PKTLOG_RCFIND = 0x000000004,
- ++ ATH10K_PKTLOG_RCUPDATE = 0x000000008,
- ++ ATH10K_PKTLOG_DBG_PRINT = 0x000000010,
- ++ ATH10K_PKTLOG_ANY = 0x00000001f,
- ++};
- ++
- ++enum ath10k_dbg_aggr_mode {
- ++ ATH10K_DBG_AGGR_MODE_AUTO,
- ++ ATH10K_DBG_AGGR_MODE_MANUAL,
- ++ ATH10K_DBG_AGGR_MODE_MAX,
- ++};
- ++
- + extern unsigned int ath10k_debug_mask;
- +
- +-__printf(1, 2) int ath10k_info(const char *fmt, ...);
- +-__printf(1, 2) int ath10k_err(const char *fmt, ...);
- +-__printf(1, 2) int ath10k_warn(const char *fmt, ...);
- ++__printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...);
- ++__printf(2, 3) void ath10k_err(struct ath10k *ar, const char *fmt, ...);
- ++__printf(2, 3) void ath10k_warn(struct ath10k *ar, const char *fmt, ...);
- ++void ath10k_print_driver_info(struct ath10k *ar);
- +
- + #ifdef CPTCFG_ATH10K_DEBUGFS
- + int ath10k_debug_start(struct ath10k *ar);
- + void ath10k_debug_stop(struct ath10k *ar);
- + int ath10k_debug_create(struct ath10k *ar);
- + void ath10k_debug_destroy(struct ath10k *ar);
- +-void ath10k_debug_read_service_map(struct ath10k *ar,
- +- void *service_map,
- +- size_t map_size);
- +-void ath10k_debug_read_target_stats(struct ath10k *ar,
- +- struct wmi_stats_event *ev);
- ++int ath10k_debug_register(struct ath10k *ar);
- ++void ath10k_debug_unregister(struct ath10k *ar);
- ++void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb);
- ++struct ath10k_fw_crash_data *
- ++ath10k_debug_get_new_fw_crash_data(struct ath10k *ar);
- +
- ++void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
- + #define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
- +
- ++void ath10k_debug_get_et_strings(struct ieee80211_hw *hw,
- ++ struct ieee80211_vif *vif,
- ++ u32 sset, u8 *data);
- ++int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
- ++ struct ieee80211_vif *vif, int sset);
- ++void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
- ++ struct ieee80211_vif *vif,
- ++ struct ethtool_stats *stats, u64 *data);
- + #else
- + static inline int ath10k_debug_start(struct ath10k *ar)
- + {
- +@@ -75,36 +102,62 @@ static inline void ath10k_debug_destroy(
- + {
- + }
- +
- +-static inline void ath10k_debug_read_service_map(struct ath10k *ar,
- +- void *service_map,
- +- size_t map_size)
- ++static inline int ath10k_debug_register(struct ath10k *ar)
- ++{
- ++ return 0;
- ++}
- ++
- ++static inline void ath10k_debug_unregister(struct ath10k *ar)
- + {
- + }
- +
- +-static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
- +- struct wmi_stats_event *ev)
- ++static inline void ath10k_debug_fw_stats_process(struct ath10k *ar,
- ++ struct sk_buff *skb)
- + {
- + }
- +
- ++static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer,
- ++ int len)
- ++{
- ++}
- ++
- ++static inline struct ath10k_fw_crash_data *
- ++ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
- ++{
- ++ return NULL;
- ++}
- ++
- + #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
- +
- ++#define ath10k_debug_get_et_strings NULL
- ++#define ath10k_debug_get_et_sset_count NULL
- ++#define ath10k_debug_get_et_stats NULL
- ++
- + #endif /* CPTCFG_ATH10K_DEBUGFS */
- ++#ifdef CPTCFG_MAC80211_DEBUGFS
- ++void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- ++ struct ieee80211_sta *sta, struct dentry *dir);
- ++#endif /* CPTCFG_MAC80211_DEBUGFS */
- +
- + #ifdef CPTCFG_ATH10K_DEBUG
- +-__printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask,
- ++__printf(3, 4) void ath10k_dbg(struct ath10k *ar,
- ++ enum ath10k_debug_mask mask,
- + const char *fmt, ...);
- +-void ath10k_dbg_dump(enum ath10k_debug_mask mask,
- ++void ath10k_dbg_dump(struct ath10k *ar,
- ++ enum ath10k_debug_mask mask,
- + const char *msg, const char *prefix,
- + const void *buf, size_t len);
- + #else /* CPTCFG_ATH10K_DEBUG */
- +
- +-static inline int ath10k_dbg(enum ath10k_debug_mask dbg_mask,
- ++static inline int ath10k_dbg(struct ath10k *ar,
- ++ enum ath10k_debug_mask dbg_mask,
- + const char *fmt, ...)
- + {
- + return 0;
- + }
- +
- +-static inline void ath10k_dbg_dump(enum ath10k_debug_mask mask,
- ++static inline void ath10k_dbg_dump(struct ath10k *ar,
- ++ enum ath10k_debug_mask mask,
- + const char *msg, const char *prefix,
- + const void *buf, size_t len)
- + {
- +--- a/drivers/net/wireless/ath/ath10k/hif.h
- ++++ b/drivers/net/wireless/ath/ath10k/hif.h
- +@@ -20,6 +20,7 @@
- +
- + #include <linux/kernel.h>
- + #include "core.h"
- ++#include "debug.h"
- +
- + struct ath10k_hif_sg_item {
- + u16 transfer_id;
- +@@ -31,11 +32,9 @@ struct ath10k_hif_sg_item {
- +
- + struct ath10k_hif_cb {
- + int (*tx_completion)(struct ath10k *ar,
- +- struct sk_buff *wbuf,
- +- unsigned transfer_id);
- ++ struct sk_buff *wbuf);
- + int (*rx_completion)(struct ath10k *ar,
- +- struct sk_buff *wbuf,
- +- u8 pipe_id);
- ++ struct sk_buff *wbuf);
- + };
- +
- + struct ath10k_hif_ops {
- +@@ -43,6 +42,12 @@ struct ath10k_hif_ops {
- + int (*tx_sg)(struct ath10k *ar, u8 pipe_id,
- + struct ath10k_hif_sg_item *items, int n_items);
- +
- ++ /* read firmware memory through the diagnose interface */
- ++ int (*diag_read)(struct ath10k *ar, u32 address, void *buf,
- ++ size_t buf_len);
- ++
- ++ int (*diag_write)(struct ath10k *ar, u32 address, const void *data,
- ++ int nbytes);
- + /*
- + * API to handle HIF-specific BMI message exchanges, this API is
- + * synchronous and only allowed to be called from a context that
- +@@ -80,6 +85,10 @@ struct ath10k_hif_ops {
- +
- + u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id);
- +
- ++ u32 (*read32)(struct ath10k *ar, u32 address);
- ++
- ++ void (*write32)(struct ath10k *ar, u32 address, u32 value);
- ++
- + /* Power up the device and enter BMI transfer mode for FW download */
- + int (*power_up)(struct ath10k *ar);
- +
- +@@ -91,7 +100,6 @@ struct ath10k_hif_ops {
- + int (*resume)(struct ath10k *ar);
- + };
- +
- +-
- + static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
- + struct ath10k_hif_sg_item *items,
- + int n_items)
- +@@ -99,6 +107,21 @@ static inline int ath10k_hif_tx_sg(struc
- + return ar->hif.ops->tx_sg(ar, pipe_id, items, n_items);
- + }
- +
- ++static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
- ++ size_t buf_len)
- ++{
- ++ return ar->hif.ops->diag_read(ar, address, buf, buf_len);
- ++}
- ++
- ++static inline int ath10k_hif_diag_write(struct ath10k *ar, u32 address,
- ++ const void *data, int nbytes)
- ++{
- ++ if (!ar->hif.ops->diag_write)
- ++ return -EOPNOTSUPP;
- ++
- ++ return ar->hif.ops->diag_write(ar, address, data, nbytes);
- ++}
- ++
- + static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
- + void *request, u32 request_len,
- + void *response, u32 *response_len)
- +@@ -178,4 +201,25 @@ static inline int ath10k_hif_resume(stru
- + return ar->hif.ops->resume(ar);
- + }
- +
- ++static inline u32 ath10k_hif_read32(struct ath10k *ar, u32 address)
- ++{
- ++ if (!ar->hif.ops->read32) {
- ++ ath10k_warn(ar, "hif read32 not supported\n");
- ++ return 0xdeaddead;
- ++ }
- ++
- ++ return ar->hif.ops->read32(ar, address);
- ++}
- ++
- ++static inline void ath10k_hif_write32(struct ath10k *ar,
- ++ u32 address, u32 data)
- ++{
- ++ if (!ar->hif.ops->write32) {
- ++ ath10k_warn(ar, "hif write32 not supported\n");
- ++ return;
- ++ }
- ++
- ++ ar->hif.ops->write32(ar, address, data);
- ++}
- ++
- + #endif /* _HIF_H_ */
- +--- a/drivers/net/wireless/ath/ath10k/htc.c
- ++++ b/drivers/net/wireless/ath/ath10k/htc.c
- +@@ -45,10 +45,8 @@ static struct sk_buff *ath10k_htc_build_
- + struct ath10k_skb_cb *skb_cb;
- +
- + skb = dev_alloc_skb(ATH10K_HTC_CONTROL_BUFFER_SIZE);
- +- if (!skb) {
- +- ath10k_warn("Unable to allocate ctrl skb\n");
- ++ if (!skb)
- + return NULL;
- +- }
- +
- + skb_reserve(skb, 20); /* FIXME: why 20 bytes? */
- + WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
- +@@ -56,7 +54,7 @@ static struct sk_buff *ath10k_htc_build_
- + skb_cb = ATH10K_SKB_CB(skb);
- + memset(skb_cb, 0, sizeof(*skb_cb));
- +
- +- ath10k_dbg(ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb);
- ++ ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb);
- + return skb;
- + }
- +
- +@@ -72,13 +70,15 @@ static inline void ath10k_htc_restore_tx
- + static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
- + struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__,
- ++ struct ath10k *ar = ep->htc->ar;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__,
- + ep->eid, skb);
- +
- + ath10k_htc_restore_tx_skb(ep->htc, skb);
- +
- + if (!ep->ep_ops.ep_tx_complete) {
- +- ath10k_warn("no tx handler for eid %d\n", ep->eid);
- ++ ath10k_warn(ar, "no tx handler for eid %d\n", ep->eid);
- + dev_kfree_skb_any(skb);
- + return;
- + }
- +@@ -89,12 +89,14 @@ static void ath10k_htc_notify_tx_complet
- + /* assumes tx_lock is held */
- + static bool ath10k_htc_ep_need_credit_update(struct ath10k_htc_ep *ep)
- + {
- ++ struct ath10k *ar = ep->htc->ar;
- ++
- + if (!ep->tx_credit_flow_enabled)
- + return false;
- + if (ep->tx_credits >= ep->tx_credits_per_max_message)
- + return false;
- +
- +- ath10k_dbg(ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n",
- + ep->eid);
- + return true;
- + }
- +@@ -123,6 +125,7 @@ int ath10k_htc_send(struct ath10k_htc *h
- + enum ath10k_htc_ep_id eid,
- + struct sk_buff *skb)
- + {
- ++ struct ath10k *ar = htc->ar;
- + struct ath10k_htc_ep *ep = &htc->endpoint[eid];
- + struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
- + struct ath10k_hif_sg_item sg_item;
- +@@ -134,18 +137,10 @@ int ath10k_htc_send(struct ath10k_htc *h
- + return -ECOMM;
- +
- + if (eid >= ATH10K_HTC_EP_COUNT) {
- +- ath10k_warn("Invalid endpoint id: %d\n", eid);
- ++ ath10k_warn(ar, "Invalid endpoint id: %d\n", eid);
- + return -ENOENT;
- + }
- +
- +- /* FIXME: This looks ugly, can we fix it? */
- +- spin_lock_bh(&htc->tx_lock);
- +- if (htc->stopped) {
- +- spin_unlock_bh(&htc->tx_lock);
- +- return -ESHUTDOWN;
- +- }
- +- spin_unlock_bh(&htc->tx_lock);
- +-
- + skb_push(skb, sizeof(struct ath10k_htc_hdr));
- +
- + if (ep->tx_credit_flow_enabled) {
- +@@ -157,7 +152,7 @@ int ath10k_htc_send(struct ath10k_htc *h
- + goto err_pull;
- + }
- + ep->tx_credits -= credits;
- +- ath10k_dbg(ATH10K_DBG_HTC,
- ++ ath10k_dbg(ar, ATH10K_DBG_HTC,
- + "htc ep %d consumed %d credits (total %d)\n",
- + eid, credits, ep->tx_credits);
- + spin_unlock_bh(&htc->tx_lock);
- +@@ -165,6 +160,7 @@ int ath10k_htc_send(struct ath10k_htc *h
- +
- + ath10k_htc_prepare_tx_skb(ep, skb);
- +
- ++ skb_cb->eid = eid;
- + skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
- + ret = dma_mapping_error(dev, skb_cb->paddr);
- + if (ret)
- +@@ -188,7 +184,7 @@ err_credits:
- + if (ep->tx_credit_flow_enabled) {
- + spin_lock_bh(&htc->tx_lock);
- + ep->tx_credits += credits;
- +- ath10k_dbg(ATH10K_DBG_HTC,
- ++ ath10k_dbg(ar, ATH10K_DBG_HTC,
- + "htc ep %d reverted %d credits back (total %d)\n",
- + eid, credits, ep->tx_credits);
- + spin_unlock_bh(&htc->tx_lock);
- +@@ -202,15 +198,18 @@ err_pull:
- + }
- +
- + static int ath10k_htc_tx_completion_handler(struct ath10k *ar,
- +- struct sk_buff *skb,
- +- unsigned int eid)
- ++ struct sk_buff *skb)
- + {
- + struct ath10k_htc *htc = &ar->htc;
- +- struct ath10k_htc_ep *ep = &htc->endpoint[eid];
- ++ struct ath10k_skb_cb *skb_cb;
- ++ struct ath10k_htc_ep *ep;
- +
- + if (WARN_ON_ONCE(!skb))
- + return 0;
- +
- ++ skb_cb = ATH10K_SKB_CB(skb);
- ++ ep = &htc->endpoint[skb_cb->eid];
- ++
- + ath10k_htc_notify_tx_completion(ep, skb);
- + /* the skb now belongs to the completion handler */
- +
- +@@ -227,11 +226,12 @@ ath10k_htc_process_credit_report(struct
- + int len,
- + enum ath10k_htc_ep_id eid)
- + {
- ++ struct ath10k *ar = htc->ar;
- + struct ath10k_htc_ep *ep;
- + int i, n_reports;
- +
- + if (len % sizeof(*report))
- +- ath10k_warn("Uneven credit report len %d", len);
- ++ ath10k_warn(ar, "Uneven credit report len %d", len);
- +
- + n_reports = len / sizeof(*report);
- +
- +@@ -243,7 +243,7 @@ ath10k_htc_process_credit_report(struct
- + ep = &htc->endpoint[report->eid];
- + ep->tx_credits += report->credits;
- +
- +- ath10k_dbg(ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
- + report->eid, report->credits, ep->tx_credits);
- +
- + if (ep->ep_ops.ep_tx_credits) {
- +@@ -260,6 +260,7 @@ static int ath10k_htc_process_trailer(st
- + int length,
- + enum ath10k_htc_ep_id src_eid)
- + {
- ++ struct ath10k *ar = htc->ar;
- + int status = 0;
- + struct ath10k_htc_record *record;
- + u8 *orig_buffer;
- +@@ -279,7 +280,7 @@ static int ath10k_htc_process_trailer(st
- +
- + if (record->hdr.len > length) {
- + /* no room left in buffer for record */
- +- ath10k_warn("Invalid record length: %d\n",
- ++ ath10k_warn(ar, "Invalid record length: %d\n",
- + record->hdr.len);
- + status = -EINVAL;
- + break;
- +@@ -289,7 +290,7 @@ static int ath10k_htc_process_trailer(st
- + case ATH10K_HTC_RECORD_CREDITS:
- + len = sizeof(struct ath10k_htc_credit_report);
- + if (record->hdr.len < len) {
- +- ath10k_warn("Credit report too long\n");
- ++ ath10k_warn(ar, "Credit report too long\n");
- + status = -EINVAL;
- + break;
- + }
- +@@ -299,7 +300,7 @@ static int ath10k_htc_process_trailer(st
- + src_eid);
- + break;
- + default:
- +- ath10k_warn("Unhandled record: id:%d length:%d\n",
- ++ ath10k_warn(ar, "Unhandled record: id:%d length:%d\n",
- + record->hdr.id, record->hdr.len);
- + break;
- + }
- +@@ -313,15 +314,14 @@ static int ath10k_htc_process_trailer(st
- + }
- +
- + if (status)
- +- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc rx bad trailer", "",
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc rx bad trailer", "",
- + orig_buffer, orig_length);
- +
- + return status;
- + }
- +
- + static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
- +- struct sk_buff *skb,
- +- u8 pipe_id)
- ++ struct sk_buff *skb)
- + {
- + int status = 0;
- + struct ath10k_htc *htc = &ar->htc;
- +@@ -339,8 +339,8 @@ static int ath10k_htc_rx_completion_hand
- + eid = hdr->eid;
- +
- + if (eid >= ATH10K_HTC_EP_COUNT) {
- +- ath10k_warn("HTC Rx: invalid eid %d\n", eid);
- +- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad header", "",
- ++ ath10k_warn(ar, "HTC Rx: invalid eid %d\n", eid);
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad header", "",
- + hdr, sizeof(*hdr));
- + status = -EINVAL;
- + goto out;
- +@@ -360,19 +360,19 @@ static int ath10k_htc_rx_completion_hand
- + payload_len = __le16_to_cpu(hdr->len);
- +
- + if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) {
- +- ath10k_warn("HTC rx frame too long, len: %zu\n",
- ++ ath10k_warn(ar, "HTC rx frame too long, len: %zu\n",
- + payload_len + sizeof(*hdr));
- +- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len", "",
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "",
- + hdr, sizeof(*hdr));
- + status = -EINVAL;
- + goto out;
- + }
- +
- + if (skb->len < payload_len) {
- +- ath10k_dbg(ATH10K_DBG_HTC,
- ++ ath10k_dbg(ar, ATH10K_DBG_HTC,
- + "HTC Rx: insufficient length, got %d, expected %d\n",
- + skb->len, payload_len);
- +- ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len",
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len",
- + "", hdr, sizeof(*hdr));
- + status = -EINVAL;
- + goto out;
- +@@ -388,7 +388,7 @@ static int ath10k_htc_rx_completion_hand
- +
- + if ((trailer_len < min_len) ||
- + (trailer_len > payload_len)) {
- +- ath10k_warn("Invalid trailer length: %d\n",
- ++ ath10k_warn(ar, "Invalid trailer length: %d\n",
- + trailer_len);
- + status = -EPROTO;
- + goto out;
- +@@ -421,7 +421,7 @@ static int ath10k_htc_rx_completion_hand
- + * this is a fatal error, target should not be
- + * sending unsolicited messages on the ep 0
- + */
- +- ath10k_warn("HTC rx ctrl still processing\n");
- ++ ath10k_warn(ar, "HTC rx ctrl still processing\n");
- + status = -EINVAL;
- + complete(&htc->ctl_resp);
- + goto out;
- +@@ -442,7 +442,7 @@ static int ath10k_htc_rx_completion_hand
- + goto out;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n",
- + eid, skb);
- + ep->ep_ops.ep_rx_complete(ar, skb);
- +
- +@@ -459,7 +459,7 @@ static void ath10k_htc_control_rx_comple
- + {
- + /* This is unexpected. FW is not supposed to send regular rx on this
- + * endpoint. */
- +- ath10k_warn("unexpected htc rx\n");
- ++ ath10k_warn(ar, "unexpected htc rx\n");
- + kfree_skb(skb);
- + }
- +
- +@@ -546,7 +546,8 @@ static u8 ath10k_htc_get_credit_allocati
- +
- + int ath10k_htc_wait_target(struct ath10k_htc *htc)
- + {
- +- int status = 0;
- ++ struct ath10k *ar = htc->ar;
- ++ int i, status = 0;
- + struct ath10k_htc_svc_conn_req conn_req;
- + struct ath10k_htc_svc_conn_resp conn_resp;
- + struct ath10k_htc_msg *msg;
- +@@ -556,16 +557,32 @@ int ath10k_htc_wait_target(struct ath10k
- +
- + status = wait_for_completion_timeout(&htc->ctl_resp,
- + ATH10K_HTC_WAIT_TIMEOUT_HZ);
- +- if (status <= 0) {
- ++ if (status == 0) {
- ++ /* Workaround: In some cases the PCI HIF doesn't
- ++ * receive interrupt for the control response message
- ++ * even if the buffer was completed. It is suspected
- ++ * iomap writes unmasking PCI CE irqs aren't propagated
- ++ * properly in KVM PCI-passthrough sometimes.
- ++ */
- ++ ath10k_warn(ar, "failed to receive control response completion, polling..\n");
- ++
- ++ for (i = 0; i < CE_COUNT; i++)
- ++ ath10k_hif_send_complete_check(htc->ar, i, 1);
- ++
- ++ status = wait_for_completion_timeout(&htc->ctl_resp,
- ++ ATH10K_HTC_WAIT_TIMEOUT_HZ);
- ++
- + if (status == 0)
- + status = -ETIMEDOUT;
- ++ }
- +
- +- ath10k_err("ctl_resp never came in (%d)\n", status);
- ++ if (status < 0) {
- ++ ath10k_err(ar, "ctl_resp never came in (%d)\n", status);
- + return status;
- + }
- +
- + if (htc->control_resp_len < sizeof(msg->hdr) + sizeof(msg->ready)) {
- +- ath10k_err("Invalid HTC ready msg len:%d\n",
- ++ ath10k_err(ar, "Invalid HTC ready msg len:%d\n",
- + htc->control_resp_len);
- + return -ECOMM;
- + }
- +@@ -576,21 +593,21 @@ int ath10k_htc_wait_target(struct ath10k
- + credit_size = __le16_to_cpu(msg->ready.credit_size);
- +
- + if (message_id != ATH10K_HTC_MSG_READY_ID) {
- +- ath10k_err("Invalid HTC ready msg: 0x%x\n", message_id);
- ++ ath10k_err(ar, "Invalid HTC ready msg: 0x%x\n", message_id);
- + return -ECOMM;
- + }
- +
- + htc->total_transmit_credits = credit_count;
- + htc->target_credit_size = credit_size;
- +
- +- ath10k_dbg(ATH10K_DBG_HTC,
- ++ ath10k_dbg(ar, ATH10K_DBG_HTC,
- + "Target ready! transmit resources: %d size:%d\n",
- + htc->total_transmit_credits,
- + htc->target_credit_size);
- +
- + if ((htc->total_transmit_credits == 0) ||
- + (htc->target_credit_size == 0)) {
- +- ath10k_err("Invalid credit size received\n");
- ++ ath10k_err(ar, "Invalid credit size received\n");
- + return -ECOMM;
- + }
- +
- +@@ -607,7 +624,8 @@ int ath10k_htc_wait_target(struct ath10k
- + /* connect fake service */
- + status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp);
- + if (status) {
- +- ath10k_err("could not connect to htc service (%d)\n", status);
- ++ ath10k_err(ar, "could not connect to htc service (%d)\n",
- ++ status);
- + return status;
- + }
- +
- +@@ -618,6 +636,7 @@ int ath10k_htc_connect_service(struct at
- + struct ath10k_htc_svc_conn_req *conn_req,
- + struct ath10k_htc_svc_conn_resp *conn_resp)
- + {
- ++ struct ath10k *ar = htc->ar;
- + struct ath10k_htc_msg *msg;
- + struct ath10k_htc_conn_svc *req_msg;
- + struct ath10k_htc_conn_svc_response resp_msg_dummy;
- +@@ -643,13 +662,13 @@ int ath10k_htc_connect_service(struct at
- + tx_alloc = ath10k_htc_get_credit_allocation(htc,
- + conn_req->service_id);
- + if (!tx_alloc)
- +- ath10k_dbg(ATH10K_DBG_BOOT,
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- + "boot htc service %s does not allocate target credits\n",
- + htc_service_name(conn_req->service_id));
- +
- + skb = ath10k_htc_build_tx_ctrl_skb(htc->ar);
- + if (!skb) {
- +- ath10k_err("Failed to allocate HTC packet\n");
- ++ ath10k_err(ar, "Failed to allocate HTC packet\n");
- + return -ENOMEM;
- + }
- +
- +@@ -684,11 +703,9 @@ int ath10k_htc_connect_service(struct at
- + /* wait for response */
- + status = wait_for_completion_timeout(&htc->ctl_resp,
- + ATH10K_HTC_CONN_SVC_TIMEOUT_HZ);
- +- if (status <= 0) {
- +- if (status == 0)
- +- status = -ETIMEDOUT;
- +- ath10k_err("Service connect timeout: %d\n", status);
- +- return status;
- ++ if (status == 0) {
- ++ ath10k_err(ar, "Service connect timeout: %d\n", status);
- ++ return -ETIMEDOUT;
- + }
- +
- + /* we controlled the buffer creation, it's aligned */
- +@@ -700,11 +717,11 @@ int ath10k_htc_connect_service(struct at
- + if ((message_id != ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID) ||
- + (htc->control_resp_len < sizeof(msg->hdr) +
- + sizeof(msg->connect_service_response))) {
- +- ath10k_err("Invalid resp message ID 0x%x", message_id);
- ++ ath10k_err(ar, "Invalid resp message ID 0x%x", message_id);
- + return -EPROTO;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_HTC,
- ++ ath10k_dbg(ar, ATH10K_DBG_HTC,
- + "HTC Service %s connect response: status: 0x%x, assigned ep: 0x%x\n",
- + htc_service_name(service_id),
- + resp_msg->status, resp_msg->eid);
- +@@ -713,7 +730,7 @@ int ath10k_htc_connect_service(struct at
- +
- + /* check response status */
- + if (resp_msg->status != ATH10K_HTC_CONN_SVC_STATUS_SUCCESS) {
- +- ath10k_err("HTC Service %s connect request failed: 0x%x)\n",
- ++ ath10k_err(ar, "HTC Service %s connect request failed: 0x%x)\n",
- + htc_service_name(service_id),
- + resp_msg->status);
- + return -EPROTO;
- +@@ -764,18 +781,18 @@ setup:
- + if (status)
- + return status;
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT,
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- + "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n",
- + htc_service_name(ep->service_id), ep->ul_pipe_id,
- + ep->dl_pipe_id, ep->eid);
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT,
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- + "boot htc ep %d ul polled %d dl polled %d\n",
- + ep->eid, ep->ul_is_polled, ep->dl_is_polled);
- +
- + if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) {
- + ep->tx_credit_flow_enabled = false;
- +- ath10k_dbg(ATH10K_DBG_BOOT,
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT,
- + "boot htc service '%s' eid %d TX flow control disabled\n",
- + htc_service_name(ep->service_id), assigned_eid);
- + }
- +@@ -783,27 +800,26 @@ setup:
- + return status;
- + }
- +
- +-struct sk_buff *ath10k_htc_alloc_skb(int size)
- ++struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size)
- + {
- + struct sk_buff *skb;
- +
- + skb = dev_alloc_skb(size + sizeof(struct ath10k_htc_hdr));
- +- if (!skb) {
- +- ath10k_warn("could not allocate HTC tx skb\n");
- ++ if (!skb)
- + return NULL;
- +- }
- +
- + skb_reserve(skb, sizeof(struct ath10k_htc_hdr));
- +
- + /* FW/HTC requires 4-byte aligned streams */
- + if (!IS_ALIGNED((unsigned long)skb->data, 4))
- +- ath10k_warn("Unaligned HTC tx skb\n");
- ++ ath10k_warn(ar, "Unaligned HTC tx skb\n");
- +
- + return skb;
- + }
- +
- + int ath10k_htc_start(struct ath10k_htc *htc)
- + {
- ++ struct ath10k *ar = htc->ar;
- + struct sk_buff *skb;
- + int status = 0;
- + struct ath10k_htc_msg *msg;
- +@@ -819,7 +835,7 @@ int ath10k_htc_start(struct ath10k_htc *
- + msg->hdr.message_id =
- + __cpu_to_le16(ATH10K_HTC_MSG_SETUP_COMPLETE_EX_ID);
- +
- +- ath10k_dbg(ATH10K_DBG_HTC, "HTC is using TX credit flow control\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC is using TX credit flow control\n");
- +
- + status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb);
- + if (status) {
- +@@ -830,19 +846,6 @@ int ath10k_htc_start(struct ath10k_htc *
- + return 0;
- + }
- +
- +-/*
- +- * stop HTC communications, i.e. stop interrupt reception, and flush all
- +- * queued buffers
- +- */
- +-void ath10k_htc_stop(struct ath10k_htc *htc)
- +-{
- +- spin_lock_bh(&htc->tx_lock);
- +- htc->stopped = true;
- +- spin_unlock_bh(&htc->tx_lock);
- +-
- +- ath10k_hif_stop(htc->ar);
- +-}
- +-
- + /* registered target arrival callback from the HIF layer */
- + int ath10k_htc_init(struct ath10k *ar)
- + {
- +@@ -852,7 +855,6 @@ int ath10k_htc_init(struct ath10k *ar)
- +
- + spin_lock_init(&htc->tx_lock);
- +
- +- htc->stopped = false;
- + ath10k_htc_reset_endpoint_states(htc);
- +
- + /* setup HIF layer callbacks */
- +--- a/drivers/net/wireless/ath/ath10k/htc.h
- ++++ b/drivers/net/wireless/ath/ath10k/htc.h
- +@@ -214,7 +214,6 @@ struct ath10k_htc_frame {
- + struct ath10k_htc_record trailer[0];
- + } __packed __aligned(4);
- +
- +-
- + /*******************/
- + /* Host-side stuff */
- + /*******************/
- +@@ -332,7 +331,7 @@ struct ath10k_htc {
- + struct ath10k *ar;
- + struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT];
- +
- +- /* protects endpoint and stopped fields */
- ++ /* protects endpoints */
- + spinlock_t tx_lock;
- +
- + struct ath10k_htc_ops htc_ops;
- +@@ -345,8 +344,6 @@ struct ath10k_htc {
- + int total_transmit_credits;
- + struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT];
- + int target_credit_size;
- +-
- +- bool stopped;
- + };
- +
- + int ath10k_htc_init(struct ath10k *ar);
- +@@ -357,7 +354,6 @@ int ath10k_htc_connect_service(struct at
- + struct ath10k_htc_svc_conn_resp *conn_resp);
- + int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
- + struct sk_buff *packet);
- +-void ath10k_htc_stop(struct ath10k_htc *htc);
- +-struct sk_buff *ath10k_htc_alloc_skb(int size);
- ++struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
- +
- + #endif
- +--- a/drivers/net/wireless/ath/ath10k/htt.c
- ++++ b/drivers/net/wireless/ath/ath10k/htt.c
- +@@ -22,7 +22,7 @@
- + #include "core.h"
- + #include "debug.h"
- +
- +-static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
- ++int ath10k_htt_connect(struct ath10k_htt *htt)
- + {
- + struct ath10k_htc_svc_conn_req conn_req;
- + struct ath10k_htc_svc_conn_resp conn_resp;
- +@@ -48,37 +48,11 @@ static int ath10k_htt_htc_attach(struct
- + return 0;
- + }
- +
- +-int ath10k_htt_attach(struct ath10k *ar)
- ++int ath10k_htt_init(struct ath10k *ar)
- + {
- + struct ath10k_htt *htt = &ar->htt;
- +- int ret;
- +
- + htt->ar = ar;
- +- htt->max_throughput_mbps = 800;
- +-
- +- /*
- +- * Connect to HTC service.
- +- * This has to be done before calling ath10k_htt_rx_attach,
- +- * since ath10k_htt_rx_attach involves sending a rx ring configure
- +- * message to the target.
- +- */
- +- ret = ath10k_htt_htc_attach(htt);
- +- if (ret) {
- +- ath10k_err("could not attach htt htc (%d)\n", ret);
- +- goto err_htc_attach;
- +- }
- +-
- +- ret = ath10k_htt_tx_attach(htt);
- +- if (ret) {
- +- ath10k_err("could not attach htt tx (%d)\n", ret);
- +- goto err_htc_attach;
- +- }
- +-
- +- ret = ath10k_htt_rx_attach(htt);
- +- if (ret) {
- +- ath10k_err("could not attach htt rx (%d)\n", ret);
- +- goto err_rx_attach;
- +- }
- +
- + /*
- + * Prefetch enough data to satisfy target
- +@@ -93,23 +67,20 @@ int ath10k_htt_attach(struct ath10k *ar)
- + 2; /* ip4 dscp or ip6 priority */
- +
- + return 0;
- +-
- +-err_rx_attach:
- +- ath10k_htt_tx_detach(htt);
- +-err_htc_attach:
- +- return ret;
- + }
- +
- + #define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ)
- +
- + static int ath10k_htt_verify_version(struct ath10k_htt *htt)
- + {
- +- ath10k_dbg(ATH10K_DBG_BOOT, "htt target version %d.%d\n",
- ++ struct ath10k *ar = htt->ar;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt target version %d.%d\n",
- + htt->target_version_major, htt->target_version_minor);
- +
- + if (htt->target_version_major != 2 &&
- + htt->target_version_major != 3) {
- +- ath10k_err("unsupported htt major version %d. supported versions are 2 and 3\n",
- ++ ath10k_err(ar, "unsupported htt major version %d. supported versions are 2 and 3\n",
- + htt->target_version_major);
- + return -ENOTSUPP;
- + }
- +@@ -117,8 +88,9 @@ static int ath10k_htt_verify_version(str
- + return 0;
- + }
- +
- +-int ath10k_htt_attach_target(struct ath10k_htt *htt)
- ++int ath10k_htt_setup(struct ath10k_htt *htt)
- + {
- ++ struct ath10k *ar = htt->ar;
- + int status;
- +
- + init_completion(&htt->target_version_received);
- +@@ -128,9 +100,9 @@ int ath10k_htt_attach_target(struct ath1
- + return status;
- +
- + status = wait_for_completion_timeout(&htt->target_version_received,
- +- HTT_TARGET_VERSION_TIMEOUT_HZ);
- +- if (status <= 0) {
- +- ath10k_warn("htt version request timed out\n");
- ++ HTT_TARGET_VERSION_TIMEOUT_HZ);
- ++ if (status == 0) {
- ++ ath10k_warn(ar, "htt version request timed out\n");
- + return -ETIMEDOUT;
- + }
- +
- +@@ -140,9 +112,3 @@ int ath10k_htt_attach_target(struct ath1
- +
- + return ath10k_htt_send_rx_ring_cfg_ll(htt);
- + }
- +-
- +-void ath10k_htt_detach(struct ath10k_htt *htt)
- +-{
- +- ath10k_htt_rx_detach(htt);
- +- ath10k_htt_tx_detach(htt);
- +-}
- +--- a/drivers/net/wireless/ath/ath10k/htt.h
- ++++ b/drivers/net/wireless/ath/ath10k/htt.h
- +@@ -21,6 +21,7 @@
- + #include <linux/bug.h>
- + #include <linux/interrupt.h>
- + #include <linux/dmapool.h>
- ++#include <linux/hashtable.h>
- + #include <net/mac80211.h>
- +
- + #include "htc.h"
- +@@ -126,6 +127,7 @@ enum htt_data_tx_ext_tid {
- + * (HL hosts manage queues on the host )
- + * more_in_batch: only for HL hosts. indicates if more packets are
- + * pending. this allows target to wait and aggregate
- ++ * freq: 0 means home channel of given vdev. intended for offchannel
- + */
- + struct htt_data_tx_desc {
- + u8 flags0; /* %HTT_DATA_TX_DESC_FLAGS0_ */
- +@@ -133,7 +135,8 @@ struct htt_data_tx_desc {
- + __le16 len;
- + __le16 id;
- + __le32 frags_paddr;
- +- __le32 peerid;
- ++ __le16 peerid;
- ++ __le16 freq;
- + u8 prefetch[0]; /* start of frame, for FW classification engine */
- + } __packed;
- +
- +@@ -156,6 +159,9 @@ enum htt_rx_ring_flags {
- + HTT_RX_RING_FLAGS_PHY_DATA_RX = 1 << 15
- + };
- +
- ++#define HTT_RX_RING_SIZE_MIN 128
- ++#define HTT_RX_RING_SIZE_MAX 2048
- ++
- + struct htt_rx_ring_setup_ring {
- + __le32 fw_idx_shadow_reg_paddr;
- + __le32 rx_ring_base_paddr;
- +@@ -240,16 +246,10 @@ struct htt_oob_sync_req {
- + __le16 rsvd0;
- + } __packed;
- +
- +-#define HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_MASK 0x1F
- +-#define HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_LSB 0
- +-
- + struct htt_aggr_conf {
- + u8 max_num_ampdu_subframes;
- +- union {
- +- /* dont use bitfields; undefined behaviour */
- +- u8 flags; /* see %HTT_AGGR_CONF_MAX_NUM_AMSDU_SUBFRAMES_ */
- +- u8 max_num_amsdu_subframes:5;
- +- } __packed;
- ++ /* amsdu_subframes is limited by 0x1F mask */
- ++ u8 max_num_amsdu_subframes;
- + } __packed;
- +
- + #define HTT_MGMT_FRM_HDR_DOWNLOAD_LEN 32
- +@@ -271,7 +271,6 @@ enum htt_mgmt_tx_status {
- +
- + /*=== target -> host messages ===============================================*/
- +
- +-
- + enum htt_t2h_msg_type {
- + HTT_T2H_MSG_TYPE_VERSION_CONF = 0x0,
- + HTT_T2H_MSG_TYPE_RX_IND = 0x1,
- +@@ -288,7 +287,19 @@ enum htt_t2h_msg_type {
- + HTT_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc,
- + HTT_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
- + HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION = 0xe,
- ++ HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf,
- ++ HTT_T2H_MSG_TYPE_RX_PN_IND = 0x10,
- ++ HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11,
- ++ HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND = 0x12,
- ++ /* 0x13 reservd */
- ++ HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE = 0x14,
- ++
- ++ /* FIXME: Do not depend on this event id. Numbering of this event id is
- ++ * broken across different firmware revisions and HTT version fails to
- ++ * indicate this.
- ++ */
- + HTT_T2H_MSG_TYPE_TEST,
- ++
- + /* keep this last */
- + HTT_T2H_NUM_MSGS
- + };
- +@@ -657,6 +668,53 @@ struct htt_rx_fragment_indication {
- + #define HTT_RX_FRAG_IND_INFO1_FLUSH_SEQ_NUM_END_MASK 0x00000FC0
- + #define HTT_RX_FRAG_IND_INFO1_FLUSH_SEQ_NUM_END_LSB 6
- +
- ++struct htt_rx_pn_ind {
- ++ __le16 peer_id;
- ++ u8 tid;
- ++ u8 seqno_start;
- ++ u8 seqno_end;
- ++ u8 pn_ie_count;
- ++ u8 reserved;
- ++ u8 pn_ies[0];
- ++} __packed;
- ++
- ++struct htt_rx_offload_msdu {
- ++ __le16 msdu_len;
- ++ __le16 peer_id;
- ++ u8 vdev_id;
- ++ u8 tid;
- ++ u8 fw_desc;
- ++ u8 payload[0];
- ++} __packed;
- ++
- ++struct htt_rx_offload_ind {
- ++ u8 reserved;
- ++ __le16 msdu_count;
- ++} __packed;
- ++
- ++struct htt_rx_in_ord_msdu_desc {
- ++ __le32 msdu_paddr;
- ++ __le16 msdu_len;
- ++ u8 fw_desc;
- ++ u8 reserved;
- ++} __packed;
- ++
- ++struct htt_rx_in_ord_ind {
- ++ u8 info;
- ++ __le16 peer_id;
- ++ u8 vdev_id;
- ++ u8 reserved;
- ++ __le16 msdu_count;
- ++ struct htt_rx_in_ord_msdu_desc msdu_descs[0];
- ++} __packed;
- ++
- ++#define HTT_RX_IN_ORD_IND_INFO_TID_MASK 0x0000001f
- ++#define HTT_RX_IN_ORD_IND_INFO_TID_LSB 0
- ++#define HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK 0x00000020
- ++#define HTT_RX_IN_ORD_IND_INFO_OFFLOAD_LSB 5
- ++#define HTT_RX_IN_ORD_IND_INFO_FRAG_MASK 0x00000040
- ++#define HTT_RX_IN_ORD_IND_INFO_FRAG_LSB 6
- ++
- + /*
- + * target -> host test message definition
- + *
- +@@ -732,7 +790,7 @@ static inline u8 *htt_rx_test_get_chars(
- + */
- + struct htt_pktlog_msg {
- + u8 pad[3];
- +- __le32 payload[1 /* or more */];
- ++ u8 payload[0];
- + } __packed;
- +
- + struct htt_dbg_stats_rx_reorder_stats {
- +@@ -1038,6 +1096,7 @@ static inline struct htt_stats_conf_item
- + {
- + return (void *)item + sizeof(*item) + roundup(item->length, 4);
- + }
- ++
- + /*
- + * host -> target FRAG DESCRIPTOR/MSDU_EXT DESC bank
- + *
- +@@ -1151,10 +1210,12 @@ struct htt_resp {
- + struct htt_rx_test rx_test;
- + struct htt_pktlog_msg pktlog_msg;
- + struct htt_stats_conf stats_conf;
- ++ struct htt_rx_pn_ind rx_pn_ind;
- ++ struct htt_rx_offload_ind rx_offload_ind;
- ++ struct htt_rx_in_ord_ind rx_in_ord_ind;
- + };
- + } __packed;
- +
- +-
- + /*** host side structures follow ***/
- +
- + struct htt_tx_done {
- +@@ -1184,7 +1245,6 @@ struct ath10k_htt {
- + struct ath10k *ar;
- + enum ath10k_htc_ep_id eid;
- +
- +- int max_throughput_mbps;
- + u8 target_version_major;
- + u8 target_version_minor;
- + struct completion target_version_received;
- +@@ -1200,6 +1260,20 @@ struct ath10k_htt {
- + * filled.
- + */
- + struct sk_buff **netbufs_ring;
- ++
- ++ /* This is used only with firmware supporting IN_ORD_IND.
- ++ *
- ++ * With Full Rx Reorder the HTT Rx Ring is more of a temporary
- ++ * buffer ring from which buffer addresses are copied by the
- ++ * firmware to MAC Rx ring. Firmware then delivers IN_ORD_IND
- ++ * pointing to specific (re-ordered) buffers.
- ++ *
- ++ * FIXME: With kernel generic hashing functions there's a lot
- ++ * of hash collisions for sk_buffs.
- ++ */
- ++ bool in_ord_rx;
- ++ DECLARE_HASHTABLE(skb_table, 4);
- ++
- + /*
- + * Ring of buffer addresses -
- + * This ring holds the "physical" device address of the
- +@@ -1254,12 +1328,11 @@ struct ath10k_htt {
- +
- + unsigned int prefetch_len;
- +
- +- /* Protects access to %pending_tx, %used_msdu_ids */
- ++ /* Protects access to pending_tx, num_pending_tx */
- + spinlock_t tx_lock;
- + int max_num_pending_tx;
- + int num_pending_tx;
- +- struct sk_buff **pending_tx;
- +- unsigned long *used_msdu_ids; /* bitmap */
- ++ struct idr pending_tx;
- + wait_queue_head_t empty_tx_wq;
- + struct dma_pool *tx_pool;
- +
- +@@ -1273,6 +1346,7 @@ struct ath10k_htt {
- + struct tasklet_struct txrx_compl_task;
- + struct sk_buff_head tx_compl_q;
- + struct sk_buff_head rx_compl_q;
- ++ struct sk_buff_head rx_in_ord_compl_q;
- +
- + /* rx_status template */
- + struct ieee80211_rx_status rx_status;
- +@@ -1328,22 +1402,28 @@ struct htt_rx_desc {
- + #define HTT_LOG2_MAX_CACHE_LINE_SIZE 7 /* 2^7 = 128 */
- + #define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1)
- +
- +-int ath10k_htt_attach(struct ath10k *ar);
- +-int ath10k_htt_attach_target(struct ath10k_htt *htt);
- +-void ath10k_htt_detach(struct ath10k_htt *htt);
- +-
- +-int ath10k_htt_tx_attach(struct ath10k_htt *htt);
- +-void ath10k_htt_tx_detach(struct ath10k_htt *htt);
- +-int ath10k_htt_rx_attach(struct ath10k_htt *htt);
- +-void ath10k_htt_rx_detach(struct ath10k_htt *htt);
- ++int ath10k_htt_connect(struct ath10k_htt *htt);
- ++int ath10k_htt_init(struct ath10k *ar);
- ++int ath10k_htt_setup(struct ath10k_htt *htt);
- ++
- ++int ath10k_htt_tx_alloc(struct ath10k_htt *htt);
- ++void ath10k_htt_tx_free(struct ath10k_htt *htt);
- ++
- ++int ath10k_htt_rx_alloc(struct ath10k_htt *htt);
- ++int ath10k_htt_rx_ring_refill(struct ath10k *ar);
- ++void ath10k_htt_rx_free(struct ath10k_htt *htt);
- ++
- + void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb);
- + void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
- + int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt);
- + int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie);
- + int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt);
- ++int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
- ++ u8 max_subfrms_ampdu,
- ++ u8 max_subfrms_amsdu);
- +
- + void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt);
- +-int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt);
- ++int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb);
- + void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);
- + int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *);
- + int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *);
- +--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
- ++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
- +@@ -21,118 +21,84 @@
- + #include "txrx.h"
- + #include "debug.h"
- + #include "trace.h"
- ++#include "mac.h"
- +
- + #include <linux/log2.h>
- +
- +-/* slightly larger than one large A-MPDU */
- +-#define HTT_RX_RING_SIZE_MIN 128
- +-
- +-/* roughly 20 ms @ 1 Gbps of 1500B MSDUs */
- +-#define HTT_RX_RING_SIZE_MAX 2048
- +-
- +-#define HTT_RX_AVG_FRM_BYTES 1000
- +-
- +-/* ms, very conservative */
- +-#define HTT_RX_HOST_LATENCY_MAX_MS 20
- +-
- +-/* ms, conservative */
- +-#define HTT_RX_HOST_LATENCY_WORST_LIKELY_MS 10
- ++#define HTT_RX_RING_SIZE HTT_RX_RING_SIZE_MAX
- ++#define HTT_RX_RING_FILL_LEVEL (((HTT_RX_RING_SIZE) / 2) - 1)
- +
- + /* when under memory pressure rx ring refill may fail and needs a retry */
- + #define HTT_RX_RING_REFILL_RETRY_MS 50
- +
- +-
- + static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb);
- + static void ath10k_htt_txrx_compl_task(unsigned long ptr);
- +
- +-static int ath10k_htt_rx_ring_size(struct ath10k_htt *htt)
- +-{
- +- int size;
- +-
- +- /*
- +- * It is expected that the host CPU will typically be able to
- +- * service the rx indication from one A-MPDU before the rx
- +- * indication from the subsequent A-MPDU happens, roughly 1-2 ms
- +- * later. However, the rx ring should be sized very conservatively,
- +- * to accomodate the worst reasonable delay before the host CPU
- +- * services a rx indication interrupt.
- +- *
- +- * The rx ring need not be kept full of empty buffers. In theory,
- +- * the htt host SW can dynamically track the low-water mark in the
- +- * rx ring, and dynamically adjust the level to which the rx ring
- +- * is filled with empty buffers, to dynamically meet the desired
- +- * low-water mark.
- +- *
- +- * In contrast, it's difficult to resize the rx ring itself, once
- +- * it's in use. Thus, the ring itself should be sized very
- +- * conservatively, while the degree to which the ring is filled
- +- * with empty buffers should be sized moderately conservatively.
- +- */
- +-
- +- /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */
- +- size =
- +- htt->max_throughput_mbps +
- +- 1000 /
- +- (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_MAX_MS;
- +-
- +- if (size < HTT_RX_RING_SIZE_MIN)
- +- size = HTT_RX_RING_SIZE_MIN;
- +-
- +- if (size > HTT_RX_RING_SIZE_MAX)
- +- size = HTT_RX_RING_SIZE_MAX;
- +-
- +- size = roundup_pow_of_two(size);
- +-
- +- return size;
- +-}
- +-
- +-static int ath10k_htt_rx_ring_fill_level(struct ath10k_htt *htt)
- ++static struct sk_buff *
- ++ath10k_htt_rx_find_skb_paddr(struct ath10k *ar, u32 paddr)
- + {
- +- int size;
- ++ struct ath10k_skb_rxcb *rxcb;
- +
- +- /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */
- +- size =
- +- htt->max_throughput_mbps *
- +- 1000 /
- +- (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_WORST_LIKELY_MS;
- +-
- +- /*
- +- * Make sure the fill level is at least 1 less than the ring size.
- +- * Leaving 1 element empty allows the SW to easily distinguish
- +- * between a full ring vs. an empty ring.
- +- */
- +- if (size >= htt->rx_ring.size)
- +- size = htt->rx_ring.size - 1;
- ++ hash_for_each_possible(ar->htt.rx_ring.skb_table, rxcb, hlist, paddr)
- ++ if (rxcb->paddr == paddr)
- ++ return ATH10K_RXCB_SKB(rxcb);
- +
- +- return size;
- ++ WARN_ON_ONCE(1);
- ++ return NULL;
- + }
- +
- + static void ath10k_htt_rx_ring_free(struct ath10k_htt *htt)
- + {
- + struct sk_buff *skb;
- +- struct ath10k_skb_cb *cb;
- ++ struct ath10k_skb_rxcb *rxcb;
- ++ struct hlist_node *n;
- + int i;
- +
- +- for (i = 0; i < htt->rx_ring.fill_cnt; i++) {
- +- skb = htt->rx_ring.netbufs_ring[i];
- +- cb = ATH10K_SKB_CB(skb);
- +- dma_unmap_single(htt->ar->dev, cb->paddr,
- +- skb->len + skb_tailroom(skb),
- +- DMA_FROM_DEVICE);
- +- dev_kfree_skb_any(skb);
- ++ if (htt->rx_ring.in_ord_rx) {
- ++ hash_for_each_safe(htt->rx_ring.skb_table, i, n, rxcb, hlist) {
- ++ skb = ATH10K_RXCB_SKB(rxcb);
- ++ dma_unmap_single(htt->ar->dev, rxcb->paddr,
- ++ skb->len + skb_tailroom(skb),
- ++ DMA_FROM_DEVICE);
- ++ hash_del(&rxcb->hlist);
- ++ dev_kfree_skb_any(skb);
- ++ }
- ++ } else {
- ++ for (i = 0; i < htt->rx_ring.size; i++) {
- ++ skb = htt->rx_ring.netbufs_ring[i];
- ++ if (!skb)
- ++ continue;
- ++
- ++ rxcb = ATH10K_SKB_RXCB(skb);
- ++ dma_unmap_single(htt->ar->dev, rxcb->paddr,
- ++ skb->len + skb_tailroom(skb),
- ++ DMA_FROM_DEVICE);
- ++ dev_kfree_skb_any(skb);
- ++ }
- + }
- +
- + htt->rx_ring.fill_cnt = 0;
- ++ hash_init(htt->rx_ring.skb_table);
- ++ memset(htt->rx_ring.netbufs_ring, 0,
- ++ htt->rx_ring.size * sizeof(htt->rx_ring.netbufs_ring[0]));
- + }
- +
- + static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num)
- + {
- + struct htt_rx_desc *rx_desc;
- ++ struct ath10k_skb_rxcb *rxcb;
- + struct sk_buff *skb;
- + dma_addr_t paddr;
- + int ret = 0, idx;
- +
- +- idx = __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr));
- ++ /* The Full Rx Reorder firmware has no way of telling the host
- ++ * implicitly when it copied HTT Rx Ring buffers to MAC Rx Ring.
- ++ * To keep things simple make sure ring is always half empty. This
- ++ * guarantees there'll be no replenishment overruns possible.
- ++ */
- ++ BUILD_BUG_ON(HTT_RX_RING_FILL_LEVEL >= HTT_RX_RING_SIZE / 2);
- ++
- ++ idx = __le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr);
- + while (num > 0) {
- + skb = dev_alloc_skb(HTT_RX_BUF_SIZE + HTT_RX_DESC_ALIGN);
- + if (!skb) {
- +@@ -159,18 +125,30 @@ static int __ath10k_htt_rx_ring_fill_n(s
- + goto fail;
- + }
- +
- +- ATH10K_SKB_CB(skb)->paddr = paddr;
- ++ rxcb = ATH10K_SKB_RXCB(skb);
- ++ rxcb->paddr = paddr;
- + htt->rx_ring.netbufs_ring[idx] = skb;
- + htt->rx_ring.paddrs_ring[idx] = __cpu_to_le32(paddr);
- + htt->rx_ring.fill_cnt++;
- +
- ++ if (htt->rx_ring.in_ord_rx) {
- ++ hash_add(htt->rx_ring.skb_table,
- ++ &ATH10K_SKB_RXCB(skb)->hlist,
- ++ (u32)paddr);
- ++ }
- ++
- + num--;
- + idx++;
- + idx &= htt->rx_ring.size_mask;
- + }
- +
- + fail:
- +- *(htt->rx_ring.alloc_idx.vaddr) = __cpu_to_le32(idx);
- ++ /*
- ++ * Make sure the rx buffer is updated before available buffer
- ++ * index to avoid any potential rx ring corruption.
- ++ */
- ++ mb();
- ++ *htt->rx_ring.alloc_idx.vaddr = __cpu_to_le32(idx);
- + return ret;
- + }
- +
- +@@ -198,7 +176,7 @@ static void ath10k_htt_rx_msdu_buff_repl
- + * automatically balances load wrt to CPU power.
- + *
- + * This probably comes at a cost of lower maximum throughput but
- +- * improves the avarage and stability. */
- ++ * improves the average and stability. */
- + spin_lock_bh(&htt->rx_ring.lock);
- + num_deficit = htt->rx_ring.fill_level - htt->rx_ring.fill_cnt;
- + num_to_fill = min(ATH10K_HTT_MAX_NUM_REFILL, num_deficit);
- +@@ -222,32 +200,37 @@ static void ath10k_htt_rx_msdu_buff_repl
- + static void ath10k_htt_rx_ring_refill_retry(unsigned long arg)
- + {
- + struct ath10k_htt *htt = (struct ath10k_htt *)arg;
- ++
- + ath10k_htt_rx_msdu_buff_replenish(htt);
- + }
- +
- +-void ath10k_htt_rx_detach(struct ath10k_htt *htt)
- ++int ath10k_htt_rx_ring_refill(struct ath10k *ar)
- + {
- +- int sw_rd_idx = htt->rx_ring.sw_rd_idx.msdu_payld;
- ++ struct ath10k_htt *htt = &ar->htt;
- ++ int ret;
- ++
- ++ spin_lock_bh(&htt->rx_ring.lock);
- ++ ret = ath10k_htt_rx_ring_fill_n(htt, (htt->rx_ring.fill_level -
- ++ htt->rx_ring.fill_cnt));
- ++ spin_unlock_bh(&htt->rx_ring.lock);
- ++
- ++ if (ret)
- ++ ath10k_htt_rx_ring_free(htt);
- ++
- ++ return ret;
- ++}
- +
- ++void ath10k_htt_rx_free(struct ath10k_htt *htt)
- ++{
- + del_timer_sync(&htt->rx_ring.refill_retry_timer);
- + tasklet_kill(&htt->rx_replenish_task);
- + tasklet_kill(&htt->txrx_compl_task);
- +
- + skb_queue_purge(&htt->tx_compl_q);
- + skb_queue_purge(&htt->rx_compl_q);
- ++ skb_queue_purge(&htt->rx_in_ord_compl_q);
- +
- +- while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) {
- +- struct sk_buff *skb =
- +- htt->rx_ring.netbufs_ring[sw_rd_idx];
- +- struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
- +-
- +- dma_unmap_single(htt->ar->dev, cb->paddr,
- +- skb->len + skb_tailroom(skb),
- +- DMA_FROM_DEVICE);
- +- dev_kfree_skb_any(htt->rx_ring.netbufs_ring[sw_rd_idx]);
- +- sw_rd_idx++;
- +- sw_rd_idx &= htt->rx_ring.size_mask;
- +- }
- ++ ath10k_htt_rx_ring_free(htt);
- +
- + dma_free_coherent(htt->ar->dev,
- + (htt->rx_ring.size *
- +@@ -265,66 +248,59 @@ void ath10k_htt_rx_detach(struct ath10k_
- +
- + static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
- + {
- ++ struct ath10k *ar = htt->ar;
- + int idx;
- + struct sk_buff *msdu;
- +
- + lockdep_assert_held(&htt->rx_ring.lock);
- +
- + if (htt->rx_ring.fill_cnt == 0) {
- +- ath10k_warn("tried to pop sk_buff from an empty rx ring\n");
- ++ ath10k_warn(ar, "tried to pop sk_buff from an empty rx ring\n");
- + return NULL;
- + }
- +
- + idx = htt->rx_ring.sw_rd_idx.msdu_payld;
- + msdu = htt->rx_ring.netbufs_ring[idx];
- ++ htt->rx_ring.netbufs_ring[idx] = NULL;
- ++ htt->rx_ring.paddrs_ring[idx] = 0;
- +
- + idx++;
- + idx &= htt->rx_ring.size_mask;
- + htt->rx_ring.sw_rd_idx.msdu_payld = idx;
- + htt->rx_ring.fill_cnt--;
- +
- +- return msdu;
- +-}
- +-
- +-static void ath10k_htt_rx_free_msdu_chain(struct sk_buff *skb)
- +-{
- +- struct sk_buff *next;
- ++ dma_unmap_single(htt->ar->dev,
- ++ ATH10K_SKB_RXCB(msdu)->paddr,
- ++ msdu->len + skb_tailroom(msdu),
- ++ DMA_FROM_DEVICE);
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx netbuf pop: ",
- ++ msdu->data, msdu->len + skb_tailroom(msdu));
- +
- +- while (skb) {
- +- next = skb->next;
- +- dev_kfree_skb_any(skb);
- +- skb = next;
- +- }
- ++ return msdu;
- + }
- +
- + /* return: < 0 fatal error, 0 - non chained msdu, 1 chained msdu */
- + static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
- + u8 **fw_desc, int *fw_desc_len,
- +- struct sk_buff **head_msdu,
- +- struct sk_buff **tail_msdu)
- ++ struct sk_buff_head *amsdu)
- + {
- ++ struct ath10k *ar = htt->ar;
- + int msdu_len, msdu_chaining = 0;
- + struct sk_buff *msdu;
- + struct htt_rx_desc *rx_desc;
- +
- + lockdep_assert_held(&htt->rx_ring.lock);
- +
- +- if (htt->rx_confused) {
- +- ath10k_warn("htt is confused. refusing rx\n");
- +- return -1;
- +- }
- +-
- +- msdu = *head_msdu = ath10k_htt_rx_netbuf_pop(htt);
- +- while (msdu) {
- ++ for (;;) {
- + int last_msdu, msdu_len_invalid, msdu_chained;
- +
- +- dma_unmap_single(htt->ar->dev,
- +- ATH10K_SKB_CB(msdu)->paddr,
- +- msdu->len + skb_tailroom(msdu),
- +- DMA_FROM_DEVICE);
- ++ msdu = ath10k_htt_rx_netbuf_pop(htt);
- ++ if (!msdu) {
- ++ __skb_queue_purge(amsdu);
- ++ return -ENOENT;
- ++ }
- +
- +- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",
- +- msdu->data, msdu->len + skb_tailroom(msdu));
- ++ __skb_queue_tail(amsdu, msdu);
- +
- + rx_desc = (struct htt_rx_desc *)msdu->data;
- +
- +@@ -343,12 +319,8 @@ static int ath10k_htt_rx_amsdu_pop(struc
- + */
- + if (!(__le32_to_cpu(rx_desc->attention.flags)
- + & RX_ATTENTION_FLAGS_MSDU_DONE)) {
- +- ath10k_htt_rx_free_msdu_chain(*head_msdu);
- +- *head_msdu = NULL;
- +- msdu = NULL;
- +- ath10k_err("htt rx stopped. cannot recover\n");
- +- htt->rx_confused = true;
- +- break;
- ++ __skb_queue_purge(amsdu);
- ++ return -EIO;
- + }
- +
- + /*
- +@@ -399,7 +371,6 @@ static int ath10k_htt_rx_amsdu_pop(struc
- + msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.info0),
- + RX_MSDU_START_INFO0_MSDU_LENGTH);
- + msdu_chained = rx_desc->frag_info.ring2_more_count;
- +- msdu_chaining = msdu_chained;
- +
- + if (msdu_len_invalid)
- + msdu_len = 0;
- +@@ -408,42 +379,32 @@ static int ath10k_htt_rx_amsdu_pop(struc
- + skb_put(msdu, min(msdu_len, HTT_RX_MSDU_SIZE));
- + msdu_len -= msdu->len;
- +
- +- /* FIXME: Do chained buffers include htt_rx_desc or not? */
- ++ /* Note: Chained buffers do not contain rx descriptor */
- + while (msdu_chained--) {
- +- struct sk_buff *next = ath10k_htt_rx_netbuf_pop(htt);
- +-
- +- dma_unmap_single(htt->ar->dev,
- +- ATH10K_SKB_CB(next)->paddr,
- +- next->len + skb_tailroom(next),
- +- DMA_FROM_DEVICE);
- +-
- +- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL,
- +- "htt rx chained: ", next->data,
- +- next->len + skb_tailroom(next));
- +-
- +- skb_trim(next, 0);
- +- skb_put(next, min(msdu_len, HTT_RX_BUF_SIZE));
- +- msdu_len -= next->len;
- ++ msdu = ath10k_htt_rx_netbuf_pop(htt);
- ++ if (!msdu) {
- ++ __skb_queue_purge(amsdu);
- ++ return -ENOENT;
- ++ }
- +
- +- msdu->next = next;
- +- msdu = next;
- ++ __skb_queue_tail(amsdu, msdu);
- ++ skb_trim(msdu, 0);
- ++ skb_put(msdu, min(msdu_len, HTT_RX_BUF_SIZE));
- ++ msdu_len -= msdu->len;
- ++ msdu_chaining = 1;
- + }
- +
- + last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
- + RX_MSDU_END_INFO0_LAST_MSDU;
- +
- +- if (last_msdu) {
- +- msdu->next = NULL;
- ++ trace_ath10k_htt_rx_desc(ar, &rx_desc->attention,
- ++ sizeof(*rx_desc) - sizeof(u32));
- ++
- ++ if (last_msdu)
- + break;
- +- } else {
- +- struct sk_buff *next = ath10k_htt_rx_netbuf_pop(htt);
- +- msdu->next = next;
- +- msdu = next;
- +- }
- + }
- +- *tail_msdu = msdu;
- +
- +- if (*head_msdu == NULL)
- ++ if (skb_queue_empty(amsdu))
- + msdu_chaining = -1;
- +
- + /*
- +@@ -465,43 +426,117 @@ static int ath10k_htt_rx_amsdu_pop(struc
- + static void ath10k_htt_rx_replenish_task(unsigned long ptr)
- + {
- + struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
- ++
- + ath10k_htt_rx_msdu_buff_replenish(htt);
- + }
- +
- +-int ath10k_htt_rx_attach(struct ath10k_htt *htt)
- ++static struct sk_buff *ath10k_htt_rx_pop_paddr(struct ath10k_htt *htt,
- ++ u32 paddr)
- ++{
- ++ struct ath10k *ar = htt->ar;
- ++ struct ath10k_skb_rxcb *rxcb;
- ++ struct sk_buff *msdu;
- ++
- ++ lockdep_assert_held(&htt->rx_ring.lock);
- ++
- ++ msdu = ath10k_htt_rx_find_skb_paddr(ar, paddr);
- ++ if (!msdu)
- ++ return NULL;
- ++
- ++ rxcb = ATH10K_SKB_RXCB(msdu);
- ++ hash_del(&rxcb->hlist);
- ++ htt->rx_ring.fill_cnt--;
- ++
- ++ dma_unmap_single(htt->ar->dev, rxcb->paddr,
- ++ msdu->len + skb_tailroom(msdu),
- ++ DMA_FROM_DEVICE);
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx netbuf pop: ",
- ++ msdu->data, msdu->len + skb_tailroom(msdu));
- ++
- ++ return msdu;
- ++}
- ++
- ++static int ath10k_htt_rx_pop_paddr_list(struct ath10k_htt *htt,
- ++ struct htt_rx_in_ord_ind *ev,
- ++ struct sk_buff_head *list)
- + {
- ++ struct ath10k *ar = htt->ar;
- ++ struct htt_rx_in_ord_msdu_desc *msdu_desc = ev->msdu_descs;
- ++ struct htt_rx_desc *rxd;
- ++ struct sk_buff *msdu;
- ++ int msdu_count;
- ++ bool is_offload;
- ++ u32 paddr;
- ++
- ++ lockdep_assert_held(&htt->rx_ring.lock);
- ++
- ++ msdu_count = __le16_to_cpu(ev->msdu_count);
- ++ is_offload = !!(ev->info & HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK);
- ++
- ++ while (msdu_count--) {
- ++ paddr = __le32_to_cpu(msdu_desc->msdu_paddr);
- ++
- ++ msdu = ath10k_htt_rx_pop_paddr(htt, paddr);
- ++ if (!msdu) {
- ++ __skb_queue_purge(list);
- ++ return -ENOENT;
- ++ }
- ++
- ++ __skb_queue_tail(list, msdu);
- ++
- ++ if (!is_offload) {
- ++ rxd = (void *)msdu->data;
- ++
- ++ trace_ath10k_htt_rx_desc(ar, rxd, sizeof(*rxd));
- ++
- ++ skb_put(msdu, sizeof(*rxd));
- ++ skb_pull(msdu, sizeof(*rxd));
- ++ skb_put(msdu, __le16_to_cpu(msdu_desc->msdu_len));
- ++
- ++ if (!(__le32_to_cpu(rxd->attention.flags) &
- ++ RX_ATTENTION_FLAGS_MSDU_DONE)) {
- ++ ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n");
- ++ return -EIO;
- ++ }
- ++ }
- ++
- ++ msdu_desc++;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- ++int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
- ++{
- ++ struct ath10k *ar = htt->ar;
- + dma_addr_t paddr;
- + void *vaddr;
- ++ size_t size;
- + struct timer_list *timer = &htt->rx_ring.refill_retry_timer;
- +
- +- htt->rx_ring.size = ath10k_htt_rx_ring_size(htt);
- +- if (!is_power_of_2(htt->rx_ring.size)) {
- +- ath10k_warn("htt rx ring size is not power of 2\n");
- +- return -EINVAL;
- +- }
- ++ htt->rx_confused = false;
- +
- ++ /* XXX: The fill level could be changed during runtime in response to
- ++ * the host processing latency. Is this really worth it?
- ++ */
- ++ htt->rx_ring.size = HTT_RX_RING_SIZE;
- + htt->rx_ring.size_mask = htt->rx_ring.size - 1;
- ++ htt->rx_ring.fill_level = HTT_RX_RING_FILL_LEVEL;
- +
- +- /*
- +- * Set the initial value for the level to which the rx ring
- +- * should be filled, based on the max throughput and the
- +- * worst likely latency for the host to fill the rx ring
- +- * with new buffers. In theory, this fill level can be
- +- * dynamically adjusted from the initial value set here, to
- +- * reflect the actual host latency rather than a
- +- * conservative assumption about the host latency.
- +- */
- +- htt->rx_ring.fill_level = ath10k_htt_rx_ring_fill_level(htt);
- ++ if (!is_power_of_2(htt->rx_ring.size)) {
- ++ ath10k_warn(ar, "htt rx ring size is not power of 2\n");
- ++ return -EINVAL;
- ++ }
- +
- + htt->rx_ring.netbufs_ring =
- +- kmalloc(htt->rx_ring.size * sizeof(struct sk_buff *),
- ++ kzalloc(htt->rx_ring.size * sizeof(struct sk_buff *),
- + GFP_KERNEL);
- + if (!htt->rx_ring.netbufs_ring)
- + goto err_netbuf;
- +
- +- vaddr = dma_alloc_coherent(htt->ar->dev,
- +- (htt->rx_ring.size * sizeof(htt->rx_ring.paddrs_ring)),
- +- &paddr, GFP_DMA);
- ++ size = htt->rx_ring.size * sizeof(htt->rx_ring.paddrs_ring);
- ++
- ++ vaddr = dma_alloc_coherent(htt->ar->dev, size, &paddr, GFP_DMA);
- + if (!vaddr)
- + goto err_dma_ring;
- +
- +@@ -516,7 +551,7 @@ int ath10k_htt_rx_attach(struct ath10k_h
- +
- + htt->rx_ring.alloc_idx.vaddr = vaddr;
- + htt->rx_ring.alloc_idx.paddr = paddr;
- +- htt->rx_ring.sw_rd_idx.msdu_payld = 0;
- ++ htt->rx_ring.sw_rd_idx.msdu_payld = htt->rx_ring.size_mask;
- + *htt->rx_ring.alloc_idx.vaddr = 0;
- +
- + /* Initialize the Rx refill retry timer */
- +@@ -525,28 +560,23 @@ int ath10k_htt_rx_attach(struct ath10k_h
- + spin_lock_init(&htt->rx_ring.lock);
- +
- + htt->rx_ring.fill_cnt = 0;
- +- if (__ath10k_htt_rx_ring_fill_n(htt, htt->rx_ring.fill_level))
- +- goto err_fill_ring;
- ++ htt->rx_ring.sw_rd_idx.msdu_payld = 0;
- ++ hash_init(htt->rx_ring.skb_table);
- +
- + tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task,
- + (unsigned long)htt);
- +
- + skb_queue_head_init(&htt->tx_compl_q);
- + skb_queue_head_init(&htt->rx_compl_q);
- ++ skb_queue_head_init(&htt->rx_in_ord_compl_q);
- +
- + tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task,
- + (unsigned long)htt);
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
- + htt->rx_ring.size, htt->rx_ring.fill_level);
- + return 0;
- +
- +-err_fill_ring:
- +- ath10k_htt_rx_ring_free(htt);
- +- dma_free_coherent(htt->ar->dev,
- +- sizeof(*htt->rx_ring.alloc_idx.vaddr),
- +- htt->rx_ring.alloc_idx.vaddr,
- +- htt->rx_ring.alloc_idx.paddr);
- + err_dma_idx:
- + dma_free_coherent(htt->ar->dev,
- + (htt->rx_ring.size *
- +@@ -559,73 +589,54 @@ err_netbuf:
- + return -ENOMEM;
- + }
- +
- +-static int ath10k_htt_rx_crypto_param_len(enum htt_rx_mpdu_encrypt_type type)
- ++static int ath10k_htt_rx_crypto_param_len(struct ath10k *ar,
- ++ enum htt_rx_mpdu_encrypt_type type)
- + {
- + switch (type) {
- ++ case HTT_RX_MPDU_ENCRYPT_NONE:
- ++ return 0;
- + case HTT_RX_MPDU_ENCRYPT_WEP40:
- + case HTT_RX_MPDU_ENCRYPT_WEP104:
- +- return 4;
- ++ return IEEE80211_WEP_IV_LEN;
- + case HTT_RX_MPDU_ENCRYPT_TKIP_WITHOUT_MIC:
- +- case HTT_RX_MPDU_ENCRYPT_WEP128: /* not tested */
- + case HTT_RX_MPDU_ENCRYPT_TKIP_WPA:
- +- case HTT_RX_MPDU_ENCRYPT_WAPI: /* not tested */
- ++ return IEEE80211_TKIP_IV_LEN;
- + case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2:
- +- return 8;
- +- case HTT_RX_MPDU_ENCRYPT_NONE:
- +- return 0;
- ++ return IEEE80211_CCMP_HDR_LEN;
- ++ case HTT_RX_MPDU_ENCRYPT_WEP128:
- ++ case HTT_RX_MPDU_ENCRYPT_WAPI:
- ++ break;
- + }
- +
- +- ath10k_warn("unknown encryption type %d\n", type);
- ++ ath10k_warn(ar, "unsupported encryption type %d\n", type);
- + return 0;
- + }
- +
- +-static int ath10k_htt_rx_crypto_tail_len(enum htt_rx_mpdu_encrypt_type type)
- ++#define MICHAEL_MIC_LEN 8
- ++
- ++static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar,
- ++ enum htt_rx_mpdu_encrypt_type type)
- + {
- + switch (type) {
- + case HTT_RX_MPDU_ENCRYPT_NONE:
- ++ return 0;
- + case HTT_RX_MPDU_ENCRYPT_WEP40:
- + case HTT_RX_MPDU_ENCRYPT_WEP104:
- +- case HTT_RX_MPDU_ENCRYPT_WEP128:
- +- case HTT_RX_MPDU_ENCRYPT_WAPI:
- +- return 0;
- ++ return IEEE80211_WEP_ICV_LEN;
- + case HTT_RX_MPDU_ENCRYPT_TKIP_WITHOUT_MIC:
- + case HTT_RX_MPDU_ENCRYPT_TKIP_WPA:
- +- return 4;
- ++ return IEEE80211_TKIP_ICV_LEN;
- + case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2:
- +- return 8;
- ++ return IEEE80211_CCMP_MIC_LEN;
- ++ case HTT_RX_MPDU_ENCRYPT_WEP128:
- ++ case HTT_RX_MPDU_ENCRYPT_WAPI:
- ++ break;
- + }
- +
- +- ath10k_warn("unknown encryption type %d\n", type);
- ++ ath10k_warn(ar, "unsupported encryption type %d\n", type);
- + return 0;
- + }
- +
- +-/* Applies for first msdu in chain, before altering it. */
- +-static struct ieee80211_hdr *ath10k_htt_rx_skb_get_hdr(struct sk_buff *skb)
- +-{
- +- struct htt_rx_desc *rxd;
- +- enum rx_msdu_decap_format fmt;
- +-
- +- rxd = (void *)skb->data - sizeof(*rxd);
- +- fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
- +- RX_MSDU_START_INFO1_DECAP_FORMAT);
- +-
- +- if (fmt == RX_MSDU_DECAP_RAW)
- +- return (void *)skb->data;
- +- else
- +- return (void *)skb->data - RX_HTT_HDR_STATUS_LEN;
- +-}
- +-
- +-/* This function only applies for first msdu in an msdu chain */
- +-static bool ath10k_htt_rx_hdr_is_amsdu(struct ieee80211_hdr *hdr)
- +-{
- +- if (ieee80211_is_data_qos(hdr->frame_control)) {
- +- u8 *qc = ieee80211_get_qos_ctl(hdr);
- +- if (qc[0] & 0x80)
- +- return true;
- +- }
- +- return false;
- +-}
- +-
- + struct rfc1042_hdr {
- + u8 llc_dsap;
- + u8 llc_ssap;
- +@@ -660,23 +671,34 @@ static const u8 rx_legacy_rate_idx[] = {
- + };
- +
- + static void ath10k_htt_rx_h_rates(struct ath10k *ar,
- +- enum ieee80211_band band,
- +- u8 info0, u32 info1, u32 info2,
- +- struct ieee80211_rx_status *status)
- ++ struct ieee80211_rx_status *status,
- ++ struct htt_rx_desc *rxd)
- + {
- ++ enum ieee80211_band band;
- + u8 cck, rate, rate_idx, bw, sgi, mcs, nss;
- + u8 preamble = 0;
- ++ u32 info1, info2, info3;
- +
- +- /* Check if valid fields */
- +- if (!(info0 & HTT_RX_INDICATION_INFO0_START_VALID))
- ++ /* Band value can't be set as undefined but freq can be 0 - use that to
- ++ * determine whether band is provided.
- ++ *
- ++ * FIXME: Perhaps this can go away if CCK rate reporting is a little
- ++ * reworked?
- ++ */
- ++ if (!status->freq)
- + return;
- +
- +- preamble = MS(info1, HTT_RX_INDICATION_INFO1_PREAMBLE_TYPE);
- ++ band = status->band;
- ++ info1 = __le32_to_cpu(rxd->ppdu_start.info1);
- ++ info2 = __le32_to_cpu(rxd->ppdu_start.info2);
- ++ info3 = __le32_to_cpu(rxd->ppdu_start.info3);
- ++
- ++ preamble = MS(info1, RX_PPDU_START_INFO1_PREAMBLE_TYPE);
- +
- + switch (preamble) {
- + case HTT_RX_LEGACY:
- +- cck = info0 & HTT_RX_INDICATION_INFO0_LEGACY_RATE_CCK;
- +- rate = MS(info0, HTT_RX_INDICATION_INFO0_LEGACY_RATE);
- ++ cck = info1 & RX_PPDU_START_INFO1_L_SIG_RATE_SELECT;
- ++ rate = MS(info1, RX_PPDU_START_INFO1_L_SIG_RATE);
- + rate_idx = 0;
- +
- + if (rate < 0x08 || rate > 0x0F)
- +@@ -703,11 +725,11 @@ static void ath10k_htt_rx_h_rates(struct
- + break;
- + case HTT_RX_HT:
- + case HTT_RX_HT_WITH_TXBF:
- +- /* HT-SIG - Table 20-11 in info1 and info2 */
- +- mcs = info1 & 0x1F;
- ++ /* HT-SIG - Table 20-11 in info2 and info3 */
- ++ mcs = info2 & 0x1F;
- + nss = mcs >> 3;
- +- bw = (info1 >> 7) & 1;
- +- sgi = (info2 >> 7) & 1;
- ++ bw = (info2 >> 7) & 1;
- ++ sgi = (info3 >> 7) & 1;
- +
- + status->rate_idx = mcs;
- + status->flag |= RX_FLAG_HT;
- +@@ -718,12 +740,12 @@ static void ath10k_htt_rx_h_rates(struct
- + break;
- + case HTT_RX_VHT:
- + case HTT_RX_VHT_WITH_TXBF:
- +- /* VHT-SIG-A1 in info 1, VHT-SIG-A2 in info2
- ++ /* VHT-SIG-A1 in info2, VHT-SIG-A2 in info3
- + TODO check this */
- +- mcs = (info2 >> 4) & 0x0F;
- +- nss = ((info1 >> 10) & 0x07) + 1;
- +- bw = info1 & 3;
- +- sgi = info2 & 1;
- ++ mcs = (info3 >> 4) & 0x0F;
- ++ nss = ((info2 >> 10) & 0x07) + 1;
- ++ bw = info2 & 3;
- ++ sgi = info3 & 1;
- +
- + status->rate_idx = mcs;
- + status->vht_nss = nss;
- +@@ -751,28 +773,6 @@ static void ath10k_htt_rx_h_rates(struct
- + }
- + }
- +
- +-static void ath10k_htt_rx_h_protected(struct ath10k_htt *htt,
- +- struct ieee80211_rx_status *rx_status,
- +- struct sk_buff *skb,
- +- enum htt_rx_mpdu_encrypt_type enctype)
- +-{
- +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- +-
- +-
- +- if (enctype == HTT_RX_MPDU_ENCRYPT_NONE) {
- +- rx_status->flag &= ~(RX_FLAG_DECRYPTED |
- +- RX_FLAG_IV_STRIPPED |
- +- RX_FLAG_MMIC_STRIPPED);
- +- return;
- +- }
- +-
- +- rx_status->flag |= RX_FLAG_DECRYPTED |
- +- RX_FLAG_IV_STRIPPED |
- +- RX_FLAG_MMIC_STRIPPED;
- +- hdr->frame_control = __cpu_to_le16(__le16_to_cpu(hdr->frame_control) &
- +- ~IEEE80211_FCTL_PROTECTED);
- +-}
- +-
- + static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
- + struct ieee80211_rx_status *status)
- + {
- +@@ -793,19 +793,121 @@ static bool ath10k_htt_rx_h_channel(stru
- + return true;
- + }
- +
- ++static void ath10k_htt_rx_h_signal(struct ath10k *ar,
- ++ struct ieee80211_rx_status *status,
- ++ struct htt_rx_desc *rxd)
- ++{
- ++ /* FIXME: Get real NF */
- ++ status->signal = ATH10K_DEFAULT_NOISE_FLOOR +
- ++ rxd->ppdu_start.rssi_comb;
- ++ status->flag &= ~RX_FLAG_NO_SIGNAL_VAL;
- ++}
- ++
- ++static void ath10k_htt_rx_h_mactime(struct ath10k *ar,
- ++ struct ieee80211_rx_status *status,
- ++ struct htt_rx_desc *rxd)
- ++{
- ++ /* FIXME: TSF is known only at the end of PPDU, in the last MPDU. This
- ++ * means all prior MSDUs in a PPDU are reported to mac80211 without the
- ++ * TSF. Is it worth holding frames until end of PPDU is known?
- ++ *
- ++ * FIXME: Can we get/compute 64bit TSF?
- ++ */
- ++ status->mactime = __le32_to_cpu(rxd->ppdu_end.common.tsf_timestamp);
- ++ status->flag |= RX_FLAG_MACTIME_END;
- ++}
- ++
- ++static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
- ++ struct sk_buff_head *amsdu,
- ++ struct ieee80211_rx_status *status)
- ++{
- ++ struct sk_buff *first;
- ++ struct htt_rx_desc *rxd;
- ++ bool is_first_ppdu;
- ++ bool is_last_ppdu;
- ++
- ++ if (skb_queue_empty(amsdu))
- ++ return;
- ++
- ++ first = skb_peek(amsdu);
- ++ rxd = (void *)first->data - sizeof(*rxd);
- ++
- ++ is_first_ppdu = !!(rxd->attention.flags &
- ++ __cpu_to_le32(RX_ATTENTION_FLAGS_FIRST_MPDU));
- ++ is_last_ppdu = !!(rxd->attention.flags &
- ++ __cpu_to_le32(RX_ATTENTION_FLAGS_LAST_MPDU));
- ++
- ++ if (is_first_ppdu) {
- ++ /* New PPDU starts so clear out the old per-PPDU status. */
- ++ status->freq = 0;
- ++ status->rate_idx = 0;
- ++ status->vht_nss = 0;
- ++ status->vht_flag &= ~RX_VHT_FLAG_80MHZ;
- ++ status->flag &= ~(RX_FLAG_HT |
- ++ RX_FLAG_VHT |
- ++ RX_FLAG_SHORT_GI |
- ++ RX_FLAG_40MHZ |
- ++ RX_FLAG_MACTIME_END);
- ++ status->flag |= RX_FLAG_NO_SIGNAL_VAL;
- ++
- ++ ath10k_htt_rx_h_signal(ar, status, rxd);
- ++ ath10k_htt_rx_h_channel(ar, status);
- ++ ath10k_htt_rx_h_rates(ar, status, rxd);
- ++ }
- ++
- ++ if (is_last_ppdu)
- ++ ath10k_htt_rx_h_mactime(ar, status, rxd);
- ++}
- ++
- ++static const char * const tid_to_ac[] = {
- ++ "BE",
- ++ "BK",
- ++ "BK",
- ++ "BE",
- ++ "VI",
- ++ "VI",
- ++ "VO",
- ++ "VO",
- ++};
- ++
- ++static char *ath10k_get_tid(struct ieee80211_hdr *hdr, char *out, size_t size)
- ++{
- ++ u8 *qc;
- ++ int tid;
- ++
- ++ if (!ieee80211_is_data_qos(hdr->frame_control))
- ++ return "";
- ++
- ++ qc = ieee80211_get_qos_ctl(hdr);
- ++ tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
- ++ if (tid < 8)
- ++ snprintf(out, size, "tid %d (%s)", tid, tid_to_ac[tid]);
- ++ else
- ++ snprintf(out, size, "tid %d", tid);
- ++
- ++ return out;
- ++}
- ++
- + static void ath10k_process_rx(struct ath10k *ar,
- + struct ieee80211_rx_status *rx_status,
- + struct sk_buff *skb)
- + {
- + struct ieee80211_rx_status *status;
- ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- ++ char tid[32];
- +
- + status = IEEE80211_SKB_RXCB(skb);
- + *status = *rx_status;
- +
- +- ath10k_dbg(ATH10K_DBG_DATA,
- +- "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %imic-err %i\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_DATA,
- ++ "rx skb %p len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
- + skb,
- + skb->len,
- ++ ieee80211_get_SA(hdr),
- ++ ath10k_get_tid(hdr, tid, sizeof(tid)),
- ++ is_multicast_ether_addr(ieee80211_get_DA(hdr)) ?
- ++ "mcast" : "ucast",
- ++ (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4,
- + status->flag == 0 ? "legacy" : "",
- + status->flag & RX_FLAG_HT ? "ht" : "",
- + status->flag & RX_FLAG_VHT ? "vht" : "",
- +@@ -817,9 +919,12 @@ static void ath10k_process_rx(struct ath
- + status->freq,
- + status->band, status->flag,
- + !!(status->flag & RX_FLAG_FAILED_FCS_CRC),
- +- !!(status->flag & RX_FLAG_MMIC_ERROR));
- +- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
- ++ !!(status->flag & RX_FLAG_MMIC_ERROR),
- ++ !!(status->flag & RX_FLAG_AMSDU_MORE));
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
- + skb->data, skb->len);
- ++ trace_ath10k_rx_hdr(ar, skb->data, skb->len);
- ++ trace_ath10k_rx_payload(ar, skb->data, skb->len);
- +
- + ieee80211_rx(ar->hw, skb);
- + }
- +@@ -830,179 +935,263 @@ static int ath10k_htt_rx_nwifi_hdrlen(st
- + return round_up(ieee80211_hdrlen(hdr->frame_control), 4);
- + }
- +
- +-static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
- +- struct ieee80211_rx_status *rx_status,
- +- struct sk_buff *skb_in)
- ++static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar,
- ++ struct sk_buff *msdu,
- ++ struct ieee80211_rx_status *status,
- ++ enum htt_rx_mpdu_encrypt_type enctype,
- ++ bool is_decrypted)
- + {
- ++ struct ieee80211_hdr *hdr;
- + struct htt_rx_desc *rxd;
- +- struct sk_buff *skb = skb_in;
- +- struct sk_buff *first;
- +- enum rx_msdu_decap_format fmt;
- +- enum htt_rx_mpdu_encrypt_type enctype;
- ++ size_t hdr_len;
- ++ size_t crypto_len;
- ++ bool is_first;
- ++ bool is_last;
- ++
- ++ rxd = (void *)msdu->data - sizeof(*rxd);
- ++ is_first = !!(rxd->msdu_end.info0 &
- ++ __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU));
- ++ is_last = !!(rxd->msdu_end.info0 &
- ++ __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU));
- ++
- ++ /* Delivered decapped frame:
- ++ * [802.11 header]
- ++ * [crypto param] <-- can be trimmed if !fcs_err &&
- ++ * !decrypt_err && !peer_idx_invalid
- ++ * [amsdu header] <-- only if A-MSDU
- ++ * [rfc1042/llc]
- ++ * [payload]
- ++ * [FCS] <-- at end, needs to be trimmed
- ++ */
- ++
- ++ /* This probably shouldn't happen but warn just in case */
- ++ if (unlikely(WARN_ON_ONCE(!is_first)))
- ++ return;
- ++
- ++ /* This probably shouldn't happen but warn just in case */
- ++ if (unlikely(WARN_ON_ONCE(!(is_first && is_last))))
- ++ return;
- ++
- ++ skb_trim(msdu, msdu->len - FCS_LEN);
- ++
- ++ /* In most cases this will be true for sniffed frames. It makes sense
- ++ * to deliver them as-is without stripping the crypto param. This would
- ++ * also make sense for software based decryption (which is not
- ++ * implemented in ath10k).
- ++ *
- ++ * If there's no error then the frame is decrypted. At least that is
- ++ * the case for frames that come in via fragmented rx indication.
- ++ */
- ++ if (!is_decrypted)
- ++ return;
- ++
- ++ /* The payload is decrypted so strip crypto params. Start from tail
- ++ * since hdr is used to compute some stuff.
- ++ */
- ++
- ++ hdr = (void *)msdu->data;
- ++
- ++ /* Tail */
- ++ skb_trim(msdu, msdu->len - ath10k_htt_rx_crypto_tail_len(ar, enctype));
- ++
- ++ /* MMIC */
- ++ if (!ieee80211_has_morefrags(hdr->frame_control) &&
- ++ enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
- ++ skb_trim(msdu, msdu->len - 8);
- ++
- ++ /* Head */
- ++ hdr_len = ieee80211_hdrlen(hdr->frame_control);
- ++ crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype);
- ++
- ++ memmove((void *)msdu->data + crypto_len,
- ++ (void *)msdu->data, hdr_len);
- ++ skb_pull(msdu, crypto_len);
- ++}
- ++
- ++static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
- ++ struct sk_buff *msdu,
- ++ struct ieee80211_rx_status *status,
- ++ const u8 first_hdr[64])
- ++{
- + struct ieee80211_hdr *hdr;
- +- u8 hdr_buf[64], addr[ETH_ALEN], *qos;
- +- unsigned int hdr_len;
- ++ size_t hdr_len;
- ++ u8 da[ETH_ALEN];
- ++ u8 sa[ETH_ALEN];
- ++
- ++ /* Delivered decapped frame:
- ++ * [nwifi 802.11 header] <-- replaced with 802.11 hdr
- ++ * [rfc1042/llc]
- ++ *
- ++ * Note: The nwifi header doesn't have QoS Control and is
- ++ * (always?) a 3addr frame.
- ++ *
- ++ * Note2: There's no A-MSDU subframe header. Even if it's part
- ++ * of an A-MSDU.
- ++ */
- +
- +- rxd = (void *)skb->data - sizeof(*rxd);
- +- enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
- +- RX_MPDU_START_INFO0_ENCRYPT_TYPE);
- ++ /* pull decapped header and copy SA & DA */
- ++ hdr = (struct ieee80211_hdr *)msdu->data;
- ++ hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
- ++ ether_addr_copy(da, ieee80211_get_DA(hdr));
- ++ ether_addr_copy(sa, ieee80211_get_SA(hdr));
- ++ skb_pull(msdu, hdr_len);
- +
- +- hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status;
- ++ /* push original 802.11 header */
- ++ hdr = (struct ieee80211_hdr *)first_hdr;
- + hdr_len = ieee80211_hdrlen(hdr->frame_control);
- +- memcpy(hdr_buf, hdr, hdr_len);
- +- hdr = (struct ieee80211_hdr *)hdr_buf;
- ++ memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
- +
- +- first = skb;
- +- while (skb) {
- +- void *decap_hdr;
- +- int len;
- +-
- +- rxd = (void *)skb->data - sizeof(*rxd);
- +- fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
- +- RX_MSDU_START_INFO1_DECAP_FORMAT);
- +- decap_hdr = (void *)rxd->rx_hdr_status;
- +-
- +- skb->ip_summed = ath10k_htt_rx_get_csum_state(skb);
- +-
- +- /* First frame in an A-MSDU chain has more decapped data. */
- +- if (skb == first) {
- +- len = round_up(ieee80211_hdrlen(hdr->frame_control), 4);
- +- len += round_up(ath10k_htt_rx_crypto_param_len(enctype),
- +- 4);
- +- decap_hdr += len;
- +- }
- ++ /* original 802.11 header has a different DA and in
- ++ * case of 4addr it may also have different SA
- ++ */
- ++ hdr = (struct ieee80211_hdr *)msdu->data;
- ++ ether_addr_copy(ieee80211_get_DA(hdr), da);
- ++ ether_addr_copy(ieee80211_get_SA(hdr), sa);
- ++}
- +
- +- switch (fmt) {
- +- case RX_MSDU_DECAP_RAW:
- +- /* remove trailing FCS */
- +- skb_trim(skb, skb->len - FCS_LEN);
- +- break;
- +- case RX_MSDU_DECAP_NATIVE_WIFI:
- +- /* pull decapped header and copy DA */
- +- hdr = (struct ieee80211_hdr *)skb->data;
- +- hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
- +- memcpy(addr, ieee80211_get_DA(hdr), ETH_ALEN);
- +- skb_pull(skb, hdr_len);
- +-
- +- /* push original 802.11 header */
- +- hdr = (struct ieee80211_hdr *)hdr_buf;
- +- hdr_len = ieee80211_hdrlen(hdr->frame_control);
- +- memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
- +-
- +- /* original A-MSDU header has the bit set but we're
- +- * not including A-MSDU subframe header */
- +- hdr = (struct ieee80211_hdr *)skb->data;
- +- qos = ieee80211_get_qos_ctl(hdr);
- +- qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
- ++static void *ath10k_htt_rx_h_find_rfc1042(struct ath10k *ar,
- ++ struct sk_buff *msdu,
- ++ enum htt_rx_mpdu_encrypt_type enctype)
- ++{
- ++ struct ieee80211_hdr *hdr;
- ++ struct htt_rx_desc *rxd;
- ++ size_t hdr_len, crypto_len;
- ++ void *rfc1042;
- ++ bool is_first, is_last, is_amsdu;
- +
- +- /* original 802.11 header has a different DA */
- +- memcpy(ieee80211_get_DA(hdr), addr, ETH_ALEN);
- +- break;
- +- case RX_MSDU_DECAP_ETHERNET2_DIX:
- +- /* strip ethernet header and insert decapped 802.11
- +- * header, amsdu subframe header and rfc1042 header */
- +-
- +- len = 0;
- +- len += sizeof(struct rfc1042_hdr);
- +- len += sizeof(struct amsdu_subframe_hdr);
- +-
- +- skb_pull(skb, sizeof(struct ethhdr));
- +- memcpy(skb_push(skb, len), decap_hdr, len);
- +- memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
- +- break;
- +- case RX_MSDU_DECAP_8023_SNAP_LLC:
- +- /* insert decapped 802.11 header making a singly
- +- * A-MSDU */
- +- memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
- +- break;
- +- }
- ++ rxd = (void *)msdu->data - sizeof(*rxd);
- ++ hdr = (void *)rxd->rx_hdr_status;
- +
- +- skb_in = skb;
- +- ath10k_htt_rx_h_protected(htt, rx_status, skb_in, enctype);
- +- skb = skb->next;
- +- skb_in->next = NULL;
- ++ is_first = !!(rxd->msdu_end.info0 &
- ++ __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU));
- ++ is_last = !!(rxd->msdu_end.info0 &
- ++ __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU));
- ++ is_amsdu = !(is_first && is_last);
- +
- +- if (skb)
- +- rx_status->flag |= RX_FLAG_AMSDU_MORE;
- +- else
- +- rx_status->flag &= ~RX_FLAG_AMSDU_MORE;
- ++ rfc1042 = hdr;
- ++
- ++ if (is_first) {
- ++ hdr_len = ieee80211_hdrlen(hdr->frame_control);
- ++ crypto_len = ath10k_htt_rx_crypto_param_len(ar, enctype);
- +
- +- ath10k_process_rx(htt->ar, rx_status, skb_in);
- ++ rfc1042 += round_up(hdr_len, 4) +
- ++ round_up(crypto_len, 4);
- + }
- +
- +- /* FIXME: It might be nice to re-assemble the A-MSDU when there's a
- +- * monitor interface active for sniffing purposes. */
- ++ if (is_amsdu)
- ++ rfc1042 += sizeof(struct amsdu_subframe_hdr);
- ++
- ++ return rfc1042;
- + }
- +
- +-static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
- +- struct ieee80211_rx_status *rx_status,
- +- struct sk_buff *skb)
- ++static void ath10k_htt_rx_h_undecap_eth(struct ath10k *ar,
- ++ struct sk_buff *msdu,
- ++ struct ieee80211_rx_status *status,
- ++ const u8 first_hdr[64],
- ++ enum htt_rx_mpdu_encrypt_type enctype)
- + {
- +- struct htt_rx_desc *rxd;
- + struct ieee80211_hdr *hdr;
- +- enum rx_msdu_decap_format fmt;
- +- enum htt_rx_mpdu_encrypt_type enctype;
- +- int hdr_len;
- ++ struct ethhdr *eth;
- ++ size_t hdr_len;
- + void *rfc1042;
- ++ u8 da[ETH_ALEN];
- ++ u8 sa[ETH_ALEN];
- +
- +- /* This shouldn't happen. If it does than it may be a FW bug. */
- +- if (skb->next) {
- +- ath10k_warn("htt rx received chained non A-MSDU frame\n");
- +- ath10k_htt_rx_free_msdu_chain(skb->next);
- +- skb->next = NULL;
- +- }
- ++ /* Delivered decapped frame:
- ++ * [eth header] <-- replaced with 802.11 hdr & rfc1042/llc
- ++ * [payload]
- ++ */
- +
- +- rxd = (void *)skb->data - sizeof(*rxd);
- +- fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
- +- RX_MSDU_START_INFO1_DECAP_FORMAT);
- +- enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
- +- RX_MPDU_START_INFO0_ENCRYPT_TYPE);
- +- hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status;
- ++ rfc1042 = ath10k_htt_rx_h_find_rfc1042(ar, msdu, enctype);
- ++ if (WARN_ON_ONCE(!rfc1042))
- ++ return;
- ++
- ++ /* pull decapped header and copy SA & DA */
- ++ eth = (struct ethhdr *)msdu->data;
- ++ ether_addr_copy(da, eth->h_dest);
- ++ ether_addr_copy(sa, eth->h_source);
- ++ skb_pull(msdu, sizeof(struct ethhdr));
- ++
- ++ /* push rfc1042/llc/snap */
- ++ memcpy(skb_push(msdu, sizeof(struct rfc1042_hdr)), rfc1042,
- ++ sizeof(struct rfc1042_hdr));
- ++
- ++ /* push original 802.11 header */
- ++ hdr = (struct ieee80211_hdr *)first_hdr;
- + hdr_len = ieee80211_hdrlen(hdr->frame_control);
- ++ memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
- ++
- ++ /* original 802.11 header has a different DA and in
- ++ * case of 4addr it may also have different SA
- ++ */
- ++ hdr = (struct ieee80211_hdr *)msdu->data;
- ++ ether_addr_copy(ieee80211_get_DA(hdr), da);
- ++ ether_addr_copy(ieee80211_get_SA(hdr), sa);
- ++}
- ++
- ++static void ath10k_htt_rx_h_undecap_snap(struct ath10k *ar,
- ++ struct sk_buff *msdu,
- ++ struct ieee80211_rx_status *status,
- ++ const u8 first_hdr[64])
- ++{
- ++ struct ieee80211_hdr *hdr;
- ++ size_t hdr_len;
- ++
- ++ /* Delivered decapped frame:
- ++ * [amsdu header] <-- replaced with 802.11 hdr
- ++ * [rfc1042/llc]
- ++ * [payload]
- ++ */
- ++
- ++ skb_pull(msdu, sizeof(struct amsdu_subframe_hdr));
- ++
- ++ hdr = (struct ieee80211_hdr *)first_hdr;
- ++ hdr_len = ieee80211_hdrlen(hdr->frame_control);
- ++ memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
- ++}
- ++
- ++static void ath10k_htt_rx_h_undecap(struct ath10k *ar,
- ++ struct sk_buff *msdu,
- ++ struct ieee80211_rx_status *status,
- ++ u8 first_hdr[64],
- ++ enum htt_rx_mpdu_encrypt_type enctype,
- ++ bool is_decrypted)
- ++{
- ++ struct htt_rx_desc *rxd;
- ++ enum rx_msdu_decap_format decap;
- ++ struct ieee80211_hdr *hdr;
- ++
- ++ /* First msdu's decapped header:
- ++ * [802.11 header] <-- padded to 4 bytes long
- ++ * [crypto param] <-- padded to 4 bytes long
- ++ * [amsdu header] <-- only if A-MSDU
- ++ * [rfc1042/llc]
- ++ *
- ++ * Other (2nd, 3rd, ..) msdu's decapped header:
- ++ * [amsdu header] <-- only if A-MSDU
- ++ * [rfc1042/llc]
- ++ */
- +
- +- skb->ip_summed = ath10k_htt_rx_get_csum_state(skb);
- ++ rxd = (void *)msdu->data - sizeof(*rxd);
- ++ hdr = (void *)rxd->rx_hdr_status;
- ++ decap = MS(__le32_to_cpu(rxd->msdu_start.info1),
- ++ RX_MSDU_START_INFO1_DECAP_FORMAT);
- +
- +- switch (fmt) {
- ++ switch (decap) {
- + case RX_MSDU_DECAP_RAW:
- +- /* remove trailing FCS */
- +- skb_trim(skb, skb->len - FCS_LEN);
- ++ ath10k_htt_rx_h_undecap_raw(ar, msdu, status, enctype,
- ++ is_decrypted);
- + break;
- + case RX_MSDU_DECAP_NATIVE_WIFI:
- +- /* Pull decapped header */
- +- hdr = (struct ieee80211_hdr *)skb->data;
- +- hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
- +- skb_pull(skb, hdr_len);
- +-
- +- /* Push original header */
- +- hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status;
- +- hdr_len = ieee80211_hdrlen(hdr->frame_control);
- +- memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
- ++ ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr);
- + break;
- + case RX_MSDU_DECAP_ETHERNET2_DIX:
- +- /* strip ethernet header and insert decapped 802.11 header and
- +- * rfc1042 header */
- +-
- +- rfc1042 = hdr;
- +- rfc1042 += roundup(hdr_len, 4);
- +- rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(enctype), 4);
- +-
- +- skb_pull(skb, sizeof(struct ethhdr));
- +- memcpy(skb_push(skb, sizeof(struct rfc1042_hdr)),
- +- rfc1042, sizeof(struct rfc1042_hdr));
- +- memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
- ++ ath10k_htt_rx_h_undecap_eth(ar, msdu, status, first_hdr, enctype);
- + break;
- + case RX_MSDU_DECAP_8023_SNAP_LLC:
- +- /* remove A-MSDU subframe header and insert
- +- * decapped 802.11 header. rfc1042 header is already there */
- +-
- +- skb_pull(skb, sizeof(struct amsdu_subframe_hdr));
- +- memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
- ++ ath10k_htt_rx_h_undecap_snap(ar, msdu, status, first_hdr);
- + break;
- + }
- +-
- +- ath10k_htt_rx_h_protected(htt, rx_status, skb, enctype);
- +-
- +- ath10k_process_rx(htt->ar, rx_status, skb);
- + }
- +
- + static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb)
- +@@ -1036,10 +1225,128 @@ static int ath10k_htt_rx_get_csum_state(
- + return CHECKSUM_UNNECESSARY;
- + }
- +
- +-static int ath10k_unchain_msdu(struct sk_buff *msdu_head)
- ++static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu)
- ++{
- ++ msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu);
- ++}
- ++
- ++static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
- ++ struct sk_buff_head *amsdu,
- ++ struct ieee80211_rx_status *status)
- ++{
- ++ struct sk_buff *first;
- ++ struct sk_buff *last;
- ++ struct sk_buff *msdu;
- ++ struct htt_rx_desc *rxd;
- ++ struct ieee80211_hdr *hdr;
- ++ enum htt_rx_mpdu_encrypt_type enctype;
- ++ u8 first_hdr[64];
- ++ u8 *qos;
- ++ size_t hdr_len;
- ++ bool has_fcs_err;
- ++ bool has_crypto_err;
- ++ bool has_tkip_err;
- ++ bool has_peer_idx_invalid;
- ++ bool is_decrypted;
- ++ u32 attention;
- ++
- ++ if (skb_queue_empty(amsdu))
- ++ return;
- ++
- ++ first = skb_peek(amsdu);
- ++ rxd = (void *)first->data - sizeof(*rxd);
- ++
- ++ enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
- ++ RX_MPDU_START_INFO0_ENCRYPT_TYPE);
- ++
- ++ /* First MSDU's Rx descriptor in an A-MSDU contains full 802.11
- ++ * decapped header. It'll be used for undecapping of each MSDU.
- ++ */
- ++ hdr = (void *)rxd->rx_hdr_status;
- ++ hdr_len = ieee80211_hdrlen(hdr->frame_control);
- ++ memcpy(first_hdr, hdr, hdr_len);
- ++
- ++ /* Each A-MSDU subframe will use the original header as the base and be
- ++ * reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl.
- ++ */
- ++ hdr = (void *)first_hdr;
- ++ qos = ieee80211_get_qos_ctl(hdr);
- ++ qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
- ++
- ++ /* Some attention flags are valid only in the last MSDU. */
- ++ last = skb_peek_tail(amsdu);
- ++ rxd = (void *)last->data - sizeof(*rxd);
- ++ attention = __le32_to_cpu(rxd->attention.flags);
- ++
- ++ has_fcs_err = !!(attention & RX_ATTENTION_FLAGS_FCS_ERR);
- ++ has_crypto_err = !!(attention & RX_ATTENTION_FLAGS_DECRYPT_ERR);
- ++ has_tkip_err = !!(attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR);
- ++ has_peer_idx_invalid = !!(attention & RX_ATTENTION_FLAGS_PEER_IDX_INVALID);
- ++
- ++ /* Note: If hardware captures an encrypted frame that it can't decrypt,
- ++ * e.g. due to fcs error, missing peer or invalid key data it will
- ++ * report the frame as raw.
- ++ */
- ++ is_decrypted = (enctype != HTT_RX_MPDU_ENCRYPT_NONE &&
- ++ !has_fcs_err &&
- ++ !has_crypto_err &&
- ++ !has_peer_idx_invalid);
- ++
- ++ /* Clear per-MPDU flags while leaving per-PPDU flags intact. */
- ++ status->flag &= ~(RX_FLAG_FAILED_FCS_CRC |
- ++ RX_FLAG_MMIC_ERROR |
- ++ RX_FLAG_DECRYPTED |
- ++ RX_FLAG_IV_STRIPPED |
- ++ RX_FLAG_MMIC_STRIPPED);
- ++
- ++ if (has_fcs_err)
- ++ status->flag |= RX_FLAG_FAILED_FCS_CRC;
- ++
- ++ if (has_tkip_err)
- ++ status->flag |= RX_FLAG_MMIC_ERROR;
- ++
- ++ if (is_decrypted)
- ++ status->flag |= RX_FLAG_DECRYPTED |
- ++ RX_FLAG_IV_STRIPPED |
- ++ RX_FLAG_MMIC_STRIPPED;
- ++
- ++ skb_queue_walk(amsdu, msdu) {
- ++ ath10k_htt_rx_h_csum_offload(msdu);
- ++ ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype,
- ++ is_decrypted);
- ++
- ++ /* Undecapping involves copying the original 802.11 header back
- ++ * to sk_buff. If frame is protected and hardware has decrypted
- ++ * it then remove the protected bit.
- ++ */
- ++ if (!is_decrypted)
- ++ continue;
- ++
- ++ hdr = (void *)msdu->data;
- ++ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- ++ }
- ++}
- ++
- ++static void ath10k_htt_rx_h_deliver(struct ath10k *ar,
- ++ struct sk_buff_head *amsdu,
- ++ struct ieee80211_rx_status *status)
- ++{
- ++ struct sk_buff *msdu;
- ++
- ++ while ((msdu = __skb_dequeue(amsdu))) {
- ++ /* Setup per-MSDU flags */
- ++ if (skb_queue_empty(amsdu))
- ++ status->flag &= ~RX_FLAG_AMSDU_MORE;
- ++ else
- ++ status->flag |= RX_FLAG_AMSDU_MORE;
- ++
- ++ ath10k_process_rx(ar, status, msdu);
- ++ }
- ++}
- ++
- ++static int ath10k_unchain_msdu(struct sk_buff_head *amsdu)
- + {
- +- struct sk_buff *next = msdu_head->next;
- +- struct sk_buff *to_free = next;
- ++ struct sk_buff *skb, *first;
- + int space;
- + int total_len = 0;
- +
- +@@ -1050,110 +1357,142 @@ static int ath10k_unchain_msdu(struct sk
- + * skb?
- + */
- +
- +- msdu_head->next = NULL;
- ++ first = __skb_dequeue(amsdu);
- +
- + /* Allocate total length all at once. */
- +- while (next) {
- +- total_len += next->len;
- +- next = next->next;
- +- }
- ++ skb_queue_walk(amsdu, skb)
- ++ total_len += skb->len;
- +
- +- space = total_len - skb_tailroom(msdu_head);
- ++ space = total_len - skb_tailroom(first);
- + if ((space > 0) &&
- +- (pskb_expand_head(msdu_head, 0, space, GFP_ATOMIC) < 0)) {
- ++ (pskb_expand_head(first, 0, space, GFP_ATOMIC) < 0)) {
- + /* TODO: bump some rx-oom error stat */
- + /* put it back together so we can free the
- + * whole list at once.
- + */
- +- msdu_head->next = to_free;
- ++ __skb_queue_head(amsdu, first);
- + return -1;
- + }
- +
- + /* Walk list again, copying contents into
- + * msdu_head
- + */
- +- next = to_free;
- +- while (next) {
- +- skb_copy_from_linear_data(next, skb_put(msdu_head, next->len),
- +- next->len);
- +- next = next->next;
- ++ while ((skb = __skb_dequeue(amsdu))) {
- ++ skb_copy_from_linear_data(skb, skb_put(first, skb->len),
- ++ skb->len);
- ++ dev_kfree_skb_any(skb);
- + }
- +
- +- /* If here, we have consolidated skb. Free the
- +- * fragments and pass the main skb on up the
- +- * stack.
- +- */
- +- ath10k_htt_rx_free_msdu_chain(to_free);
- ++ __skb_queue_head(amsdu, first);
- + return 0;
- + }
- +
- +-static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt,
- +- struct sk_buff *head,
- +- enum htt_rx_mpdu_status status,
- +- bool channel_set,
- +- u32 attention)
- +-{
- +- if (head->len == 0) {
- +- ath10k_dbg(ATH10K_DBG_HTT,
- +- "htt rx dropping due to zero-len\n");
- +- return false;
- +- }
- ++static void ath10k_htt_rx_h_unchain(struct ath10k *ar,
- ++ struct sk_buff_head *amsdu,
- ++ bool chained)
- ++{
- ++ struct sk_buff *first;
- ++ struct htt_rx_desc *rxd;
- ++ enum rx_msdu_decap_format decap;
- +
- +- if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) {
- +- ath10k_dbg(ATH10K_DBG_HTT,
- +- "htt rx dropping due to decrypt-err\n");
- +- return false;
- +- }
- ++ first = skb_peek(amsdu);
- ++ rxd = (void *)first->data - sizeof(*rxd);
- ++ decap = MS(__le32_to_cpu(rxd->msdu_start.info1),
- ++ RX_MSDU_START_INFO1_DECAP_FORMAT);
- +
- +- if (!channel_set) {
- +- ath10k_warn("no channel configured; ignoring frame!\n");
- +- return false;
- ++ if (!chained)
- ++ return;
- ++
- ++ /* FIXME: Current unchaining logic can only handle simple case of raw
- ++ * msdu chaining. If decapping is other than raw the chaining may be
- ++ * more complex and this isn't handled by the current code. Don't even
- ++ * try re-constructing such frames - it'll be pretty much garbage.
- ++ */
- ++ if (decap != RX_MSDU_DECAP_RAW ||
- ++ skb_queue_len(amsdu) != 1 + rxd->frag_info.ring2_more_count) {
- ++ __skb_queue_purge(amsdu);
- ++ return;
- + }
- +
- +- /* Skip mgmt frames while we handle this in WMI */
- +- if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL ||
- +- attention & RX_ATTENTION_FLAGS_MGMT_TYPE) {
- +- ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
- ++ ath10k_unchain_msdu(amsdu);
- ++}
- ++
- ++static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
- ++ struct sk_buff_head *amsdu,
- ++ struct ieee80211_rx_status *rx_status)
- ++{
- ++ struct sk_buff *msdu;
- ++ struct htt_rx_desc *rxd;
- ++ bool is_mgmt;
- ++ bool has_fcs_err;
- ++
- ++ msdu = skb_peek(amsdu);
- ++ rxd = (void *)msdu->data - sizeof(*rxd);
- ++
- ++ /* FIXME: It might be a good idea to do some fuzzy-testing to drop
- ++ * invalid/dangerous frames.
- ++ */
- ++
- ++ if (!rx_status->freq) {
- ++ ath10k_warn(ar, "no channel configured; ignoring frame(s)!\n");
- + return false;
- + }
- +
- +- if (status != HTT_RX_IND_MPDU_STATUS_OK &&
- +- status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
- +- status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
- +- !htt->ar->monitor_started) {
- +- ath10k_dbg(ATH10K_DBG_HTT,
- +- "htt rx ignoring frame w/ status %d\n",
- +- status);
- ++ is_mgmt = !!(rxd->attention.flags &
- ++ __cpu_to_le32(RX_ATTENTION_FLAGS_MGMT_TYPE));
- ++ has_fcs_err = !!(rxd->attention.flags &
- ++ __cpu_to_le32(RX_ATTENTION_FLAGS_FCS_ERR));
- ++
- ++ /* Management frames are handled via WMI events. The pros of such
- ++ * approach is that channel is explicitly provided in WMI events
- ++ * whereas HTT doesn't provide channel information for Rxed frames.
- ++ *
- ++ * However some firmware revisions don't report corrupted frames via
- ++ * WMI so don't drop them.
- ++ */
- ++ if (is_mgmt && !has_fcs_err) {
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
- + return false;
- + }
- +
- +- if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
- +- ath10k_dbg(ATH10K_DBG_HTT,
- +- "htt rx CAC running\n");
- ++ if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) {
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx cac running\n");
- + return false;
- + }
- +
- + return true;
- + }
- +
- ++static void ath10k_htt_rx_h_filter(struct ath10k *ar,
- ++ struct sk_buff_head *amsdu,
- ++ struct ieee80211_rx_status *rx_status)
- ++{
- ++ if (skb_queue_empty(amsdu))
- ++ return;
- ++
- ++ if (ath10k_htt_rx_amsdu_allowed(ar, amsdu, rx_status))
- ++ return;
- ++
- ++ __skb_queue_purge(amsdu);
- ++}
- ++
- + static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
- + struct htt_rx_indication *rx)
- + {
- ++ struct ath10k *ar = htt->ar;
- + struct ieee80211_rx_status *rx_status = &htt->rx_status;
- + struct htt_rx_indication_mpdu_range *mpdu_ranges;
- +- struct htt_rx_desc *rxd;
- +- enum htt_rx_mpdu_status status;
- +- struct ieee80211_hdr *hdr;
- ++ struct sk_buff_head amsdu;
- + int num_mpdu_ranges;
- +- u32 attention;
- + int fw_desc_len;
- + u8 *fw_desc;
- +- bool channel_set;
- +- int i, j;
- +- int ret;
- ++ int i, ret, mpdu_count = 0;
- +
- + lockdep_assert_held(&htt->rx_ring.lock);
- +
- ++ if (htt->rx_confused)
- ++ return;
- ++
- + fw_desc_len = __le16_to_cpu(rx->prefix.fw_rx_desc_bytes);
- + fw_desc = (u8 *)&rx->fw_desc;
- +
- +@@ -1161,201 +1500,82 @@ static void ath10k_htt_rx_handler(struct
- + HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
- + mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx);
- +
- +- /* Fill this once, while this is per-ppdu */
- +- if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_START_VALID) {
- +- memset(rx_status, 0, sizeof(*rx_status));
- +- rx_status->signal = ATH10K_DEFAULT_NOISE_FLOOR +
- +- rx->ppdu.combined_rssi;
- +- }
- +-
- +- if (rx->ppdu.info0 & HTT_RX_INDICATION_INFO0_END_VALID) {
- +- /* TSF available only in 32-bit */
- +- rx_status->mactime = __le32_to_cpu(rx->ppdu.tsf) & 0xffffffff;
- +- rx_status->flag |= RX_FLAG_MACTIME_END;
- +- }
- +-
- +- channel_set = ath10k_htt_rx_h_channel(htt->ar, rx_status);
- +-
- +- if (channel_set) {
- +- ath10k_htt_rx_h_rates(htt->ar, rx_status->band,
- +- rx->ppdu.info0,
- +- __le32_to_cpu(rx->ppdu.info1),
- +- __le32_to_cpu(rx->ppdu.info2),
- +- rx_status);
- +- }
- +-
- +- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
- + rx, sizeof(*rx) +
- + (sizeof(struct htt_rx_indication_mpdu_range) *
- + num_mpdu_ranges));
- +
- +- for (i = 0; i < num_mpdu_ranges; i++) {
- +- status = mpdu_ranges[i].mpdu_range_status;
- +-
- +- for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) {
- +- struct sk_buff *msdu_head, *msdu_tail;
- ++ for (i = 0; i < num_mpdu_ranges; i++)
- ++ mpdu_count += mpdu_ranges[i].mpdu_count;
- +
- +- msdu_head = NULL;
- +- msdu_tail = NULL;
- +- ret = ath10k_htt_rx_amsdu_pop(htt,
- +- &fw_desc,
- +- &fw_desc_len,
- +- &msdu_head,
- +- &msdu_tail);
- +-
- +- if (ret < 0) {
- +- ath10k_warn("failed to pop amsdu from htt rx ring %d\n",
- +- ret);
- +- ath10k_htt_rx_free_msdu_chain(msdu_head);
- +- continue;
- +- }
- +-
- +- rxd = container_of((void *)msdu_head->data,
- +- struct htt_rx_desc,
- +- msdu_payload);
- +- attention = __le32_to_cpu(rxd->attention.flags);
- +-
- +- if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head,
- +- status,
- +- channel_set,
- +- attention)) {
- +- ath10k_htt_rx_free_msdu_chain(msdu_head);
- +- continue;
- +- }
- +-
- +- if (ret > 0 &&
- +- ath10k_unchain_msdu(msdu_head) < 0) {
- +- ath10k_htt_rx_free_msdu_chain(msdu_head);
- +- continue;
- +- }
- +-
- +- if (attention & RX_ATTENTION_FLAGS_FCS_ERR)
- +- rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
- +- else
- +- rx_status->flag &= ~RX_FLAG_FAILED_FCS_CRC;
- +-
- +- if (attention & RX_ATTENTION_FLAGS_TKIP_MIC_ERR)
- +- rx_status->flag |= RX_FLAG_MMIC_ERROR;
- +- else
- +- rx_status->flag &= ~RX_FLAG_MMIC_ERROR;
- +-
- +- hdr = ath10k_htt_rx_skb_get_hdr(msdu_head);
- +-
- +- if (ath10k_htt_rx_hdr_is_amsdu(hdr))
- +- ath10k_htt_rx_amsdu(htt, rx_status, msdu_head);
- +- else
- +- ath10k_htt_rx_msdu(htt, rx_status, msdu_head);
- ++ while (mpdu_count--) {
- ++ __skb_queue_head_init(&amsdu);
- ++ ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc,
- ++ &fw_desc_len, &amsdu);
- ++ if (ret < 0) {
- ++ ath10k_warn(ar, "rx ring became corrupted: %d\n", ret);
- ++ __skb_queue_purge(&amsdu);
- ++ /* FIXME: It's probably a good idea to reboot the
- ++ * device instead of leaving it inoperable.
- ++ */
- ++ htt->rx_confused = true;
- ++ break;
- + }
- ++
- ++ ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status);
- ++ ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
- ++ ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
- ++ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
- ++ ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
- + }
- +
- + tasklet_schedule(&htt->rx_replenish_task);
- + }
- +
- + static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
- +- struct htt_rx_fragment_indication *frag)
- ++ struct htt_rx_fragment_indication *frag)
- + {
- +- struct sk_buff *msdu_head, *msdu_tail;
- +- enum htt_rx_mpdu_encrypt_type enctype;
- +- struct htt_rx_desc *rxd;
- +- enum rx_msdu_decap_format fmt;
- ++ struct ath10k *ar = htt->ar;
- + struct ieee80211_rx_status *rx_status = &htt->rx_status;
- +- struct ieee80211_hdr *hdr;
- ++ struct sk_buff_head amsdu;
- + int ret;
- +- bool tkip_mic_err;
- +- bool decrypt_err;
- + u8 *fw_desc;
- +- int fw_desc_len, hdrlen, paramlen;
- +- int trim;
- ++ int fw_desc_len;
- +
- + fw_desc_len = __le16_to_cpu(frag->fw_rx_desc_bytes);
- + fw_desc = (u8 *)frag->fw_msdu_rx_desc;
- +
- +- msdu_head = NULL;
- +- msdu_tail = NULL;
- ++ __skb_queue_head_init(&amsdu);
- +
- + spin_lock_bh(&htt->rx_ring.lock);
- + ret = ath10k_htt_rx_amsdu_pop(htt, &fw_desc, &fw_desc_len,
- +- &msdu_head, &msdu_tail);
- ++ &amsdu);
- + spin_unlock_bh(&htt->rx_ring.lock);
- +
- +- ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
- ++ tasklet_schedule(&htt->rx_replenish_task);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
- +
- + if (ret) {
- +- ath10k_warn("failed to pop amsdu from httr rx ring for fragmented rx %d\n",
- ++ ath10k_warn(ar, "failed to pop amsdu from httr rx ring for fragmented rx %d\n",
- + ret);
- +- ath10k_htt_rx_free_msdu_chain(msdu_head);
- ++ __skb_queue_purge(&amsdu);
- + return;
- + }
- +
- +- /* FIXME: implement signal strength */
- +-
- +- hdr = (struct ieee80211_hdr *)msdu_head->data;
- +- rxd = (void *)msdu_head->data - sizeof(*rxd);
- +- tkip_mic_err = !!(__le32_to_cpu(rxd->attention.flags) &
- +- RX_ATTENTION_FLAGS_TKIP_MIC_ERR);
- +- decrypt_err = !!(__le32_to_cpu(rxd->attention.flags) &
- +- RX_ATTENTION_FLAGS_DECRYPT_ERR);
- +- fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
- +- RX_MSDU_START_INFO1_DECAP_FORMAT);
- +-
- +- if (fmt != RX_MSDU_DECAP_RAW) {
- +- ath10k_warn("we dont support non-raw fragmented rx yet\n");
- +- dev_kfree_skb_any(msdu_head);
- +- goto end;
- +- }
- +-
- +- enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
- +- RX_MPDU_START_INFO0_ENCRYPT_TYPE);
- +- ath10k_htt_rx_h_protected(htt, rx_status, msdu_head, enctype);
- +- msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head);
- +-
- +- if (tkip_mic_err)
- +- ath10k_warn("tkip mic error\n");
- +-
- +- if (decrypt_err) {
- +- ath10k_warn("decryption err in fragmented rx\n");
- +- dev_kfree_skb_any(msdu_head);
- +- goto end;
- +- }
- +-
- +- if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) {
- +- hdrlen = ieee80211_hdrlen(hdr->frame_control);
- +- paramlen = ath10k_htt_rx_crypto_param_len(enctype);
- +-
- +- /* It is more efficient to move the header than the payload */
- +- memmove((void *)msdu_head->data + paramlen,
- +- (void *)msdu_head->data,
- +- hdrlen);
- +- skb_pull(msdu_head, paramlen);
- +- hdr = (struct ieee80211_hdr *)msdu_head->data;
- +- }
- +-
- +- /* remove trailing FCS */
- +- trim = 4;
- +-
- +- /* remove crypto trailer */
- +- trim += ath10k_htt_rx_crypto_tail_len(enctype);
- +-
- +- /* last fragment of TKIP frags has MIC */
- +- if (!ieee80211_has_morefrags(hdr->frame_control) &&
- +- enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA)
- +- trim += 8;
- +-
- +- if (trim > msdu_head->len) {
- +- ath10k_warn("htt rx fragment: trailer longer than the frame itself? drop\n");
- +- dev_kfree_skb_any(msdu_head);
- +- goto end;
- ++ if (skb_queue_len(&amsdu) != 1) {
- ++ ath10k_warn(ar, "failed to pop frag amsdu: too many msdus\n");
- ++ __skb_queue_purge(&amsdu);
- ++ return;
- + }
- +
- +- skb_trim(msdu_head, msdu_head->len - trim);
- +-
- +- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
- +- msdu_head->data, msdu_head->len);
- +- ath10k_process_rx(htt->ar, rx_status, msdu_head);
- ++ ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status);
- ++ ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
- ++ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
- ++ ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
- +
- +-end:
- + if (fw_desc_len > 0) {
- +- ath10k_dbg(ATH10K_DBG_HTT,
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT,
- + "expecting more fragmented rx in one indication %d\n",
- + fw_desc_len);
- + }
- +@@ -1385,12 +1605,12 @@ static void ath10k_htt_rx_frm_tx_compl(s
- + tx_done.discard = true;
- + break;
- + default:
- +- ath10k_warn("unhandled tx completion status %d\n", status);
- ++ ath10k_warn(ar, "unhandled tx completion status %d\n", status);
- + tx_done.discard = true;
- + break;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
- + resp->data_tx_completion.num_msdus);
- +
- + for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
- +@@ -1400,6 +1620,274 @@ static void ath10k_htt_rx_frm_tx_compl(s
- + }
- + }
- +
- ++static void ath10k_htt_rx_addba(struct ath10k *ar, struct htt_resp *resp)
- ++{
- ++ struct htt_rx_addba *ev = &resp->rx_addba;
- ++ struct ath10k_peer *peer;
- ++ struct ath10k_vif *arvif;
- ++ u16 info0, tid, peer_id;
- ++
- ++ info0 = __le16_to_cpu(ev->info0);
- ++ tid = MS(info0, HTT_RX_BA_INFO0_TID);
- ++ peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT,
- ++ "htt rx addba tid %hu peer_id %hu size %hhu\n",
- ++ tid, peer_id, ev->window_size);
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++ peer = ath10k_peer_find_by_id(ar, peer_id);
- ++ if (!peer) {
- ++ ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n",
- ++ peer_id);
- ++ spin_unlock_bh(&ar->data_lock);
- ++ return;
- ++ }
- ++
- ++ arvif = ath10k_get_arvif(ar, peer->vdev_id);
- ++ if (!arvif) {
- ++ ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n",
- ++ peer->vdev_id);
- ++ spin_unlock_bh(&ar->data_lock);
- ++ return;
- ++ }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT,
- ++ "htt rx start rx ba session sta %pM tid %hu size %hhu\n",
- ++ peer->addr, tid, ev->window_size);
- ++
- ++ ieee80211_start_rx_ba_session_offl(arvif->vif, peer->addr, tid);
- ++ spin_unlock_bh(&ar->data_lock);
- ++}
- ++
- ++static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp)
- ++{
- ++ struct htt_rx_delba *ev = &resp->rx_delba;
- ++ struct ath10k_peer *peer;
- ++ struct ath10k_vif *arvif;
- ++ u16 info0, tid, peer_id;
- ++
- ++ info0 = __le16_to_cpu(ev->info0);
- ++ tid = MS(info0, HTT_RX_BA_INFO0_TID);
- ++ peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT,
- ++ "htt rx delba tid %hu peer_id %hu\n",
- ++ tid, peer_id);
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++ peer = ath10k_peer_find_by_id(ar, peer_id);
- ++ if (!peer) {
- ++ ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n",
- ++ peer_id);
- ++ spin_unlock_bh(&ar->data_lock);
- ++ return;
- ++ }
- ++
- ++ arvif = ath10k_get_arvif(ar, peer->vdev_id);
- ++ if (!arvif) {
- ++ ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n",
- ++ peer->vdev_id);
- ++ spin_unlock_bh(&ar->data_lock);
- ++ return;
- ++ }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT,
- ++ "htt rx stop rx ba session sta %pM tid %hu\n",
- ++ peer->addr, tid);
- ++
- ++ ieee80211_stop_rx_ba_session_offl(arvif->vif, peer->addr, tid);
- ++ spin_unlock_bh(&ar->data_lock);
- ++}
- ++
- ++static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list,
- ++ struct sk_buff_head *amsdu)
- ++{
- ++ struct sk_buff *msdu;
- ++ struct htt_rx_desc *rxd;
- ++
- ++ if (skb_queue_empty(list))
- ++ return -ENOBUFS;
- ++
- ++ if (WARN_ON(!skb_queue_empty(amsdu)))
- ++ return -EINVAL;
- ++
- ++ while ((msdu = __skb_dequeue(list))) {
- ++ __skb_queue_tail(amsdu, msdu);
- ++
- ++ rxd = (void *)msdu->data - sizeof(*rxd);
- ++ if (rxd->msdu_end.info0 &
- ++ __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU))
- ++ break;
- ++ }
- ++
- ++ msdu = skb_peek_tail(amsdu);
- ++ rxd = (void *)msdu->data - sizeof(*rxd);
- ++ if (!(rxd->msdu_end.info0 &
- ++ __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU))) {
- ++ skb_queue_splice_init(amsdu, list);
- ++ return -EAGAIN;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- ++static void ath10k_htt_rx_h_rx_offload_prot(struct ieee80211_rx_status *status,
- ++ struct sk_buff *skb)
- ++{
- ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- ++
- ++ if (!ieee80211_has_protected(hdr->frame_control))
- ++ return;
- ++
- ++ /* Offloaded frames are already decrypted but firmware insists they are
- ++ * protected in the 802.11 header. Strip the flag. Otherwise mac80211
- ++ * will drop the frame.
- ++ */
- ++
- ++ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- ++ status->flag |= RX_FLAG_DECRYPTED |
- ++ RX_FLAG_IV_STRIPPED |
- ++ RX_FLAG_MMIC_STRIPPED;
- ++}
- ++
- ++static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
- ++ struct sk_buff_head *list)
- ++{
- ++ struct ath10k_htt *htt = &ar->htt;
- ++ struct ieee80211_rx_status *status = &htt->rx_status;
- ++ struct htt_rx_offload_msdu *rx;
- ++ struct sk_buff *msdu;
- ++ size_t offset;
- ++
- ++ while ((msdu = __skb_dequeue(list))) {
- ++ /* Offloaded frames don't have Rx descriptor. Instead they have
- ++ * a short meta information header.
- ++ */
- ++
- ++ rx = (void *)msdu->data;
- ++
- ++ skb_put(msdu, sizeof(*rx));
- ++ skb_pull(msdu, sizeof(*rx));
- ++
- ++ if (skb_tailroom(msdu) < __le16_to_cpu(rx->msdu_len)) {
- ++ ath10k_warn(ar, "dropping frame: offloaded rx msdu is too long!\n");
- ++ dev_kfree_skb_any(msdu);
- ++ continue;
- ++ }
- ++
- ++ skb_put(msdu, __le16_to_cpu(rx->msdu_len));
- ++
- ++ /* Offloaded rx header length isn't multiple of 2 nor 4 so the
- ++ * actual payload is unaligned. Align the frame. Otherwise
- ++ * mac80211 complains. This shouldn't reduce performance much
- ++ * because these offloaded frames are rare.
- ++ */
- ++ offset = 4 - ((unsigned long)msdu->data & 3);
- ++ skb_put(msdu, offset);
- ++ memmove(msdu->data + offset, msdu->data, msdu->len);
- ++ skb_pull(msdu, offset);
- ++
- ++ /* FIXME: The frame is NWifi. Re-construct QoS Control
- ++ * if possible later.
- ++ */
- ++
- ++ memset(status, 0, sizeof(*status));
- ++ status->flag |= RX_FLAG_NO_SIGNAL_VAL;
- ++
- ++ ath10k_htt_rx_h_rx_offload_prot(status, msdu);
- ++ ath10k_htt_rx_h_channel(ar, status);
- ++ ath10k_process_rx(ar, status, msdu);
- ++ }
- ++}
- ++
- ++static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
- ++{
- ++ struct ath10k_htt *htt = &ar->htt;
- ++ struct htt_resp *resp = (void *)skb->data;
- ++ struct ieee80211_rx_status *status = &htt->rx_status;
- ++ struct sk_buff_head list;
- ++ struct sk_buff_head amsdu;
- ++ u16 peer_id;
- ++ u16 msdu_count;
- ++ u8 vdev_id;
- ++ u8 tid;
- ++ bool offload;
- ++ bool frag;
- ++ int ret;
- ++
- ++ lockdep_assert_held(&htt->rx_ring.lock);
- ++
- ++ if (htt->rx_confused)
- ++ return;
- ++
- ++ skb_pull(skb, sizeof(resp->hdr));
- ++ skb_pull(skb, sizeof(resp->rx_in_ord_ind));
- ++
- ++ peer_id = __le16_to_cpu(resp->rx_in_ord_ind.peer_id);
- ++ msdu_count = __le16_to_cpu(resp->rx_in_ord_ind.msdu_count);
- ++ vdev_id = resp->rx_in_ord_ind.vdev_id;
- ++ tid = SM(resp->rx_in_ord_ind.info, HTT_RX_IN_ORD_IND_INFO_TID);
- ++ offload = !!(resp->rx_in_ord_ind.info &
- ++ HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK);
- ++ frag = !!(resp->rx_in_ord_ind.info & HTT_RX_IN_ORD_IND_INFO_FRAG_MASK);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT,
- ++ "htt rx in ord vdev %i peer %i tid %i offload %i frag %i msdu count %i\n",
- ++ vdev_id, peer_id, tid, offload, frag, msdu_count);
- ++
- ++ if (skb->len < msdu_count * sizeof(*resp->rx_in_ord_ind.msdu_descs)) {
- ++ ath10k_warn(ar, "dropping invalid in order rx indication\n");
- ++ return;
- ++ }
- ++
- ++ /* The event can deliver more than 1 A-MSDU. Each A-MSDU is later
- ++ * extracted and processed.
- ++ */
- ++ __skb_queue_head_init(&list);
- ++ ret = ath10k_htt_rx_pop_paddr_list(htt, &resp->rx_in_ord_ind, &list);
- ++ if (ret < 0) {
- ++ ath10k_warn(ar, "failed to pop paddr list: %d\n", ret);
- ++ htt->rx_confused = true;
- ++ return;
- ++ }
- ++
- ++ /* Offloaded frames are very different and need to be handled
- ++ * separately.
- ++ */
- ++ if (offload)
- ++ ath10k_htt_rx_h_rx_offload(ar, &list);
- ++
- ++ while (!skb_queue_empty(&list)) {
- ++ __skb_queue_head_init(&amsdu);
- ++ ret = ath10k_htt_rx_extract_amsdu(&list, &amsdu);
- ++ switch (ret) {
- ++ case 0:
- ++ /* Note: The in-order indication may report interleaved
- ++ * frames from different PPDUs meaning reported rx rate
- ++ * to mac80211 isn't accurate/reliable. It's still
- ++ * better to report something than nothing though. This
- ++ * should still give an idea about rx rate to the user.
- ++ */
- ++ ath10k_htt_rx_h_ppdu(ar, &amsdu, status);
- ++ ath10k_htt_rx_h_filter(ar, &amsdu, status);
- ++ ath10k_htt_rx_h_mpdu(ar, &amsdu, status);
- ++ ath10k_htt_rx_h_deliver(ar, &amsdu, status);
- ++ break;
- ++ case -EAGAIN:
- ++ /* fall through */
- ++ default:
- ++ /* Should not happen. */
- ++ ath10k_warn(ar, "failed to extract amsdu: %d\n", ret);
- ++ htt->rx_confused = true;
- ++ __skb_queue_purge(&list);
- ++ return;
- ++ }
- ++ }
- ++
- ++ tasklet_schedule(&htt->rx_replenish_task);
- ++}
- ++
- + void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
- + {
- + struct ath10k_htt *htt = &ar->htt;
- +@@ -1407,9 +1895,9 @@ void ath10k_htt_t2h_msg_handler(struct a
- +
- + /* confirm alignment */
- + if (!IS_ALIGNED((unsigned long)skb->data, 4))
- +- ath10k_warn("unaligned htt message, expect trouble\n");
- ++ ath10k_warn(ar, "unaligned htt message, expect trouble\n");
- +
- +- ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
- + resp->hdr.msg_type);
- + switch (resp->hdr.msg_type) {
- + case HTT_T2H_MSG_TYPE_VERSION_CONF: {
- +@@ -1473,7 +1961,7 @@ void ath10k_htt_t2h_msg_handler(struct a
- + struct ath10k *ar = htt->ar;
- + struct htt_security_indication *ev = &resp->security_indication;
- +
- +- ath10k_dbg(ATH10K_DBG_HTT,
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT,
- + "sec ind peer_id %d unicast %d type %d\n",
- + __le16_to_cpu(ev->peer_id),
- + !!(ev->flags & HTT_SECURITY_IS_UNICAST),
- +@@ -1482,7 +1970,7 @@ void ath10k_htt_t2h_msg_handler(struct a
- + break;
- + }
- + case HTT_T2H_MSG_TYPE_RX_FRAG_IND: {
- +- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
- + skb->data, skb->len);
- + ath10k_htt_rx_frag_handler(htt, &resp->rx_frag_ind);
- + break;
- +@@ -1491,16 +1979,55 @@ void ath10k_htt_t2h_msg_handler(struct a
- + /* FIX THIS */
- + break;
- + case HTT_T2H_MSG_TYPE_STATS_CONF:
- +- trace_ath10k_htt_stats(skb->data, skb->len);
- ++ trace_ath10k_htt_stats(ar, skb->data, skb->len);
- + break;
- + case HTT_T2H_MSG_TYPE_TX_INSPECT_IND:
- ++ /* Firmware can return tx frames if it's unable to fully
- ++ * process them and suspects host may be able to fix it. ath10k
- ++ * sends all tx frames as already inspected so this shouldn't
- ++ * happen unless fw has a bug.
- ++ */
- ++ ath10k_warn(ar, "received an unexpected htt tx inspect event\n");
- ++ break;
- + case HTT_T2H_MSG_TYPE_RX_ADDBA:
- ++ ath10k_htt_rx_addba(ar, resp);
- ++ break;
- + case HTT_T2H_MSG_TYPE_RX_DELBA:
- +- case HTT_T2H_MSG_TYPE_RX_FLUSH:
- ++ ath10k_htt_rx_delba(ar, resp);
- ++ break;
- ++ case HTT_T2H_MSG_TYPE_PKTLOG: {
- ++ struct ath10k_pktlog_hdr *hdr =
- ++ (struct ath10k_pktlog_hdr *)resp->pktlog_msg.payload;
- ++
- ++ trace_ath10k_htt_pktlog(ar, resp->pktlog_msg.payload,
- ++ sizeof(*hdr) +
- ++ __le16_to_cpu(hdr->size));
- ++ break;
- ++ }
- ++ case HTT_T2H_MSG_TYPE_RX_FLUSH: {
- ++ /* Ignore this event because mac80211 takes care of Rx
- ++ * aggregation reordering.
- ++ */
- ++ break;
- ++ }
- ++ case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: {
- ++ spin_lock_bh(&htt->rx_ring.lock);
- ++ __skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
- ++ spin_unlock_bh(&htt->rx_ring.lock);
- ++ tasklet_schedule(&htt->txrx_compl_task);
- ++ return;
- ++ }
- ++ case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
- ++ /* FIXME: This WMI-TLV event is overlapping with 10.2
- ++ * CHAN_CHANGE - both being 0xF. Neither is being used in
- ++ * practice so no immediate action is necessary. Nevertheless
- ++ * HTT may need an abstraction layer like WMI has one day.
- ++ */
- ++ break;
- + default:
- +- ath10k_dbg(ATH10K_DBG_HTT, "htt event (%d) not handled\n",
- +- resp->hdr.msg_type);
- +- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
- ++ ath10k_warn(ar, "htt event (%d) not handled\n",
- ++ resp->hdr.msg_type);
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
- + skb->data, skb->len);
- + break;
- + };
- +@@ -1512,6 +2039,7 @@ void ath10k_htt_t2h_msg_handler(struct a
- + static void ath10k_htt_txrx_compl_task(unsigned long ptr)
- + {
- + struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
- ++ struct ath10k *ar = htt->ar;
- + struct htt_resp *resp;
- + struct sk_buff *skb;
- +
- +@@ -1528,5 +2056,10 @@ static void ath10k_htt_txrx_compl_task(u
- + ath10k_htt_rx_handler(htt, &resp->rx_ind);
- + dev_kfree_skb_any(skb);
- + }
- ++
- ++ while ((skb = __skb_dequeue(&htt->rx_in_ord_compl_q))) {
- ++ ath10k_htt_rx_in_ord_ind(ar, skb);
- ++ dev_kfree_skb_any(skb);
- ++ }
- + spin_unlock_bh(&htt->rx_ring.lock);
- + }
- +--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
- ++++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
- +@@ -56,98 +56,74 @@ exit:
- + return ret;
- + }
- +
- +-int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt)
- ++int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb)
- + {
- +- int msdu_id;
- ++ struct ath10k *ar = htt->ar;
- ++ int ret;
- +
- + lockdep_assert_held(&htt->tx_lock);
- +
- +- msdu_id = find_first_zero_bit(htt->used_msdu_ids,
- +- htt->max_num_pending_tx);
- +- if (msdu_id == htt->max_num_pending_tx)
- +- return -ENOBUFS;
- +-
- +- ath10k_dbg(ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id);
- +- __set_bit(msdu_id, htt->used_msdu_ids);
- +- return msdu_id;
- ++ ret = idr_alloc(&htt->pending_tx, skb, 0, 0x10000, GFP_ATOMIC);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", ret);
- ++
- ++ return ret;
- + }
- +
- + void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)
- + {
- ++ struct ath10k *ar = htt->ar;
- ++
- + lockdep_assert_held(&htt->tx_lock);
- +
- +- if (!test_bit(msdu_id, htt->used_msdu_ids))
- +- ath10k_warn("trying to free unallocated msdu_id %d\n", msdu_id);
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id);
- +
- +- ath10k_dbg(ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id);
- +- __clear_bit(msdu_id, htt->used_msdu_ids);
- ++ idr_remove(&htt->pending_tx, msdu_id);
- + }
- +
- +-int ath10k_htt_tx_attach(struct ath10k_htt *htt)
- ++int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
- + {
- +- spin_lock_init(&htt->tx_lock);
- +- init_waitqueue_head(&htt->empty_tx_wq);
- +-
- +- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, htt->ar->fw_features))
- +- htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
- +- else
- +- htt->max_num_pending_tx = TARGET_NUM_MSDU_DESC;
- ++ struct ath10k *ar = htt->ar;
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
- + htt->max_num_pending_tx);
- +
- +- htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) *
- +- htt->max_num_pending_tx, GFP_KERNEL);
- +- if (!htt->pending_tx)
- +- return -ENOMEM;
- +-
- +- htt->used_msdu_ids = kzalloc(sizeof(unsigned long) *
- +- BITS_TO_LONGS(htt->max_num_pending_tx),
- +- GFP_KERNEL);
- +- if (!htt->used_msdu_ids) {
- +- kfree(htt->pending_tx);
- +- return -ENOMEM;
- +- }
- ++ spin_lock_init(&htt->tx_lock);
- ++ idr_init(&htt->pending_tx);
- +
- + htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev,
- + sizeof(struct ath10k_htt_txbuf), 4, 0);
- + if (!htt->tx_pool) {
- +- kfree(htt->used_msdu_ids);
- +- kfree(htt->pending_tx);
- ++ idr_destroy(&htt->pending_tx);
- + return -ENOMEM;
- + }
- +
- + return 0;
- + }
- +
- +-static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
- ++static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx)
- + {
- ++ struct ath10k *ar = ctx;
- ++ struct ath10k_htt *htt = &ar->htt;
- + struct htt_tx_done tx_done = {0};
- +- int msdu_id;
- +-
- +- spin_lock_bh(&htt->tx_lock);
- +- for (msdu_id = 0; msdu_id < htt->max_num_pending_tx; msdu_id++) {
- +- if (!test_bit(msdu_id, htt->used_msdu_ids))
- +- continue;
- +
- +- ath10k_dbg(ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n",
- +- msdu_id);
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n", msdu_id);
- +
- +- tx_done.discard = 1;
- +- tx_done.msdu_id = msdu_id;
- ++ tx_done.discard = 1;
- ++ tx_done.msdu_id = msdu_id;
- +
- +- ath10k_txrx_tx_unref(htt, &tx_done);
- +- }
- ++ spin_lock_bh(&htt->tx_lock);
- ++ ath10k_txrx_tx_unref(htt, &tx_done);
- + spin_unlock_bh(&htt->tx_lock);
- ++
- ++ return 0;
- + }
- +
- +-void ath10k_htt_tx_detach(struct ath10k_htt *htt)
- ++void ath10k_htt_tx_free(struct ath10k_htt *htt)
- + {
- +- ath10k_htt_tx_cleanup_pending(htt);
- +- kfree(htt->pending_tx);
- +- kfree(htt->used_msdu_ids);
- ++ idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
- ++ idr_destroy(&htt->pending_tx);
- + dma_pool_destroy(htt->tx_pool);
- +- return;
- + }
- +
- + void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
- +@@ -157,6 +133,7 @@ void ath10k_htt_htc_tx_complete(struct a
- +
- + int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
- + {
- ++ struct ath10k *ar = htt->ar;
- + struct sk_buff *skb;
- + struct htt_cmd *cmd;
- + int len = 0;
- +@@ -165,7 +142,7 @@ int ath10k_htt_h2t_ver_req_msg(struct at
- + len += sizeof(cmd->hdr);
- + len += sizeof(cmd->ver_req);
- +
- +- skb = ath10k_htc_alloc_skb(len);
- ++ skb = ath10k_htc_alloc_skb(ar, len);
- + if (!skb)
- + return -ENOMEM;
- +
- +@@ -184,6 +161,7 @@ int ath10k_htt_h2t_ver_req_msg(struct at
- +
- + int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
- + {
- ++ struct ath10k *ar = htt->ar;
- + struct htt_stats_req *req;
- + struct sk_buff *skb;
- + struct htt_cmd *cmd;
- +@@ -192,7 +170,7 @@ int ath10k_htt_h2t_stats_req(struct ath1
- + len += sizeof(cmd->hdr);
- + len += sizeof(cmd->stats_req);
- +
- +- skb = ath10k_htc_alloc_skb(len);
- ++ skb = ath10k_htc_alloc_skb(ar, len);
- + if (!skb)
- + return -ENOMEM;
- +
- +@@ -214,7 +192,8 @@ int ath10k_htt_h2t_stats_req(struct ath1
- +
- + ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
- + if (ret) {
- +- ath10k_warn("failed to send htt type stats request: %d", ret);
- ++ ath10k_warn(ar, "failed to send htt type stats request: %d",
- ++ ret);
- + dev_kfree_skb_any(skb);
- + return ret;
- + }
- +@@ -224,6 +203,7 @@ int ath10k_htt_h2t_stats_req(struct ath1
- +
- + int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
- + {
- ++ struct ath10k *ar = htt->ar;
- + struct sk_buff *skb;
- + struct htt_cmd *cmd;
- + struct htt_rx_ring_setup_ring *ring;
- +@@ -242,7 +222,7 @@ int ath10k_htt_send_rx_ring_cfg_ll(struc
- +
- + len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup.hdr)
- + + (sizeof(*ring) * num_rx_ring);
- +- skb = ath10k_htc_alloc_skb(len);
- ++ skb = ath10k_htc_alloc_skb(ar, len);
- + if (!skb)
- + return -ENOMEM;
- +
- +@@ -307,9 +287,57 @@ int ath10k_htt_send_rx_ring_cfg_ll(struc
- + return 0;
- + }
- +
- ++int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
- ++ u8 max_subfrms_ampdu,
- ++ u8 max_subfrms_amsdu)
- ++{
- ++ struct ath10k *ar = htt->ar;
- ++ struct htt_aggr_conf *aggr_conf;
- ++ struct sk_buff *skb;
- ++ struct htt_cmd *cmd;
- ++ int len;
- ++ int ret;
- ++
- ++ /* Firmware defaults are: amsdu = 3 and ampdu = 64 */
- ++
- ++ if (max_subfrms_ampdu == 0 || max_subfrms_ampdu > 64)
- ++ return -EINVAL;
- ++
- ++ if (max_subfrms_amsdu == 0 || max_subfrms_amsdu > 31)
- ++ return -EINVAL;
- ++
- ++ len = sizeof(cmd->hdr);
- ++ len += sizeof(cmd->aggr_conf);
- ++
- ++ skb = ath10k_htc_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return -ENOMEM;
- ++
- ++ skb_put(skb, len);
- ++ cmd = (struct htt_cmd *)skb->data;
- ++ cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_AGGR_CFG;
- ++
- ++ aggr_conf = &cmd->aggr_conf;
- ++ aggr_conf->max_num_ampdu_subframes = max_subfrms_ampdu;
- ++ aggr_conf->max_num_amsdu_subframes = max_subfrms_amsdu;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d",
- ++ aggr_conf->max_num_amsdu_subframes,
- ++ aggr_conf->max_num_ampdu_subframes);
- ++
- ++ ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
- ++ if (ret) {
- ++ dev_kfree_skb_any(skb);
- ++ return ret;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- + int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
- + {
- +- struct device *dev = htt->ar->dev;
- ++ struct ath10k *ar = htt->ar;
- ++ struct device *dev = ar->dev;
- + struct sk_buff *txdesc = NULL;
- + struct htt_cmd *cmd;
- + struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
- +@@ -318,7 +346,6 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt
- + int msdu_id = -1;
- + int res;
- +
- +-
- + res = ath10k_htt_tx_inc_pending(htt);
- + if (res)
- + goto err;
- +@@ -327,16 +354,15 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt
- + len += sizeof(cmd->mgmt_tx);
- +
- + spin_lock_bh(&htt->tx_lock);
- +- res = ath10k_htt_tx_alloc_msdu_id(htt);
- ++ res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
- + if (res < 0) {
- + spin_unlock_bh(&htt->tx_lock);
- + goto err_tx_dec;
- + }
- + msdu_id = res;
- +- htt->pending_tx[msdu_id] = msdu;
- + spin_unlock_bh(&htt->tx_lock);
- +
- +- txdesc = ath10k_htc_alloc_skb(len);
- ++ txdesc = ath10k_htc_alloc_skb(ar, len);
- + if (!txdesc) {
- + res = -ENOMEM;
- + goto err_free_msdu_id;
- +@@ -372,7 +398,6 @@ err_free_txdesc:
- + dev_kfree_skb_any(txdesc);
- + err_free_msdu_id:
- + spin_lock_bh(&htt->tx_lock);
- +- htt->pending_tx[msdu_id] = NULL;
- + ath10k_htt_tx_free_msdu_id(htt, msdu_id);
- + spin_unlock_bh(&htt->tx_lock);
- + err_tx_dec:
- +@@ -383,7 +408,8 @@ err:
- +
- + int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
- + {
- +- struct device *dev = htt->ar->dev;
- ++ struct ath10k *ar = htt->ar;
- ++ struct device *dev = ar->dev;
- + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
- + struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
- + struct ath10k_hif_sg_item sg_items[2];
- +@@ -403,13 +429,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt
- + goto err;
- +
- + spin_lock_bh(&htt->tx_lock);
- +- res = ath10k_htt_tx_alloc_msdu_id(htt);
- ++ res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
- + if (res < 0) {
- + spin_unlock_bh(&htt->tx_lock);
- + goto err_tx_dec;
- + }
- + msdu_id = res;
- +- htt->pending_tx[msdu_id] = msdu;
- + spin_unlock_bh(&htt->tx_lock);
- +
- + prefetch_len = min(htt->prefetch_len, msdu->len);
- +@@ -423,10 +448,18 @@ int ath10k_htt_tx(struct ath10k_htt *htt
- +
- + skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC,
- + &paddr);
- +- if (!skb_cb->htt.txbuf)
- ++ if (!skb_cb->htt.txbuf) {
- ++ res = -ENOMEM;
- + goto err_free_msdu_id;
- ++ }
- + skb_cb->htt.txbuf_paddr = paddr;
- +
- ++ if ((ieee80211_is_action(hdr->frame_control) ||
- ++ ieee80211_is_deauth(hdr->frame_control) ||
- ++ ieee80211_is_disassoc(hdr->frame_control)) &&
- ++ ieee80211_has_protected(hdr->frame_control))
- ++ skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
- ++
- + skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len,
- + DMA_TO_DEVICE);
- + res = dma_mapping_error(dev, skb_cb->paddr);
- +@@ -482,8 +515,16 @@ int ath10k_htt_tx(struct ath10k_htt *htt
- +
- + flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
- + flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID);
- +- flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
- +- flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
- ++ if (msdu->ip_summed == CHECKSUM_PARTIAL) {
- ++ flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
- ++ flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
- ++ }
- ++
- ++ /* Prevent firmware from sending up tx inspection requests. There's
- ++ * nothing ath10k can do with frames requested for inspection so force
- ++ * it to simply rely a regular tx completion with discard status.
- ++ */
- ++ flags1 |= HTT_DATA_TX_DESC_FLAGS1_POSTPONED;
- +
- + skb_cb->htt.txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM;
- + skb_cb->htt.txbuf->cmd_tx.flags0 = flags0;
- +@@ -491,14 +532,18 @@ int ath10k_htt_tx(struct ath10k_htt *htt
- + skb_cb->htt.txbuf->cmd_tx.len = __cpu_to_le16(msdu->len);
- + skb_cb->htt.txbuf->cmd_tx.id = __cpu_to_le16(msdu_id);
- + skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
- +- skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID);
- ++ skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le16(HTT_INVALID_PEERID);
- ++ skb_cb->htt.txbuf->cmd_tx.freq = __cpu_to_le16(skb_cb->htt.freq);
- +
- +- ath10k_dbg(ATH10K_DBG_HTT,
- +- "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n",
- ++ trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid);
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT,
- ++ "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu freq %hu\n",
- + flags0, flags1, msdu->len, msdu_id, frags_paddr,
- +- (u32)skb_cb->paddr, vdev_id, tid);
- +- ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
- ++ (u32)skb_cb->paddr, vdev_id, tid, skb_cb->htt.freq);
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
- + msdu->data, msdu->len);
- ++ trace_ath10k_tx_hdr(ar, msdu->data, msdu->len);
- ++ trace_ath10k_tx_payload(ar, msdu->data, msdu->len);
- +
- + sg_items[0].transfer_id = 0;
- + sg_items[0].transfer_context = NULL;
- +@@ -531,7 +576,6 @@ err_free_txbuf:
- + skb_cb->htt.txbuf_paddr);
- + err_free_msdu_id:
- + spin_lock_bh(&htt->tx_lock);
- +- htt->pending_tx[msdu_id] = NULL;
- + ath10k_htt_tx_free_msdu_id(htt, msdu_id);
- + spin_unlock_bh(&htt->tx_lock);
- + err_tx_dec:
- +--- a/drivers/net/wireless/ath/ath10k/hw.h
- ++++ b/drivers/net/wireless/ath/ath10k/hw.h
- +@@ -20,24 +20,73 @@
- +
- + #include "targaddrs.h"
- +
- ++#define ATH10K_FW_DIR "ath10k"
- ++
- + /* QCA988X 1.0 definitions (unsupported) */
- + #define QCA988X_HW_1_0_CHIP_ID_REV 0x0
- +
- + /* QCA988X 2.0 definitions */
- + #define QCA988X_HW_2_0_VERSION 0x4100016c
- + #define QCA988X_HW_2_0_CHIP_ID_REV 0x2
- +-#define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0"
- ++#define QCA988X_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA988X/hw2.0"
- + #define QCA988X_HW_2_0_FW_FILE "firmware.bin"
- +-#define QCA988X_HW_2_0_FW_2_FILE "firmware-2.bin"
- + #define QCA988X_HW_2_0_OTP_FILE "otp.bin"
- + #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
- + #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
- +
- ++/* QCA6174 target BMI version signatures */
- ++#define QCA6174_HW_1_0_VERSION 0x05000000
- ++#define QCA6174_HW_1_1_VERSION 0x05000001
- ++#define QCA6174_HW_1_3_VERSION 0x05000003
- ++#define QCA6174_HW_2_1_VERSION 0x05010000
- ++#define QCA6174_HW_3_0_VERSION 0x05020000
- ++#define QCA6174_HW_3_2_VERSION 0x05030000
- ++
- ++enum qca6174_pci_rev {
- ++ QCA6174_PCI_REV_1_1 = 0x11,
- ++ QCA6174_PCI_REV_1_3 = 0x13,
- ++ QCA6174_PCI_REV_2_0 = 0x20,
- ++ QCA6174_PCI_REV_3_0 = 0x30,
- ++};
- ++
- ++enum qca6174_chip_id_rev {
- ++ QCA6174_HW_1_0_CHIP_ID_REV = 0,
- ++ QCA6174_HW_1_1_CHIP_ID_REV = 1,
- ++ QCA6174_HW_1_3_CHIP_ID_REV = 2,
- ++ QCA6174_HW_2_1_CHIP_ID_REV = 4,
- ++ QCA6174_HW_2_2_CHIP_ID_REV = 5,
- ++ QCA6174_HW_3_0_CHIP_ID_REV = 8,
- ++ QCA6174_HW_3_1_CHIP_ID_REV = 9,
- ++ QCA6174_HW_3_2_CHIP_ID_REV = 10,
- ++};
- ++
- ++#define QCA6174_HW_2_1_FW_DIR "ath10k/QCA6174/hw2.1"
- ++#define QCA6174_HW_2_1_FW_FILE "firmware.bin"
- ++#define QCA6174_HW_2_1_OTP_FILE "otp.bin"
- ++#define QCA6174_HW_2_1_BOARD_DATA_FILE "board.bin"
- ++#define QCA6174_HW_2_1_PATCH_LOAD_ADDR 0x1234
- ++
- ++#define QCA6174_HW_3_0_FW_DIR "ath10k/QCA6174/hw3.0"
- ++#define QCA6174_HW_3_0_FW_FILE "firmware.bin"
- ++#define QCA6174_HW_3_0_OTP_FILE "otp.bin"
- ++#define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin"
- ++#define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234
- ++
- + #define ATH10K_FW_API2_FILE "firmware-2.bin"
- ++#define ATH10K_FW_API3_FILE "firmware-3.bin"
- ++
- ++/* added support for ATH10K_FW_IE_WMI_OP_VERSION */
- ++#define ATH10K_FW_API4_FILE "firmware-4.bin"
- ++
- ++#define ATH10K_FW_UTF_FILE "utf.bin"
- +
- + /* includes also the null byte */
- + #define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K"
- +
- ++#define REG_DUMP_COUNT_QCA988X 60
- ++
- ++#define QCA988X_CAL_DATA_LEN 2116
- ++
- + struct ath10k_fw_ie {
- + __le32 id;
- + __le32 len;
- +@@ -50,8 +99,57 @@ enum ath10k_fw_ie_type {
- + ATH10K_FW_IE_FEATURES = 2,
- + ATH10K_FW_IE_FW_IMAGE = 3,
- + ATH10K_FW_IE_OTP_IMAGE = 4,
- ++
- ++ /* WMI "operations" interface version, 32 bit value. Supported from
- ++ * FW API 4 and above.
- ++ */
- ++ ATH10K_FW_IE_WMI_OP_VERSION = 5,
- ++};
- ++
- ++enum ath10k_fw_wmi_op_version {
- ++ ATH10K_FW_WMI_OP_VERSION_UNSET = 0,
- ++
- ++ ATH10K_FW_WMI_OP_VERSION_MAIN = 1,
- ++ ATH10K_FW_WMI_OP_VERSION_10_1 = 2,
- ++ ATH10K_FW_WMI_OP_VERSION_10_2 = 3,
- ++ ATH10K_FW_WMI_OP_VERSION_TLV = 4,
- ++ ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5,
- ++
- ++ /* keep last */
- ++ ATH10K_FW_WMI_OP_VERSION_MAX,
- ++};
- ++
- ++enum ath10k_hw_rev {
- ++ ATH10K_HW_QCA988X,
- ++ ATH10K_HW_QCA6174,
- ++};
- ++
- ++struct ath10k_hw_regs {
- ++ u32 rtc_state_cold_reset_mask;
- ++ u32 rtc_soc_base_address;
- ++ u32 rtc_wmac_base_address;
- ++ u32 soc_core_base_address;
- ++ u32 ce_wrapper_base_address;
- ++ u32 ce0_base_address;
- ++ u32 ce1_base_address;
- ++ u32 ce2_base_address;
- ++ u32 ce3_base_address;
- ++ u32 ce4_base_address;
- ++ u32 ce5_base_address;
- ++ u32 ce6_base_address;
- ++ u32 ce7_base_address;
- ++ u32 soc_reset_control_si0_rst_mask;
- ++ u32 soc_reset_control_ce_rst_mask;
- ++ u32 soc_chip_id_address;
- ++ u32 scratch_3_address;
- + };
- +
- ++extern const struct ath10k_hw_regs qca988x_regs;
- ++extern const struct ath10k_hw_regs qca6174_regs;
- ++
- ++#define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X)
- ++#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174)
- ++
- + /* Known pecularities:
- + * - current FW doesn't support raw rx mode (last tested v599)
- + * - current FW dumps upon raw tx mode (last tested v599)
- +@@ -73,6 +171,15 @@ enum ath10k_mcast2ucast_mode {
- + ATH10K_MCAST2UCAST_ENABLED = 1,
- + };
- +
- ++struct ath10k_pktlog_hdr {
- ++ __le16 flags;
- ++ __le16 missed_cnt;
- ++ __le16 log_type;
- ++ __le16 size;
- ++ __le32 timestamp;
- ++ u8 payload[0];
- ++} __packed;
- ++
- + /* Target specific defines for MAIN firmware */
- + #define TARGET_NUM_VDEVS 8
- + #define TARGET_NUM_PEER_AST 2
- +@@ -80,11 +187,13 @@ enum ath10k_mcast2ucast_mode {
- + #define TARGET_DMA_BURST_SIZE 0
- + #define TARGET_MAC_AGGR_DELIM 0
- + #define TARGET_AST_SKID_LIMIT 16
- +-#define TARGET_NUM_PEERS 16
- ++#define TARGET_NUM_STATIONS 16
- ++#define TARGET_NUM_PEERS ((TARGET_NUM_STATIONS) + \
- ++ (TARGET_NUM_VDEVS))
- + #define TARGET_NUM_OFFLOAD_PEERS 0
- + #define TARGET_NUM_OFFLOAD_REORDER_BUFS 0
- + #define TARGET_NUM_PEER_KEYS 2
- +-#define TARGET_NUM_TIDS (2 * ((TARGET_NUM_PEERS) + (TARGET_NUM_VDEVS)))
- ++#define TARGET_NUM_TIDS ((TARGET_NUM_PEERS) * 2)
- + #define TARGET_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
- + #define TARGET_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
- + #define TARGET_RX_TIMEOUT_LO_PRI 100
- +@@ -115,12 +224,15 @@ enum ath10k_mcast2ucast_mode {
- + #define TARGET_10X_DMA_BURST_SIZE 0
- + #define TARGET_10X_MAC_AGGR_DELIM 0
- + #define TARGET_10X_AST_SKID_LIMIT 16
- +-#define TARGET_10X_NUM_PEERS (128 + (TARGET_10X_NUM_VDEVS))
- +-#define TARGET_10X_NUM_PEERS_MAX 128
- ++#define TARGET_10X_NUM_STATIONS 128
- ++#define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \
- ++ (TARGET_10X_NUM_VDEVS))
- + #define TARGET_10X_NUM_OFFLOAD_PEERS 0
- + #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0
- + #define TARGET_10X_NUM_PEER_KEYS 2
- +-#define TARGET_10X_NUM_TIDS 256
- ++#define TARGET_10X_NUM_TIDS_MAX 256
- ++#define TARGET_10X_NUM_TIDS min((TARGET_10X_NUM_TIDS_MAX), \
- ++ (TARGET_10X_NUM_PEERS) * 2)
- + #define TARGET_10X_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
- + #define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
- + #define TARGET_10X_RX_TIMEOUT_LO_PRI 100
- +@@ -140,6 +252,18 @@ enum ath10k_mcast2ucast_mode {
- + #define TARGET_10X_NUM_MSDU_DESC (1024 + 400)
- + #define TARGET_10X_MAX_FRAG_ENTRIES 0
- +
- ++/* 10.2 parameters */
- ++#define TARGET_10_2_DMA_BURST_SIZE 1
- ++
- ++/* Target specific defines for WMI-TLV firmware */
- ++#define TARGET_TLV_NUM_VDEVS 3
- ++#define TARGET_TLV_NUM_STATIONS 32
- ++#define TARGET_TLV_NUM_PEERS ((TARGET_TLV_NUM_STATIONS) + \
- ++ (TARGET_TLV_NUM_VDEVS) + \
- ++ 2)
- ++#define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2)
- ++#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
- ++
- + /* Number of Copy Engines supported */
- + #define CE_COUNT 8
- +
- +@@ -170,7 +294,7 @@ enum ath10k_mcast2ucast_mode {
- + /* as of IP3.7.1 */
- + #define RTC_STATE_V_ON 3
- +
- +-#define RTC_STATE_COLD_RESET_MASK 0x00000400
- ++#define RTC_STATE_COLD_RESET_MASK ar->regs->rtc_state_cold_reset_mask
- + #define RTC_STATE_V_LSB 0
- + #define RTC_STATE_V_MASK 0x00000007
- + #define RTC_STATE_ADDRESS 0x0000
- +@@ -179,12 +303,12 @@ enum ath10k_mcast2ucast_mode {
- + #define PCIE_SOC_WAKE_RESET 0x00000000
- + #define SOC_GLOBAL_RESET_ADDRESS 0x0008
- +
- +-#define RTC_SOC_BASE_ADDRESS 0x00004000
- +-#define RTC_WMAC_BASE_ADDRESS 0x00005000
- ++#define RTC_SOC_BASE_ADDRESS ar->regs->rtc_soc_base_address
- ++#define RTC_WMAC_BASE_ADDRESS ar->regs->rtc_wmac_base_address
- + #define MAC_COEX_BASE_ADDRESS 0x00006000
- + #define BT_COEX_BASE_ADDRESS 0x00007000
- + #define SOC_PCIE_BASE_ADDRESS 0x00008000
- +-#define SOC_CORE_BASE_ADDRESS 0x00009000
- ++#define SOC_CORE_BASE_ADDRESS ar->regs->soc_core_base_address
- + #define WLAN_UART_BASE_ADDRESS 0x0000c000
- + #define WLAN_SI_BASE_ADDRESS 0x00010000
- + #define WLAN_GPIO_BASE_ADDRESS 0x00014000
- +@@ -193,23 +317,23 @@ enum ath10k_mcast2ucast_mode {
- + #define EFUSE_BASE_ADDRESS 0x00030000
- + #define FPGA_REG_BASE_ADDRESS 0x00039000
- + #define WLAN_UART2_BASE_ADDRESS 0x00054c00
- +-#define CE_WRAPPER_BASE_ADDRESS 0x00057000
- +-#define CE0_BASE_ADDRESS 0x00057400
- +-#define CE1_BASE_ADDRESS 0x00057800
- +-#define CE2_BASE_ADDRESS 0x00057c00
- +-#define CE3_BASE_ADDRESS 0x00058000
- +-#define CE4_BASE_ADDRESS 0x00058400
- +-#define CE5_BASE_ADDRESS 0x00058800
- +-#define CE6_BASE_ADDRESS 0x00058c00
- +-#define CE7_BASE_ADDRESS 0x00059000
- ++#define CE_WRAPPER_BASE_ADDRESS ar->regs->ce_wrapper_base_address
- ++#define CE0_BASE_ADDRESS ar->regs->ce0_base_address
- ++#define CE1_BASE_ADDRESS ar->regs->ce1_base_address
- ++#define CE2_BASE_ADDRESS ar->regs->ce2_base_address
- ++#define CE3_BASE_ADDRESS ar->regs->ce3_base_address
- ++#define CE4_BASE_ADDRESS ar->regs->ce4_base_address
- ++#define CE5_BASE_ADDRESS ar->regs->ce5_base_address
- ++#define CE6_BASE_ADDRESS ar->regs->ce6_base_address
- ++#define CE7_BASE_ADDRESS ar->regs->ce7_base_address
- + #define DBI_BASE_ADDRESS 0x00060000
- + #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000
- + #define PCIE_LOCAL_BASE_ADDRESS 0x00080000
- +
- + #define SOC_RESET_CONTROL_ADDRESS 0x00000000
- + #define SOC_RESET_CONTROL_OFFSET 0x00000000
- +-#define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001
- +-#define SOC_RESET_CONTROL_CE_RST_MASK 0x00040000
- ++#define SOC_RESET_CONTROL_SI0_RST_MASK ar->regs->soc_reset_control_si0_rst_mask
- ++#define SOC_RESET_CONTROL_CE_RST_MASK ar->regs->soc_reset_control_ce_rst_mask
- + #define SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040
- + #define SOC_CPU_CLOCK_OFFSET 0x00000020
- + #define SOC_CPU_CLOCK_STANDARD_LSB 0
- +@@ -223,7 +347,7 @@ enum ath10k_mcast2ucast_mode {
- + #define SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050
- + #define SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004
- +
- +-#define SOC_CHIP_ID_ADDRESS 0x000000ec
- ++#define SOC_CHIP_ID_ADDRESS ar->regs->soc_chip_id_address
- + #define SOC_CHIP_ID_REV_LSB 8
- + #define SOC_CHIP_ID_REV_MASK 0x00000f00
- +
- +@@ -274,11 +398,12 @@ enum ath10k_mcast2ucast_mode {
- + #define SI_RX_DATA1_OFFSET 0x00000014
- +
- + #define CORE_CTRL_CPU_INTR_MASK 0x00002000
- ++#define CORE_CTRL_PCIE_REG_31_MASK 0x00000800
- + #define CORE_CTRL_ADDRESS 0x0000
- + #define PCIE_INTR_ENABLE_ADDRESS 0x0008
- + #define PCIE_INTR_CAUSE_ADDRESS 0x000c
- + #define PCIE_INTR_CLR_ADDRESS 0x0014
- +-#define SCRATCH_3_ADDRESS 0x0030
- ++#define SCRATCH_3_ADDRESS ar->regs->scratch_3_address
- + #define CPU_INTR_ADDRESS 0x0010
- +
- + /* Firmware indications to the Host via SCRATCH_3 register. */
- +--- a/drivers/net/wireless/ath/ath10k/mac.c
- ++++ b/drivers/net/wireless/ath/ath10k/mac.c
- +@@ -26,6 +26,9 @@
- + #include "wmi.h"
- + #include "htt.h"
- + #include "txrx.h"
- ++#include "testmode.h"
- ++#include "wmi.h"
- ++#include "wmi-ops.h"
- +
- + /**********/
- + /* Crypto */
- +@@ -34,8 +37,9 @@
- + static int ath10k_send_key(struct ath10k_vif *arvif,
- + struct ieee80211_key_conf *key,
- + enum set_key_cmd cmd,
- +- const u8 *macaddr)
- ++ const u8 *macaddr, bool def_idx)
- + {
- ++ struct ath10k *ar = arvif->ar;
- + struct wmi_vdev_install_key_arg arg = {
- + .vdev_id = arvif->vdev_id,
- + .key_idx = key->keyidx,
- +@@ -54,7 +58,7 @@ static int ath10k_send_key(struct ath10k
- + switch (key->cipher) {
- + case WLAN_CIPHER_SUITE_CCMP:
- + arg.key_cipher = WMI_CIPHER_AES_CCM;
- +- key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
- ++ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT;
- + break;
- + case WLAN_CIPHER_SUITE_TKIP:
- + arg.key_cipher = WMI_CIPHER_TKIP;
- +@@ -68,9 +72,12 @@ static int ath10k_send_key(struct ath10k
- + * Otherwise pairwise key must be set */
- + if (memcmp(macaddr, arvif->vif->addr, ETH_ALEN))
- + arg.key_flags = WMI_KEY_PAIRWISE;
- ++
- ++ if (def_idx)
- ++ arg.key_flags |= WMI_KEY_TX_USAGE;
- + break;
- + default:
- +- ath10k_warn("cipher %d is not supported\n", key->cipher);
- ++ ath10k_warn(ar, "cipher %d is not supported\n", key->cipher);
- + return -EOPNOTSUPP;
- + }
- +
- +@@ -85,7 +92,7 @@ static int ath10k_send_key(struct ath10k
- + static int ath10k_install_key(struct ath10k_vif *arvif,
- + struct ieee80211_key_conf *key,
- + enum set_key_cmd cmd,
- +- const u8 *macaddr)
- ++ const u8 *macaddr, bool def_idx)
- + {
- + struct ath10k *ar = arvif->ar;
- + int ret;
- +@@ -94,7 +101,7 @@ static int ath10k_install_key(struct ath
- +
- + reinit_completion(&ar->install_key_done);
- +
- +- ret = ath10k_send_key(arvif, key, cmd, macaddr);
- ++ ret = ath10k_send_key(arvif, key, cmd, macaddr, def_idx);
- + if (ret)
- + return ret;
- +
- +@@ -112,6 +119,7 @@ static int ath10k_install_peer_wep_keys(
- + struct ath10k_peer *peer;
- + int ret;
- + int i;
- ++ bool def_idx;
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- +@@ -125,13 +133,20 @@ static int ath10k_install_peer_wep_keys(
- + for (i = 0; i < ARRAY_SIZE(arvif->wep_keys); i++) {
- + if (arvif->wep_keys[i] == NULL)
- + continue;
- ++ /* set TX_USAGE flag for default key id */
- ++ if (arvif->def_wep_key_idx == i)
- ++ def_idx = true;
- ++ else
- ++ def_idx = false;
- +
- + ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY,
- +- addr);
- ++ addr, def_idx);
- + if (ret)
- + return ret;
- +
- ++ spin_lock_bh(&ar->data_lock);
- + peer->keys[i] = arvif->wep_keys[i];
- ++ spin_unlock_bh(&ar->data_lock);
- + }
- +
- + return 0;
- +@@ -159,21 +174,49 @@ static int ath10k_clear_peer_keys(struct
- + if (peer->keys[i] == NULL)
- + continue;
- +
- ++ /* key flags are not required to delete the key */
- + ret = ath10k_install_key(arvif, peer->keys[i],
- +- DISABLE_KEY, addr);
- ++ DISABLE_KEY, addr, false);
- + if (ret && first_errno == 0)
- + first_errno = ret;
- +
- + if (ret)
- +- ath10k_warn("failed to remove peer wep key %d: %d\n",
- ++ ath10k_warn(ar, "failed to remove peer wep key %d: %d\n",
- + i, ret);
- +
- ++ spin_lock_bh(&ar->data_lock);
- + peer->keys[i] = NULL;
- ++ spin_unlock_bh(&ar->data_lock);
- + }
- +
- + return first_errno;
- + }
- +
- ++bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
- ++ u8 keyidx)
- ++{
- ++ struct ath10k_peer *peer;
- ++ int i;
- ++
- ++ lockdep_assert_held(&ar->data_lock);
- ++
- ++ /* We don't know which vdev this peer belongs to,
- ++ * since WMI doesn't give us that information.
- ++ *
- ++ * FIXME: multi-bss needs to be handled.
- ++ */
- ++ peer = ath10k_peer_find(ar, 0, addr);
- ++ if (!peer)
- ++ return false;
- ++
- ++ for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
- ++ if (peer->keys[i] && peer->keys[i]->keyidx == keyidx)
- ++ return true;
- ++ }
- ++
- ++ return false;
- ++}
- ++
- + static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
- + struct ieee80211_key_conf *key)
- + {
- +@@ -194,7 +237,7 @@ static int ath10k_clear_vdev_key(struct
- + list_for_each_entry(peer, &ar->peers, list) {
- + for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
- + if (peer->keys[i] == key) {
- +- memcpy(addr, peer->addr, ETH_ALEN);
- ++ ether_addr_copy(addr, peer->addr);
- + peer->keys[i] = NULL;
- + break;
- + }
- +@@ -207,20 +250,19 @@ static int ath10k_clear_vdev_key(struct
- +
- + if (i == ARRAY_SIZE(peer->keys))
- + break;
- +-
- +- ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr);
- ++ /* key flags are not required to delete the key */
- ++ ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, false);
- + if (ret && first_errno == 0)
- + first_errno = ret;
- +
- + if (ret)
- +- ath10k_warn("failed to remove key for %pM: %d\n",
- ++ ath10k_warn(ar, "failed to remove key for %pM: %d\n",
- + addr, ret);
- + }
- +
- + return first_errno;
- + }
- +
- +-
- + /*********************/
- + /* General utilities */
- + /*********************/
- +@@ -234,7 +276,10 @@ chan_to_phymode(const struct cfg80211_ch
- + case IEEE80211_BAND_2GHZ:
- + switch (chandef->width) {
- + case NL80211_CHAN_WIDTH_20_NOHT:
- +- phymode = MODE_11G;
- ++ if (chandef->chan->flags & IEEE80211_CHAN_NO_OFDM)
- ++ phymode = MODE_11B;
- ++ else
- ++ phymode = MODE_11G;
- + break;
- + case NL80211_CHAN_WIDTH_20:
- + phymode = MODE_11NG_HT20;
- +@@ -322,22 +367,24 @@ static int ath10k_peer_create(struct ath
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- ++ if (ar->num_peers >= ar->max_num_peers)
- ++ return -ENOBUFS;
- ++
- + ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
- + if (ret) {
- +- ath10k_warn("failed to create wmi peer %pM on vdev %i: %i\n",
- ++ ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n",
- + addr, vdev_id, ret);
- + return ret;
- + }
- +
- + ret = ath10k_wait_for_peer_created(ar, vdev_id, addr);
- + if (ret) {
- +- ath10k_warn("failed to wait for created wmi peer %pM on vdev %i: %i\n",
- ++ ath10k_warn(ar, "failed to wait for created wmi peer %pM on vdev %i: %i\n",
- + addr, vdev_id, ret);
- + return ret;
- + }
- +- spin_lock_bh(&ar->data_lock);
- ++
- + ar->num_peers++;
- +- spin_unlock_bh(&ar->data_lock);
- +
- + return 0;
- + }
- +@@ -352,7 +399,7 @@ static int ath10k_mac_set_kickout(struct
- + ret = ath10k_wmi_pdev_set_param(ar, param,
- + ATH10K_KICKOUT_THRESHOLD);
- + if (ret) {
- +- ath10k_warn("failed to set kickout threshold on vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to set kickout threshold on vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + return ret;
- + }
- +@@ -361,7 +408,7 @@ static int ath10k_mac_set_kickout(struct
- + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
- + ATH10K_KEEPALIVE_MIN_IDLE);
- + if (ret) {
- +- ath10k_warn("failed to set keepalive minimum idle time on vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to set keepalive minimum idle time on vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + return ret;
- + }
- +@@ -370,7 +417,7 @@ static int ath10k_mac_set_kickout(struct
- + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
- + ATH10K_KEEPALIVE_MAX_IDLE);
- + if (ret) {
- +- ath10k_warn("failed to set keepalive maximum idle time on vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to set keepalive maximum idle time on vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + return ret;
- + }
- +@@ -379,7 +426,7 @@ static int ath10k_mac_set_kickout(struct
- + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
- + ATH10K_KEEPALIVE_MAX_UNRESPONSIVE);
- + if (ret) {
- +- ath10k_warn("failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + return ret;
- + }
- +@@ -387,15 +434,11 @@ static int ath10k_mac_set_kickout(struct
- + return 0;
- + }
- +
- +-static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
- ++static int ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
- + {
- + struct ath10k *ar = arvif->ar;
- + u32 vdev_param;
- +
- +- if (value != 0xFFFFFFFF)
- +- value = min_t(u32, arvif->ar->hw->wiphy->rts_threshold,
- +- ATH10K_RTS_MAX);
- +-
- + vdev_param = ar->wmi.vdev_param->rts_threshold;
- + return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, value);
- + }
- +@@ -428,9 +471,7 @@ static int ath10k_peer_delete(struct ath
- + if (ret)
- + return ret;
- +
- +- spin_lock_bh(&ar->data_lock);
- + ar->num_peers--;
- +- spin_unlock_bh(&ar->data_lock);
- +
- + return 0;
- + }
- +@@ -446,7 +487,7 @@ static void ath10k_peer_cleanup(struct a
- + if (peer->vdev_id != vdev_id)
- + continue;
- +
- +- ath10k_warn("removing stale peer %pM from vdev_id %d\n",
- ++ ath10k_warn(ar, "removing stale peer %pM from vdev_id %d\n",
- + peer->addr, vdev_id);
- +
- + list_del(&peer->list);
- +@@ -467,20 +508,63 @@ static void ath10k_peer_cleanup_all(stru
- + list_del(&peer->list);
- + kfree(peer);
- + }
- +- ar->num_peers = 0;
- + spin_unlock_bh(&ar->data_lock);
- ++
- ++ ar->num_peers = 0;
- ++ ar->num_stations = 0;
- + }
- +
- + /************************/
- + /* Interface management */
- + /************************/
- +
- ++void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif)
- ++{
- ++ struct ath10k *ar = arvif->ar;
- ++
- ++ lockdep_assert_held(&ar->data_lock);
- ++
- ++ if (!arvif->beacon)
- ++ return;
- ++
- ++ if (!arvif->beacon_buf)
- ++ dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr,
- ++ arvif->beacon->len, DMA_TO_DEVICE);
- ++
- ++ if (WARN_ON(arvif->beacon_state != ATH10K_BEACON_SCHEDULED &&
- ++ arvif->beacon_state != ATH10K_BEACON_SENT))
- ++ return;
- ++
- ++ dev_kfree_skb_any(arvif->beacon);
- ++
- ++ arvif->beacon = NULL;
- ++ arvif->beacon_state = ATH10K_BEACON_SCHEDULED;
- ++}
- ++
- ++static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
- ++{
- ++ struct ath10k *ar = arvif->ar;
- ++
- ++ lockdep_assert_held(&ar->data_lock);
- ++
- ++ ath10k_mac_vif_beacon_free(arvif);
- ++
- ++ if (arvif->beacon_buf) {
- ++ dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
- ++ arvif->beacon_buf, arvif->beacon_paddr);
- ++ arvif->beacon_buf = NULL;
- ++ }
- ++}
- ++
- + static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
- + {
- + int ret;
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- ++ if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
- ++ return -ESHUTDOWN;
- ++
- + ret = wait_for_completion_timeout(&ar->vdev_setup_done,
- + ATH10K_VDEV_SETUP_TIMEOUT_HZ);
- + if (ret == 0)
- +@@ -489,19 +573,6 @@ static inline int ath10k_vdev_setup_sync
- + return 0;
- + }
- +
- +-static bool ath10k_monitor_is_enabled(struct ath10k *ar)
- +-{
- +- lockdep_assert_held(&ar->conf_mutex);
- +-
- +- ath10k_dbg(ATH10K_DBG_MAC,
- +- "mac monitor refs: promisc %d monitor %d cac %d\n",
- +- ar->promisc, ar->monitor,
- +- test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags));
- +-
- +- return ar->promisc || ar->monitor ||
- +- test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
- +-}
- +-
- + static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
- + {
- + struct cfg80211_chan_def *chandef = &ar->chandef;
- +@@ -526,37 +597,39 @@ static int ath10k_monitor_vdev_start(str
- + arg.channel.max_reg_power = channel->max_reg_power * 2;
- + arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
- +
- ++ reinit_completion(&ar->vdev_setup_done);
- ++
- + ret = ath10k_wmi_vdev_start(ar, &arg);
- + if (ret) {
- +- ath10k_warn("failed to request monitor vdev %i start: %d\n",
- ++ ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n",
- + vdev_id, ret);
- + return ret;
- + }
- +
- + ret = ath10k_vdev_setup_sync(ar);
- + if (ret) {
- +- ath10k_warn("failed to synchronize setup for monitor vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i start: %d\n",
- + vdev_id, ret);
- + return ret;
- + }
- +
- + ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr);
- + if (ret) {
- +- ath10k_warn("failed to put up monitor vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to put up monitor vdev %i: %d\n",
- + vdev_id, ret);
- + goto vdev_stop;
- + }
- +
- + ar->monitor_vdev_id = vdev_id;
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i started\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i started\n",
- + ar->monitor_vdev_id);
- + return 0;
- +
- + vdev_stop:
- + ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
- + if (ret)
- +- ath10k_warn("failed to stop monitor vdev %i after start failure: %d\n",
- ++ ath10k_warn(ar, "failed to stop monitor vdev %i after start failure: %d\n",
- + ar->monitor_vdev_id, ret);
- +
- + return ret;
- +@@ -570,20 +643,22 @@ static int ath10k_monitor_vdev_stop(stru
- +
- + ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id);
- + if (ret)
- +- ath10k_warn("failed to put down monitor vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to put down monitor vdev %i: %d\n",
- + ar->monitor_vdev_id, ret);
- +
- ++ reinit_completion(&ar->vdev_setup_done);
- ++
- + ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
- + if (ret)
- +- ath10k_warn("failed to to request monitor vdev %i stop: %d\n",
- ++ ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n",
- + ar->monitor_vdev_id, ret);
- +
- + ret = ath10k_vdev_setup_sync(ar);
- + if (ret)
- +- ath10k_warn("failed to synchronise monitor vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to synchronize monitor vdev %i stop: %d\n",
- + ar->monitor_vdev_id, ret);
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n",
- + ar->monitor_vdev_id);
- + return ret;
- + }
- +@@ -594,35 +669,29 @@ static int ath10k_monitor_vdev_create(st
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- +- bit = ffs(ar->free_vdev_map);
- +- if (bit == 0) {
- +- ath10k_warn("failed to find free vdev id for monitor vdev\n");
- ++ if (ar->free_vdev_map == 0) {
- ++ ath10k_warn(ar, "failed to find free vdev id for monitor vdev\n");
- + return -ENOMEM;
- + }
- +
- +- ar->monitor_vdev_id = bit - 1;
- +- ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
- ++ bit = __ffs64(ar->free_vdev_map);
- ++
- ++ ar->monitor_vdev_id = bit;
- +
- + ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id,
- + WMI_VDEV_TYPE_MONITOR,
- + 0, ar->mac_addr);
- + if (ret) {
- +- ath10k_warn("failed to request monitor vdev %i creation: %d\n",
- ++ ath10k_warn(ar, "failed to request monitor vdev %i creation: %d\n",
- + ar->monitor_vdev_id, ret);
- +- goto vdev_fail;
- ++ return ret;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
- ++ ar->free_vdev_map &= ~(1LL << ar->monitor_vdev_id);
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
- + ar->monitor_vdev_id);
- +
- + return 0;
- +-
- +-vdev_fail:
- +- /*
- +- * Restore the ID to the global map.
- +- */
- +- ar->free_vdev_map |= 1 << (ar->monitor_vdev_id);
- +- return ret;
- + }
- +
- + static int ath10k_monitor_vdev_delete(struct ath10k *ar)
- +@@ -633,14 +702,14 @@ static int ath10k_monitor_vdev_delete(st
- +
- + ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id);
- + if (ret) {
- +- ath10k_warn("failed to request wmi monitor vdev %i removal: %d\n",
- ++ ath10k_warn(ar, "failed to request wmi monitor vdev %i removal: %d\n",
- + ar->monitor_vdev_id, ret);
- + return ret;
- + }
- +
- +- ar->free_vdev_map |= 1 << (ar->monitor_vdev_id);
- ++ ar->free_vdev_map |= 1LL << ar->monitor_vdev_id;
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
- + ar->monitor_vdev_id);
- + return ret;
- + }
- +@@ -651,63 +720,70 @@ static int ath10k_monitor_start(struct a
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- +- if (!ath10k_monitor_is_enabled(ar)) {
- +- ath10k_warn("trying to start monitor with no references\n");
- +- return 0;
- +- }
- +-
- +- if (ar->monitor_started) {
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor already started\n");
- +- return 0;
- +- }
- +-
- + ret = ath10k_monitor_vdev_create(ar);
- + if (ret) {
- +- ath10k_warn("failed to create monitor vdev: %d\n", ret);
- ++ ath10k_warn(ar, "failed to create monitor vdev: %d\n", ret);
- + return ret;
- + }
- +
- + ret = ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id);
- + if (ret) {
- +- ath10k_warn("failed to start monitor vdev: %d\n", ret);
- ++ ath10k_warn(ar, "failed to start monitor vdev: %d\n", ret);
- + ath10k_monitor_vdev_delete(ar);
- + return ret;
- + }
- +
- + ar->monitor_started = true;
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor started\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor started\n");
- +
- + return 0;
- + }
- +
- +-static void ath10k_monitor_stop(struct ath10k *ar)
- ++static int ath10k_monitor_stop(struct ath10k *ar)
- + {
- + int ret;
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- +- if (ath10k_monitor_is_enabled(ar)) {
- +- ath10k_dbg(ATH10K_DBG_MAC,
- +- "mac monitor will be stopped later\n");
- +- return;
- ++ ret = ath10k_monitor_vdev_stop(ar);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to stop monitor vdev: %d\n", ret);
- ++ return ret;
- + }
- +
- +- if (!ar->monitor_started) {
- +- ath10k_dbg(ATH10K_DBG_MAC,
- +- "mac monitor probably failed to start earlier\n");
- +- return;
- ++ ret = ath10k_monitor_vdev_delete(ar);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to delete monitor vdev: %d\n", ret);
- ++ return ret;
- + }
- +
- +- ret = ath10k_monitor_vdev_stop(ar);
- +- if (ret)
- +- ath10k_warn("failed to stop monitor vdev: %d\n", ret);
- ++ ar->monitor_started = false;
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopped\n");
- +
- +- ret = ath10k_monitor_vdev_delete(ar);
- +- if (ret)
- +- ath10k_warn("failed to delete monitor vdev: %d\n", ret);
- ++ return 0;
- ++}
- +
- +- ar->monitor_started = false;
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac monitor stopped\n");
- ++static int ath10k_monitor_recalc(struct ath10k *ar)
- ++{
- ++ bool should_start;
- ++
- ++ lockdep_assert_held(&ar->conf_mutex);
- ++
- ++ should_start = ar->monitor ||
- ++ ar->filter_flags & FIF_PROMISC_IN_BSS ||
- ++ test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC,
- ++ "mac monitor recalc started? %d should? %d\n",
- ++ ar->monitor_started, should_start);
- ++
- ++ if (should_start == ar->monitor_started)
- ++ return 0;
- ++
- ++ if (should_start)
- ++ return ath10k_monitor_start(ar);
- ++
- ++ return ath10k_monitor_stop(ar);
- + }
- +
- + static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
- +@@ -738,14 +814,14 @@ static int ath10k_start_cac(struct ath10
- +
- + set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
- +
- +- ret = ath10k_monitor_start(ar);
- ++ ret = ath10k_monitor_recalc(ar);
- + if (ret) {
- +- ath10k_warn("failed to start monitor (cac): %d\n", ret);
- ++ ath10k_warn(ar, "failed to start monitor (cac): %d\n", ret);
- + clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
- + return ret;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n",
- + ar->monitor_vdev_id);
- +
- + return 0;
- +@@ -762,7 +838,7 @@ static int ath10k_stop_cac(struct ath10k
- + clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
- + ath10k_monitor_stop(ar);
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac finished\n");
- +
- + return 0;
- + }
- +@@ -788,12 +864,12 @@ static void ath10k_recalc_radar_detectio
- + * radiation is not allowed, make this channel DFS_UNAVAILABLE
- + * by indicating that radar was detected.
- + */
- +- ath10k_warn("failed to start CAC: %d\n", ret);
- ++ ath10k_warn(ar, "failed to start CAC: %d\n", ret);
- + ieee80211_radar_detected(ar->hw);
- + }
- + }
- +
- +-static int ath10k_vdev_start(struct ath10k_vif *arvif)
- ++static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart)
- + {
- + struct ath10k *ar = arvif->ar;
- + struct cfg80211_chan_def *chandef = &ar->chandef;
- +@@ -830,22 +906,27 @@ static int ath10k_vdev_start(struct ath1
- + arg.ssid_len = arvif->vif->bss_conf.ssid_len;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_MAC,
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC,
- + "mac vdev %d start center_freq %d phymode %s\n",
- + arg.vdev_id, arg.channel.freq,
- + ath10k_wmi_phymode_str(arg.channel.mode));
- +
- +- ret = ath10k_wmi_vdev_start(ar, &arg);
- ++ if (restart)
- ++ ret = ath10k_wmi_vdev_restart(ar, &arg);
- ++ else
- ++ ret = ath10k_wmi_vdev_start(ar, &arg);
- ++
- + if (ret) {
- +- ath10k_warn("failed to start WMI vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to start WMI vdev %i: %d\n",
- + arg.vdev_id, ret);
- + return ret;
- + }
- +
- + ret = ath10k_vdev_setup_sync(ar);
- + if (ret) {
- +- ath10k_warn("failed to synchronise setup for vdev %i: %d\n",
- +- arg.vdev_id, ret);
- ++ ath10k_warn(ar,
- ++ "failed to synchronize setup for vdev %i restart %d: %d\n",
- ++ arg.vdev_id, restart, ret);
- + return ret;
- + }
- +
- +@@ -855,6 +936,16 @@ static int ath10k_vdev_start(struct ath1
- + return ret;
- + }
- +
- ++static int ath10k_vdev_start(struct ath10k_vif *arvif)
- ++{
- ++ return ath10k_vdev_start_restart(arvif, false);
- ++}
- ++
- ++static int ath10k_vdev_restart(struct ath10k_vif *arvif)
- ++{
- ++ return ath10k_vdev_start_restart(arvif, true);
- ++}
- ++
- + static int ath10k_vdev_stop(struct ath10k_vif *arvif)
- + {
- + struct ath10k *ar = arvif->ar;
- +@@ -866,14 +957,14 @@ static int ath10k_vdev_stop(struct ath10
- +
- + ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
- + if (ret) {
- +- ath10k_warn("failed to stop WMI vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to stop WMI vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + return ret;
- + }
- +
- + ret = ath10k_vdev_setup_sync(ar);
- + if (ret) {
- +- ath10k_warn("failed to syncronise setup for vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to synchronize setup for vdev %i stop: %d\n",
- + arvif->vdev_id, ret);
- + return ret;
- + }
- +@@ -888,9 +979,147 @@ static int ath10k_vdev_stop(struct ath10
- + return ret;
- + }
- +
- ++static int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif,
- ++ struct sk_buff *bcn)
- ++{
- ++ struct ath10k *ar = arvif->ar;
- ++ struct ieee80211_mgmt *mgmt;
- ++ const u8 *p2p_ie;
- ++ int ret;
- ++
- ++ if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
- ++ return 0;
- ++
- ++ if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
- ++ return 0;
- ++
- ++ mgmt = (void *)bcn->data;
- ++ p2p_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
- ++ mgmt->u.beacon.variable,
- ++ bcn->len - (mgmt->u.beacon.variable -
- ++ bcn->data));
- ++ if (!p2p_ie)
- ++ return -ENOENT;
- ++
- ++ ret = ath10k_wmi_p2p_go_bcn_ie(ar, arvif->vdev_id, p2p_ie);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to submit p2p go bcn ie for vdev %i: %d\n",
- ++ arvif->vdev_id, ret);
- ++ return ret;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui,
- ++ u8 oui_type, size_t ie_offset)
- ++{
- ++ size_t len;
- ++ const u8 *next;
- ++ const u8 *end;
- ++ u8 *ie;
- ++
- ++ if (WARN_ON(skb->len < ie_offset))
- ++ return -EINVAL;
- ++
- ++ ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
- ++ skb->data + ie_offset,
- ++ skb->len - ie_offset);
- ++ if (!ie)
- ++ return -ENOENT;
- ++
- ++ len = ie[1] + 2;
- ++ end = skb->data + skb->len;
- ++ next = ie + len;
- ++
- ++ if (WARN_ON(next > end))
- ++ return -EINVAL;
- ++
- ++ memmove(ie, next, end - next);
- ++ skb_trim(skb, skb->len - len);
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_mac_setup_bcn_tmpl(struct ath10k_vif *arvif)
- ++{
- ++ struct ath10k *ar = arvif->ar;
- ++ struct ieee80211_hw *hw = ar->hw;
- ++ struct ieee80211_vif *vif = arvif->vif;
- ++ struct ieee80211_mutable_offsets offs = {};
- ++ struct sk_buff *bcn;
- ++ int ret;
- ++
- ++ if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
- ++ return 0;
- ++
- ++ bcn = ieee80211_beacon_get_template(hw, vif, &offs);
- ++ if (!bcn) {
- ++ ath10k_warn(ar, "failed to get beacon template from mac80211\n");
- ++ return -EPERM;
- ++ }
- ++
- ++ ret = ath10k_mac_setup_bcn_p2p_ie(arvif, bcn);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to setup p2p go bcn ie: %d\n", ret);
- ++ kfree_skb(bcn);
- ++ return ret;
- ++ }
- ++
- ++ /* P2P IE is inserted by firmware automatically (as configured above)
- ++ * so remove it from the base beacon template to avoid duplicate P2P
- ++ * IEs in beacon frames.
- ++ */
- ++ ath10k_mac_remove_vendor_ie(bcn, WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
- ++ offsetof(struct ieee80211_mgmt,
- ++ u.beacon.variable));
- ++
- ++ ret = ath10k_wmi_bcn_tmpl(ar, arvif->vdev_id, offs.tim_offset, bcn, 0,
- ++ 0, NULL, 0);
- ++ kfree_skb(bcn);
- ++
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to submit beacon template command: %d\n",
- ++ ret);
- ++ return ret;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif)
- ++{
- ++ struct ath10k *ar = arvif->ar;
- ++ struct ieee80211_hw *hw = ar->hw;
- ++ struct ieee80211_vif *vif = arvif->vif;
- ++ struct sk_buff *prb;
- ++ int ret;
- ++
- ++ if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
- ++ return 0;
- ++
- ++ prb = ieee80211_proberesp_get(hw, vif);
- ++ if (!prb) {
- ++ ath10k_warn(ar, "failed to get probe resp template from mac80211\n");
- ++ return -EPERM;
- ++ }
- ++
- ++ ret = ath10k_wmi_prb_tmpl(ar, arvif->vdev_id, prb);
- ++ kfree_skb(prb);
- ++
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to submit probe resp template command: %d\n",
- ++ ret);
- ++ return ret;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- + static void ath10k_control_beaconing(struct ath10k_vif *arvif,
- +- struct ieee80211_bss_conf *info)
- ++ struct ieee80211_bss_conf *info)
- + {
- ++ struct ath10k *ar = arvif->ar;
- + int ret = 0;
- +
- + lockdep_assert_held(&arvif->ar->conf_mutex);
- +@@ -902,15 +1131,7 @@ static void ath10k_control_beaconing(str
- + arvif->is_up = false;
- +
- + spin_lock_bh(&arvif->ar->data_lock);
- +- if (arvif->beacon) {
- +- dma_unmap_single(arvif->ar->dev,
- +- ATH10K_SKB_CB(arvif->beacon)->paddr,
- +- arvif->beacon->len, DMA_TO_DEVICE);
- +- dev_kfree_skb_any(arvif->beacon);
- +-
- +- arvif->beacon = NULL;
- +- arvif->beacon_sent = false;
- +- }
- ++ ath10k_mac_vif_beacon_free(arvif);
- + spin_unlock_bh(&arvif->ar->data_lock);
- +
- + return;
- +@@ -923,12 +1144,12 @@ static void ath10k_control_beaconing(str
- + return;
- +
- + arvif->aid = 0;
- +- memcpy(arvif->bssid, info->bssid, ETH_ALEN);
- ++ ether_addr_copy(arvif->bssid, info->bssid);
- +
- + ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
- + arvif->bssid);
- + if (ret) {
- +- ath10k_warn("failed to bring up vdev %d: %i\n",
- ++ ath10k_warn(ar, "failed to bring up vdev %d: %i\n",
- + arvif->vdev_id, ret);
- + ath10k_vdev_stop(arvif);
- + return;
- +@@ -937,13 +1158,14 @@ static void ath10k_control_beaconing(str
- + arvif->is_started = true;
- + arvif->is_up = true;
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
- + }
- +
- + static void ath10k_control_ibss(struct ath10k_vif *arvif,
- + struct ieee80211_bss_conf *info,
- + const u8 self_peer[ETH_ALEN])
- + {
- ++ struct ath10k *ar = arvif->ar;
- + u32 vdev_param;
- + int ret = 0;
- +
- +@@ -952,20 +1174,12 @@ static void ath10k_control_ibss(struct a
- + if (!info->ibss_joined) {
- + ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer);
- + if (ret)
- +- ath10k_warn("failed to delete IBSS self peer %pM for vdev %d: %d\n",
- ++ ath10k_warn(ar, "failed to delete IBSS self peer %pM for vdev %d: %d\n",
- + self_peer, arvif->vdev_id, ret);
- +
- + if (is_zero_ether_addr(arvif->bssid))
- + return;
- +
- +- ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
- +- arvif->bssid);
- +- if (ret) {
- +- ath10k_warn("failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
- +- arvif->bssid, arvif->vdev_id, ret);
- +- return;
- +- }
- +-
- + memset(arvif->bssid, 0, ETH_ALEN);
- +
- + return;
- +@@ -973,7 +1187,7 @@ static void ath10k_control_ibss(struct a
- +
- + ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer);
- + if (ret) {
- +- ath10k_warn("failed to create IBSS self peer %pM for vdev %d: %d\n",
- ++ ath10k_warn(ar, "failed to create IBSS self peer %pM for vdev %d: %d\n",
- + self_peer, arvif->vdev_id, ret);
- + return;
- + }
- +@@ -982,103 +1196,211 @@ static void ath10k_control_ibss(struct a
- + ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param,
- + ATH10K_DEFAULT_ATIM);
- + if (ret)
- +- ath10k_warn("failed to set IBSS ATIM for vdev %d: %d\n",
- ++ ath10k_warn(ar, "failed to set IBSS ATIM for vdev %d: %d\n",
- + arvif->vdev_id, ret);
- + }
- +
- +-/*
- +- * Review this when mac80211 gains per-interface powersave support.
- +- */
- +-static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
- ++static int ath10k_mac_vif_recalc_ps_wake_threshold(struct ath10k_vif *arvif)
- + {
- + struct ath10k *ar = arvif->ar;
- +- struct ieee80211_conf *conf = &ar->hw->conf;
- +- enum wmi_sta_powersave_param param;
- +- enum wmi_sta_ps_mode psmode;
- ++ u32 param;
- ++ u32 value;
- + int ret;
- +
- + lockdep_assert_held(&arvif->ar->conf_mutex);
- +
- +- if (arvif->vif->type != NL80211_IFTYPE_STATION)
- +- return 0;
- +-
- +- if (conf->flags & IEEE80211_CONF_PS) {
- +- psmode = WMI_STA_PS_MODE_ENABLED;
- +- param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
- ++ if (arvif->u.sta.uapsd)
- ++ value = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER;
- ++ else
- ++ value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
- +
- +- ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
- +- conf->dynamic_ps_timeout);
- +- if (ret) {
- +- ath10k_warn("failed to set inactivity time for vdev %d: %i\n",
- +- arvif->vdev_id, ret);
- +- return ret;
- +- }
- +- } else {
- +- psmode = WMI_STA_PS_MODE_DISABLED;
- ++ param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD;
- ++ ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to submit ps wake threshold %u on vdev %i: %d\n",
- ++ value, arvif->vdev_id, ret);
- ++ return ret;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
- +- arvif->vdev_id, psmode ? "enable" : "disable");
- ++ return 0;
- ++}
- +
- +- ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode);
- ++static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif)
- ++{
- ++ struct ath10k *ar = arvif->ar;
- ++ u32 param;
- ++ u32 value;
- ++ int ret;
- ++
- ++ lockdep_assert_held(&arvif->ar->conf_mutex);
- ++
- ++ if (arvif->u.sta.uapsd)
- ++ value = WMI_STA_PS_PSPOLL_COUNT_UAPSD;
- ++ else
- ++ value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
- ++
- ++ param = WMI_STA_PS_PARAM_PSPOLL_COUNT;
- ++ ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
- ++ param, value);
- + if (ret) {
- +- ath10k_warn("failed to set PS Mode %d for vdev %d: %d\n",
- +- psmode, arvif->vdev_id, ret);
- ++ ath10k_warn(ar, "failed to submit ps poll count %u on vdev %i: %d\n",
- ++ value, arvif->vdev_id, ret);
- + return ret;
- + }
- +
- + return 0;
- + }
- +
- +-/**********************/
- +-/* Station management */
- +-/**********************/
- +-
- +-static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
- +- struct ath10k_vif *arvif,
- +- struct ieee80211_sta *sta,
- +- struct ieee80211_bss_conf *bss_conf,
- +- struct wmi_peer_assoc_complete_arg *arg)
- ++static int ath10k_mac_ps_vif_count(struct ath10k *ar)
- + {
- ++ struct ath10k_vif *arvif;
- ++ int num = 0;
- ++
- + lockdep_assert_held(&ar->conf_mutex);
- +
- +- memcpy(arg->addr, sta->addr, ETH_ALEN);
- +- arg->vdev_id = arvif->vdev_id;
- +- arg->peer_aid = sta->aid;
- +- arg->peer_flags |= WMI_PEER_AUTH;
- ++ list_for_each_entry(arvif, &ar->arvifs, list)
- ++ if (arvif->ps)
- ++ num++;
- +
- +- if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
- +- /*
- +- * Seems FW have problems with Power Save in STA
- +- * mode when we setup this parameter to high (eg. 5).
- +- * Often we see that FW don't send NULL (with clean P flags)
- +- * frame even there is info about buffered frames in beacons.
- +- * Sometimes we have to wait more than 10 seconds before FW
- +- * will wakeup. Often sending one ping from AP to our device
- +- * just fail (more than 50%).
- +- *
- +- * Seems setting this FW parameter to 1 couse FW
- +- * will check every beacon and will wakup immediately
- +- * after detection buffered data.
- +- */
- +- arg->peer_listen_intval = 1;
- +- else
- +- arg->peer_listen_intval = ar->hw->conf.listen_interval;
- ++ return num;
- ++}
- +
- +- arg->peer_num_spatial_streams = 1;
- ++static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
- ++{
- ++ struct ath10k *ar = arvif->ar;
- ++ struct ieee80211_vif *vif = arvif->vif;
- ++ struct ieee80211_conf *conf = &ar->hw->conf;
- ++ enum wmi_sta_powersave_param param;
- ++ enum wmi_sta_ps_mode psmode;
- ++ int ret;
- ++ int ps_timeout;
- ++ bool enable_ps;
- +
- +- /*
- +- * The assoc capabilities are available only in managed mode.
- ++ lockdep_assert_held(&arvif->ar->conf_mutex);
- ++
- ++ if (arvif->vif->type != NL80211_IFTYPE_STATION)
- ++ return 0;
- ++
- ++ enable_ps = arvif->ps;
- ++
- ++ if (enable_ps && ath10k_mac_ps_vif_count(ar) > 1 &&
- ++ !test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT,
- ++ ar->fw_features)) {
- ++ ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n",
- ++ arvif->vdev_id);
- ++ enable_ps = false;
- ++ }
- ++
- ++ if (enable_ps) {
- ++ psmode = WMI_STA_PS_MODE_ENABLED;
- ++ param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
- ++
- ++ ps_timeout = conf->dynamic_ps_timeout;
- ++ if (ps_timeout == 0) {
- ++ /* Firmware doesn't like 0 */
- ++ ps_timeout = ieee80211_tu_to_usec(
- ++ vif->bss_conf.beacon_int) / 1000;
- ++ }
- ++
- ++ ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
- ++ ps_timeout);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to set inactivity time for vdev %d: %i\n",
- ++ arvif->vdev_id, ret);
- ++ return ret;
- ++ }
- ++ } else {
- ++ psmode = WMI_STA_PS_MODE_DISABLED;
- ++ }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
- ++ arvif->vdev_id, psmode ? "enable" : "disable");
- ++
- ++ ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to set PS Mode %d for vdev %d: %d\n",
- ++ psmode, arvif->vdev_id, ret);
- ++ return ret;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_mac_vif_disable_keepalive(struct ath10k_vif *arvif)
- ++{
- ++ struct ath10k *ar = arvif->ar;
- ++ struct wmi_sta_keepalive_arg arg = {};
- ++ int ret;
- ++
- ++ lockdep_assert_held(&arvif->ar->conf_mutex);
- ++
- ++ if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
- ++ return 0;
- ++
- ++ if (!test_bit(WMI_SERVICE_STA_KEEP_ALIVE, ar->wmi.svc_map))
- ++ return 0;
- ++
- ++ /* Some firmware revisions have a bug and ignore the `enabled` field.
- ++ * Instead use the interval to disable the keepalive.
- ++ */
- ++ arg.vdev_id = arvif->vdev_id;
- ++ arg.enabled = 1;
- ++ arg.method = WMI_STA_KEEPALIVE_METHOD_NULL_FRAME;
- ++ arg.interval = WMI_STA_KEEPALIVE_INTERVAL_DISABLE;
- ++
- ++ ret = ath10k_wmi_sta_keepalive(ar, &arg);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to submit keepalive on vdev %i: %d\n",
- ++ arvif->vdev_id, ret);
- ++ return ret;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- ++/**********************/
- ++/* Station management */
- ++/**********************/
- ++
- ++static u32 ath10k_peer_assoc_h_listen_intval(struct ath10k *ar,
- ++ struct ieee80211_vif *vif)
- ++{
- ++ /* Some firmware revisions have unstable STA powersave when listen
- ++ * interval is set too high (e.g. 5). The symptoms are firmware doesn't
- ++ * generate NullFunc frames properly even if buffered frames have been
- ++ * indicated in Beacon TIM. Firmware would seldom wake up to pull
- ++ * buffered frames. Often pinging the device from AP would simply fail.
- ++ *
- ++ * As a workaround set it to 1.
- + */
- +- if (arvif->vdev_type == WMI_VDEV_TYPE_STA && bss_conf)
- +- arg->peer_caps = bss_conf->assoc_capability;
- ++ if (vif->type == NL80211_IFTYPE_STATION)
- ++ return 1;
- ++
- ++ return ar->hw->conf.listen_interval;
- ++}
- ++
- ++static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
- ++ struct ieee80211_vif *vif,
- ++ struct ieee80211_sta *sta,
- ++ struct wmi_peer_assoc_complete_arg *arg)
- ++{
- ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- ++
- ++ lockdep_assert_held(&ar->conf_mutex);
- ++
- ++ ether_addr_copy(arg->addr, sta->addr);
- ++ arg->vdev_id = arvif->vdev_id;
- ++ arg->peer_aid = sta->aid;
- ++ arg->peer_flags |= WMI_PEER_AUTH;
- ++ arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif);
- ++ arg->peer_num_spatial_streams = 1;
- ++ arg->peer_caps = vif->bss_conf.assoc_capability;
- + }
- +
- + static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
- +- struct ath10k_vif *arvif,
- ++ struct ieee80211_vif *vif,
- + struct wmi_peer_assoc_complete_arg *arg)
- + {
- +- struct ieee80211_vif *vif = arvif->vif;
- + struct ieee80211_bss_conf *info = &vif->bss_conf;
- + struct cfg80211_bss *bss;
- + const u8 *rsnie = NULL;
- +@@ -1097,21 +1419,21 @@ static void ath10k_peer_assoc_h_crypto(s
- + ies = rcu_dereference(bss->ies);
- +
- + wpaie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
- +- WLAN_OUI_TYPE_MICROSOFT_WPA,
- +- ies->data,
- +- ies->len);
- ++ WLAN_OUI_TYPE_MICROSOFT_WPA,
- ++ ies->data,
- ++ ies->len);
- + rcu_read_unlock();
- + cfg80211_put_bss(ar->hw->wiphy, bss);
- + }
- +
- + /* FIXME: base on RSN IE/WPA IE is a correct idea? */
- + if (rsnie || wpaie) {
- +- ath10k_dbg(ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__);
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__);
- + arg->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
- + }
- +
- + if (wpaie) {
- +- ath10k_dbg(ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__);
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__);
- + arg->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
- + }
- + }
- +@@ -1149,6 +1471,7 @@ static void ath10k_peer_assoc_h_ht(struc
- + {
- + const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
- + int i, n;
- ++ u32 stbc;
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- +@@ -1185,7 +1508,6 @@ static void ath10k_peer_assoc_h_ht(struc
- + }
- +
- + if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) {
- +- u32 stbc;
- + stbc = ht_cap->cap & IEEE80211_HT_CAP_RX_STBC;
- + stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT;
- + stbc = stbc << WMI_RC_RX_STBC_FLAG_S;
- +@@ -1220,7 +1542,7 @@ static void ath10k_peer_assoc_h_ht(struc
- + arg->peer_num_spatial_streams = sta->rx_nss;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
- + arg->addr,
- + arg->peer_ht_rates.num_rates,
- + arg->peer_num_spatial_streams);
- +@@ -1237,7 +1559,7 @@ static int ath10k_peer_assoc_qos_ap(stru
- + lockdep_assert_held(&ar->conf_mutex);
- +
- + if (sta->wme && sta->uapsd_queues) {
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
- + sta->uapsd_queues, sta->max_sp);
- +
- + if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
- +@@ -1253,7 +1575,6 @@ static int ath10k_peer_assoc_qos_ap(stru
- + uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN |
- + WMI_AP_PS_UAPSD_AC0_TRIGGER_EN;
- +
- +-
- + if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP)
- + max_sp = sta->max_sp;
- +
- +@@ -1262,7 +1583,7 @@ static int ath10k_peer_assoc_qos_ap(stru
- + WMI_AP_PS_PEER_PARAM_UAPSD,
- + uapsd);
- + if (ret) {
- +- ath10k_warn("failed to set ap ps peer param uapsd for vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to set ap ps peer param uapsd for vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + return ret;
- + }
- +@@ -1272,7 +1593,7 @@ static int ath10k_peer_assoc_qos_ap(stru
- + WMI_AP_PS_PEER_PARAM_MAX_SP,
- + max_sp);
- + if (ret) {
- +- ath10k_warn("failed to set ap ps peer param max sp for vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to set ap ps peer param max sp for vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + return ret;
- + }
- +@@ -1282,9 +1603,10 @@ static int ath10k_peer_assoc_qos_ap(stru
- + sta->listen_interval - mac80211 patch required.
- + Currently use 10 seconds */
- + ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr,
- +- WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10);
- ++ WMI_AP_PS_PEER_PARAM_AGEOUT_TIME,
- ++ 10);
- + if (ret) {
- +- ath10k_warn("failed to set ap ps peer param ageout time for vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to set ap ps peer param ageout time for vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + return ret;
- + }
- +@@ -1304,8 +1626,11 @@ static void ath10k_peer_assoc_h_vht(stru
- + return;
- +
- + arg->peer_flags |= WMI_PEER_VHT;
- +- arg->peer_vht_caps = vht_cap->cap;
- +
- ++ if (ar->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
- ++ arg->peer_flags |= WMI_PEER_VHT_2G;
- ++
- ++ arg->peer_vht_caps = vht_cap->cap;
- +
- + ampdu_factor = (vht_cap->cap &
- + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
- +@@ -1331,16 +1656,17 @@ static void ath10k_peer_assoc_h_vht(stru
- + arg->peer_vht_rates.tx_mcs_set =
- + __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
- + sta->addr, arg->peer_max_mpdu, arg->peer_flags);
- + }
- +
- + static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
- +- struct ath10k_vif *arvif,
- ++ struct ieee80211_vif *vif,
- + struct ieee80211_sta *sta,
- +- struct ieee80211_bss_conf *bss_conf,
- + struct wmi_peer_assoc_complete_arg *arg)
- + {
- ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- ++
- + switch (arvif->vdev_type) {
- + case WMI_VDEV_TYPE_AP:
- + if (sta->wme)
- +@@ -1352,16 +1678,29 @@ static void ath10k_peer_assoc_h_qos(stru
- + }
- + break;
- + case WMI_VDEV_TYPE_STA:
- +- if (bss_conf->qos)
- ++ if (vif->bss_conf.qos)
- ++ arg->peer_flags |= WMI_PEER_QOS;
- ++ break;
- ++ case WMI_VDEV_TYPE_IBSS:
- ++ if (sta->wme)
- + arg->peer_flags |= WMI_PEER_QOS;
- + break;
- + default:
- + break;
- + }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM qos %d\n",
- ++ sta->addr, !!(arg->peer_flags & WMI_PEER_QOS));
- ++}
- ++
- ++static bool ath10k_mac_sta_has_11g_rates(struct ieee80211_sta *sta)
- ++{
- ++ /* First 4 rates in ath10k_rates are CCK (11b) rates. */
- ++ return sta->supp_rates[IEEE80211_BAND_2GHZ] >> 4;
- + }
- +
- + static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
- +- struct ath10k_vif *arvif,
- ++ struct ieee80211_vif *vif,
- + struct ieee80211_sta *sta,
- + struct wmi_peer_assoc_complete_arg *arg)
- + {
- +@@ -1369,13 +1708,20 @@ static void ath10k_peer_assoc_h_phymode(
- +
- + switch (ar->hw->conf.chandef.chan->band) {
- + case IEEE80211_BAND_2GHZ:
- +- if (sta->ht_cap.ht_supported) {
- ++ if (sta->vht_cap.vht_supported) {
- ++ if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
- ++ phymode = MODE_11AC_VHT40;
- ++ else
- ++ phymode = MODE_11AC_VHT20;
- ++ } else if (sta->ht_cap.ht_supported) {
- + if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
- + phymode = MODE_11NG_HT40;
- + else
- + phymode = MODE_11NG_HT20;
- +- } else {
- ++ } else if (ath10k_mac_sta_has_11g_rates(sta)) {
- + phymode = MODE_11G;
- ++ } else {
- ++ phymode = MODE_11B;
- + }
- +
- + break;
- +@@ -1404,7 +1750,7 @@ static void ath10k_peer_assoc_h_phymode(
- + break;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac peer %pM phymode %s\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM phymode %s\n",
- + sta->addr, ath10k_wmi_phymode_str(phymode));
- +
- + arg->peer_phymode = phymode;
- +@@ -1412,22 +1758,21 @@ static void ath10k_peer_assoc_h_phymode(
- + }
- +
- + static int ath10k_peer_assoc_prepare(struct ath10k *ar,
- +- struct ath10k_vif *arvif,
- ++ struct ieee80211_vif *vif,
- + struct ieee80211_sta *sta,
- +- struct ieee80211_bss_conf *bss_conf,
- + struct wmi_peer_assoc_complete_arg *arg)
- + {
- + lockdep_assert_held(&ar->conf_mutex);
- +
- + memset(arg, 0, sizeof(*arg));
- +
- +- ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, arg);
- +- ath10k_peer_assoc_h_crypto(ar, arvif, arg);
- ++ ath10k_peer_assoc_h_basic(ar, vif, sta, arg);
- ++ ath10k_peer_assoc_h_crypto(ar, vif, arg);
- + ath10k_peer_assoc_h_rates(ar, sta, arg);
- + ath10k_peer_assoc_h_ht(ar, sta, arg);
- + ath10k_peer_assoc_h_vht(ar, sta, arg);
- +- ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, arg);
- +- ath10k_peer_assoc_h_phymode(ar, arvif, sta, arg);
- ++ ath10k_peer_assoc_h_qos(ar, vif, sta, arg);
- ++ ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
- +
- + return 0;
- + }
- +@@ -1459,6 +1804,68 @@ static int ath10k_setup_peer_smps(struct
- + ath10k_smps_map[smps]);
- + }
- +
- ++static int ath10k_mac_vif_recalc_txbf(struct ath10k *ar,
- ++ struct ieee80211_vif *vif,
- ++ struct ieee80211_sta_vht_cap vht_cap)
- ++{
- ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- ++ int ret;
- ++ u32 param;
- ++ u32 value;
- ++
- ++ if (!(ar->vht_cap_info &
- ++ (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
- ++ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
- ++ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
- ++ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)))
- ++ return 0;
- ++
- ++ param = ar->wmi.vdev_param->txbf;
- ++ value = 0;
- ++
- ++ if (WARN_ON(param == WMI_VDEV_PARAM_UNSUPPORTED))
- ++ return 0;
- ++
- ++ /* The following logic is correct. If a remote STA advertises support
- ++ * for being a beamformer then we should enable us being a beamformee.
- ++ */
- ++
- ++ if (ar->vht_cap_info &
- ++ (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
- ++ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) {
- ++ if (vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)
- ++ value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE;
- ++
- ++ if (vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)
- ++ value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFEE;
- ++ }
- ++
- ++ if (ar->vht_cap_info &
- ++ (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
- ++ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
- ++ if (vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)
- ++ value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER;
- ++
- ++ if (vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)
- ++ value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFER;
- ++ }
- ++
- ++ if (value & WMI_VDEV_PARAM_TXBF_MU_TX_BFEE)
- ++ value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE;
- ++
- ++ if (value & WMI_VDEV_PARAM_TXBF_MU_TX_BFER)
- ++ value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER;
- ++
- ++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, value);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to submit vdev param txbf 0x%x: %d\n",
- ++ value, ret);
- ++ return ret;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- + /* can be called only in mac80211 callbacks due to `key_count` usage */
- + static void ath10k_bss_assoc(struct ieee80211_hw *hw,
- + struct ieee80211_vif *vif,
- +@@ -1467,17 +1874,21 @@ static void ath10k_bss_assoc(struct ieee
- + struct ath10k *ar = hw->priv;
- + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- + struct ieee80211_sta_ht_cap ht_cap;
- ++ struct ieee80211_sta_vht_cap vht_cap;
- + struct wmi_peer_assoc_complete_arg peer_arg;
- + struct ieee80211_sta *ap_sta;
- + int ret;
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n",
- ++ arvif->vdev_id, arvif->bssid, arvif->aid);
- ++
- + rcu_read_lock();
- +
- + ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);
- + if (!ap_sta) {
- +- ath10k_warn("failed to find station entry for bss %pM vdev %i\n",
- ++ ath10k_warn(ar, "failed to find station entry for bss %pM vdev %i\n",
- + bss_conf->bssid, arvif->vdev_id);
- + rcu_read_unlock();
- + return;
- +@@ -1486,11 +1897,11 @@ static void ath10k_bss_assoc(struct ieee
- + /* ap_sta must be accessed only within rcu section which must be left
- + * before calling ath10k_setup_peer_smps() which might sleep. */
- + ht_cap = ap_sta->ht_cap;
- ++ vht_cap = ap_sta->vht_cap;
- +
- +- ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
- +- bss_conf, &peer_arg);
- ++ ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg);
- + if (ret) {
- +- ath10k_warn("failed to prepare peer assoc for %pM vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n",
- + bss_conf->bssid, arvif->vdev_id, ret);
- + rcu_read_unlock();
- + return;
- +@@ -1500,88 +1911,100 @@ static void ath10k_bss_assoc(struct ieee
- +
- + ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
- + if (ret) {
- +- ath10k_warn("failed to run peer assoc for %pM vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to run peer assoc for %pM vdev %i: %d\n",
- + bss_conf->bssid, arvif->vdev_id, ret);
- + return;
- + }
- +
- + ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap);
- + if (ret) {
- +- ath10k_warn("failed to setup peer SMPS for vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to setup peer SMPS for vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + return;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_MAC,
- ++ ret = ath10k_mac_vif_recalc_txbf(ar, vif, vht_cap);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to recalc txbf for vdev %i on bss %pM: %d\n",
- ++ arvif->vdev_id, bss_conf->bssid, ret);
- ++ return;
- ++ }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC,
- + "mac vdev %d up (associated) bssid %pM aid %d\n",
- + arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
- +
- ++ WARN_ON(arvif->is_up);
- ++
- + arvif->aid = bss_conf->aid;
- +- memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN);
- ++ ether_addr_copy(arvif->bssid, bss_conf->bssid);
- +
- + ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
- + if (ret) {
- +- ath10k_warn("failed to set vdev %d up: %d\n",
- ++ ath10k_warn(ar, "failed to set vdev %d up: %d\n",
- + arvif->vdev_id, ret);
- + return;
- + }
- +
- + arvif->is_up = true;
- ++
- ++ /* Workaround: Some firmware revisions (tested with qca6174
- ++ * WLAN.RM.2.0-00073) have buggy powersave state machine and must be
- ++ * poked with peer param command.
- ++ */
- ++ ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, arvif->bssid,
- ++ WMI_PEER_DUMMY_VAR, 1);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to poke peer %pM param for ps workaround on vdev %i: %d\n",
- ++ arvif->bssid, arvif->vdev_id, ret);
- ++ return;
- ++ }
- + }
- +
- +-/*
- +- * FIXME: flush TIDs
- +- */
- + static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
- + struct ieee80211_vif *vif)
- + {
- + struct ath10k *ar = hw->priv;
- + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- ++ struct ieee80211_sta_vht_cap vht_cap = {};
- + int ret;
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- +- /*
- +- * For some reason, calling VDEV-DOWN before VDEV-STOP
- +- * makes the FW to send frames via HTT after disassociation.
- +- * No idea why this happens, even though VDEV-DOWN is supposed
- +- * to be analogous to link down, so just stop the VDEV.
- +- */
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
- +- arvif->vdev_id);
- +-
- +- /* FIXME: check return value */
- +- ret = ath10k_vdev_stop(arvif);
- +-
- +- /*
- +- * If we don't call VDEV-DOWN after VDEV-STOP FW will remain active and
- +- * report beacons from previously associated network through HTT.
- +- * This in turn would spam mac80211 WARN_ON if we bring down all
- +- * interfaces as it expects there is no rx when no interface is
- +- * running.
- +- */
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n",
- ++ arvif->vdev_id, arvif->bssid);
- +
- +- /* FIXME: why don't we print error if wmi call fails? */
- + ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
- ++ if (ret)
- ++ ath10k_warn(ar, "faield to down vdev %i: %d\n",
- ++ arvif->vdev_id, ret);
- +
- +- arvif->def_wep_key_idx = 0;
- ++ arvif->def_wep_key_idx = -1;
- ++
- ++ ret = ath10k_mac_vif_recalc_txbf(ar, vif, vht_cap);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to recalc txbf for vdev %i: %d\n",
- ++ arvif->vdev_id, ret);
- ++ return;
- ++ }
- +
- +- arvif->is_started = false;
- + arvif->is_up = false;
- + }
- +
- +-static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
- +- struct ieee80211_sta *sta, bool reassoc)
- ++static int ath10k_station_assoc(struct ath10k *ar,
- ++ struct ieee80211_vif *vif,
- ++ struct ieee80211_sta *sta,
- ++ bool reassoc)
- + {
- ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- + struct wmi_peer_assoc_complete_arg peer_arg;
- + int ret = 0;
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- +- ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
- ++ ret = ath10k_peer_assoc_prepare(ar, vif, sta, &peer_arg);
- + if (ret) {
- +- ath10k_warn("failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
- ++ ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
- + sta->addr, arvif->vdev_id, ret);
- + return ret;
- + }
- +@@ -1589,48 +2012,59 @@ static int ath10k_station_assoc(struct a
- + peer_arg.peer_reassoc = reassoc;
- + ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
- + if (ret) {
- +- ath10k_warn("failed to run peer assoc for STA %pM vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to run peer assoc for STA %pM vdev %i: %d\n",
- + sta->addr, arvif->vdev_id, ret);
- + return ret;
- + }
- +
- +- ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
- +- if (ret) {
- +- ath10k_warn("failed to setup peer SMPS for vdev %d: %d\n",
- +- arvif->vdev_id, ret);
- +- return ret;
- +- }
- +-
- +- if (!sta->wme) {
- +- arvif->num_legacy_stations++;
- +- ret = ath10k_recalc_rtscts_prot(arvif);
- ++ /* Re-assoc is run only to update supported rates for given station. It
- ++ * doesn't make much sense to reconfigure the peer completely.
- ++ */
- ++ if (!reassoc) {
- ++ ret = ath10k_setup_peer_smps(ar, arvif, sta->addr,
- ++ &sta->ht_cap);
- + if (ret) {
- +- ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
- ++ ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n",
- + arvif->vdev_id, ret);
- + return ret;
- + }
- +- }
- +
- +- ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
- +- if (ret) {
- +- ath10k_warn("failed to install peer wep keys for vdev %i: %d\n",
- +- arvif->vdev_id, ret);
- +- return ret;
- +- }
- ++ ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n",
- ++ sta->addr, arvif->vdev_id, ret);
- ++ return ret;
- ++ }
- +
- +- ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
- +- if (ret) {
- +- ath10k_warn("failed to set qos params for STA %pM for vdev %i: %d\n",
- +- sta->addr, arvif->vdev_id, ret);
- +- return ret;
- ++ if (!sta->wme) {
- ++ arvif->num_legacy_stations++;
- ++ ret = ath10k_recalc_rtscts_prot(arvif);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
- ++ arvif->vdev_id, ret);
- ++ return ret;
- ++ }
- ++ }
- ++
- ++ /* Plumb cached keys only for static WEP */
- ++ if (arvif->def_wep_key_idx != -1) {
- ++ ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
- ++ arvif->vdev_id, ret);
- ++ return ret;
- ++ }
- ++ }
- + }
- +
- + return ret;
- + }
- +
- +-static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
- ++static int ath10k_station_disassoc(struct ath10k *ar,
- ++ struct ieee80211_vif *vif,
- + struct ieee80211_sta *sta)
- + {
- ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- + int ret = 0;
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +@@ -1639,7 +2073,7 @@ static int ath10k_station_disassoc(struc
- + arvif->num_legacy_stations--;
- + ret = ath10k_recalc_rtscts_prot(arvif);
- + if (ret) {
- +- ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
- ++ ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
- + arvif->vdev_id, ret);
- + return ret;
- + }
- +@@ -1647,7 +2081,7 @@ static int ath10k_station_disassoc(struc
- +
- + ret = ath10k_clear_peer_keys(arvif, sta->addr);
- + if (ret) {
- +- ath10k_warn("failed to clear all peer wep keys for vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to clear all peer wep keys for vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + return ret;
- + }
- +@@ -1722,6 +2156,7 @@ static int ath10k_update_channel_list(st
- + ch->passive = passive;
- +
- + ch->freq = channel->center_freq;
- ++ ch->band_center_freq1 = channel->center_freq;
- + ch->min_power = 0;
- + ch->max_power = channel->max_power * 2;
- + ch->max_reg_power = channel->max_reg_power * 2;
- +@@ -1739,7 +2174,7 @@ static int ath10k_update_channel_list(st
- + if (WARN_ON_ONCE(ch->mode == MODE_UNKNOWN))
- + continue;
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "mac channel [%zd/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n",
- + ch - arg.channels, arg.n_channels,
- + ch->freq, ch->max_power, ch->max_reg_power,
- +@@ -1782,7 +2217,7 @@ static void ath10k_regd_update(struct at
- +
- + ret = ath10k_update_channel_list(ar);
- + if (ret)
- +- ath10k_warn("failed to update channel list: %d\n", ret);
- ++ ath10k_warn(ar, "failed to update channel list: %d\n", ret);
- +
- + regpair = ar->ath_common.regulatory.regpair;
- +
- +@@ -1803,7 +2238,7 @@ static void ath10k_regd_update(struct at
- + regpair->reg_5ghz_ctl,
- + wmi_dfs_reg);
- + if (ret)
- +- ath10k_warn("failed to set pdev regdomain: %d\n", ret);
- ++ ath10k_warn(ar, "failed to set pdev regdomain: %d\n", ret);
- + }
- +
- + static void ath10k_reg_notifier(struct wiphy *wiphy,
- +@@ -1816,12 +2251,12 @@ static void ath10k_reg_notifier(struct w
- + ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory);
- +
- + if (config_enabled(CPTCFG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
- +- ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
- + request->dfs_region);
- + result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector,
- + request->dfs_region);
- + if (!result)
- +- ath10k_warn("DFS region 0x%X not supported, will trigger radar for every pulse\n",
- ++ ath10k_warn(ar, "DFS region 0x%X not supported, will trigger radar for every pulse\n",
- + request->dfs_region);
- + }
- +
- +@@ -1849,28 +2284,25 @@ static u8 ath10k_tx_h_get_tid(struct iee
- + return ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
- + }
- +
- +-static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar,
- +- struct ieee80211_tx_info *info)
- ++static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif)
- + {
- +- if (info->control.vif)
- +- return ath10k_vif_to_arvif(info->control.vif)->vdev_id;
- ++ if (vif)
- ++ return ath10k_vif_to_arvif(vif)->vdev_id;
- +
- + if (ar->monitor_started)
- + return ar->monitor_vdev_id;
- +
- +- ath10k_warn("failed to resolve vdev id\n");
- ++ ath10k_warn(ar, "failed to resolve vdev id\n");
- + return 0;
- + }
- +
- +-/*
- +- * Frames sent to the FW have to be in "Native Wifi" format.
- +- * Strip the QoS field from the 802.11 header.
- ++/* HTT Tx uses Native Wifi tx mode which expects 802.11 frames without QoS
- ++ * Control in the header.
- + */
- +-static void ath10k_tx_h_qos_workaround(struct ieee80211_hw *hw,
- +- struct ieee80211_tx_control *control,
- +- struct sk_buff *skb)
- ++static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb)
- + {
- + struct ieee80211_hdr *hdr = (void *)skb->data;
- ++ struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb);
- + u8 *qos_ctl;
- +
- + if (!ieee80211_is_data_qos(hdr->frame_control))
- +@@ -1880,68 +2312,24 @@ static void ath10k_tx_h_qos_workaround(s
- + memmove(skb->data + IEEE80211_QOS_CTL_LEN,
- + skb->data, (void *)qos_ctl - (void *)skb->data);
- + skb_pull(skb, IEEE80211_QOS_CTL_LEN);
- +-}
- +-
- +-static void ath10k_tx_wep_key_work(struct work_struct *work)
- +-{
- +- struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
- +- wep_key_work);
- +- int ret, keyidx = arvif->def_wep_key_newidx;
- +-
- +- if (arvif->def_wep_key_idx == keyidx)
- +- return;
- +-
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
- +- arvif->vdev_id, keyidx);
- +
- +- ret = ath10k_wmi_vdev_set_param(arvif->ar,
- +- arvif->vdev_id,
- +- arvif->ar->wmi.vdev_param->def_keyid,
- +- keyidx);
- +- if (ret) {
- +- ath10k_warn("failed to update wep key index for vdev %d: %d\n",
- +- arvif->vdev_id,
- +- ret);
- +- return;
- ++ /* Fw/Hw generates a corrupted QoS Control Field for QoS NullFunc
- ++ * frames. Powersave is handled by the fw/hw so QoS NyllFunc frames are
- ++ * used only for CQM purposes (e.g. hostapd station keepalive ping) so
- ++ * it is safe to downgrade to NullFunc.
- ++ */
- ++ hdr = (void *)skb->data;
- ++ if (ieee80211_is_qos_nullfunc(hdr->frame_control)) {
- ++ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
- ++ cb->htt.tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
- + }
- +-
- +- arvif->def_wep_key_idx = keyidx;
- + }
- +
- +-static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
- +-{
- +- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- +- struct ieee80211_vif *vif = info->control.vif;
- +- struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- +- struct ath10k *ar = arvif->ar;
- +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- +- struct ieee80211_key_conf *key = info->control.hw_key;
- +-
- +- if (!ieee80211_has_protected(hdr->frame_control))
- +- return;
- +-
- +- if (!key)
- +- return;
- +-
- +- if (key->cipher != WLAN_CIPHER_SUITE_WEP40 &&
- +- key->cipher != WLAN_CIPHER_SUITE_WEP104)
- +- return;
- +-
- +- if (key->keyidx == arvif->def_wep_key_idx)
- +- return;
- +-
- +- /* FIXME: Most likely a few frames will be TXed with an old key. Simply
- +- * queueing frames until key index is updated is not an option because
- +- * sk_buff may need more processing to be done, e.g. offchannel */
- +- arvif->def_wep_key_newidx = key->keyidx;
- +- ieee80211_queue_work(ar->hw, &arvif->wep_key_work);
- +-}
- +-
- +-static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar, struct sk_buff *skb)
- ++static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
- ++ struct ieee80211_vif *vif,
- ++ struct sk_buff *skb)
- + {
- + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- +- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- +- struct ieee80211_vif *vif = info->control.vif;
- + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- +
- + /* This is case only for P2P_GO */
- +@@ -1961,6 +2349,18 @@ static void ath10k_tx_h_add_p2p_noa_ie(s
- + }
- + }
- +
- ++static bool ath10k_mac_need_offchan_tx_work(struct ath10k *ar)
- ++{
- ++ /* FIXME: Not really sure since when the behaviour changed. At some
- ++ * point new firmware stopped requiring creation of peer entries for
- ++ * offchannel tx (and actually creating them causes issues with wmi-htc
- ++ * tx credit replenishment and reliability). Assuming it's at least 3.4
- ++ * because that's when the `freq` was introduced to TX_FRM HTT command.
- ++ */
- ++ return !(ar->htt.target_version_major >= 3 &&
- ++ ar->htt.target_version_minor >= 4);
- ++}
- ++
- + static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
- + {
- + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- +@@ -1977,7 +2377,7 @@ static void ath10k_tx_htt(struct ath10k
- + ar->fw_features)) {
- + if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >=
- + ATH10K_MAX_NUM_MGMT_PENDING) {
- +- ath10k_warn("reached WMI management tranmist queue limit\n");
- ++ ath10k_warn(ar, "reached WMI management transmit queue limit\n");
- + ret = -EBUSY;
- + goto exit;
- + }
- +@@ -2001,7 +2401,8 @@ static void ath10k_tx_htt(struct ath10k
- +
- + exit:
- + if (ret) {
- +- ath10k_warn("failed to transmit packet, dropping: %d\n", ret);
- ++ ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
- ++ ret);
- + ieee80211_free_txskb(ar->hw, skb);
- + }
- + }
- +@@ -2043,7 +2444,7 @@ void ath10k_offchan_tx_work(struct work_
- +
- + mutex_lock(&ar->conf_mutex);
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac offchannel skb %p\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %p\n",
- + skb);
- +
- + hdr = (struct ieee80211_hdr *)skb->data;
- +@@ -2056,13 +2457,13 @@ void ath10k_offchan_tx_work(struct work_
- +
- + if (peer)
- + /* FIXME: should this use ath10k_warn()? */
- +- ath10k_dbg(ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n",
- + peer_addr, vdev_id);
- +
- + if (!peer) {
- + ret = ath10k_peer_create(ar, vdev_id, peer_addr);
- + if (ret)
- +- ath10k_warn("failed to create peer %pM on vdev %d: %d\n",
- ++ ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n",
- + peer_addr, vdev_id, ret);
- + }
- +
- +@@ -2075,14 +2476,14 @@ void ath10k_offchan_tx_work(struct work_
- +
- + ret = wait_for_completion_timeout(&ar->offchan_tx_completed,
- + 3 * HZ);
- +- if (ret <= 0)
- +- ath10k_warn("timed out waiting for offchannel skb %p\n",
- ++ if (ret == 0)
- ++ ath10k_warn(ar, "timed out waiting for offchannel skb %p\n",
- + skb);
- +
- + if (!peer) {
- + ret = ath10k_peer_delete(ar, vdev_id, peer_addr);
- + if (ret)
- +- ath10k_warn("failed to delete peer %pM on vdev %d: %d\n",
- ++ ath10k_warn(ar, "failed to delete peer %pM on vdev %d: %d\n",
- + peer_addr, vdev_id, ret);
- + }
- +
- +@@ -2116,7 +2517,7 @@ void ath10k_mgmt_over_wmi_tx_work(struct
- +
- + ret = ath10k_wmi_mgmt_tx(ar, skb);
- + if (ret) {
- +- ath10k_warn("failed to transmit management frame via WMI: %d\n",
- ++ ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n",
- + ret);
- + ieee80211_free_txskb(ar->hw, skb);
- + }
- +@@ -2127,34 +2528,41 @@ void ath10k_mgmt_over_wmi_tx_work(struct
- + /* Scanning */
- + /************/
- +
- +-/*
- +- * This gets called if we dont get a heart-beat during scan.
- +- * This may indicate the FW has hung and we need to abort the
- +- * scan manually to prevent cancel_hw_scan() from deadlocking
- +- */
- +-void ath10k_reset_scan(unsigned long ptr)
- ++void __ath10k_scan_finish(struct ath10k *ar)
- + {
- +- struct ath10k *ar = (struct ath10k *)ptr;
- +-
- +- spin_lock_bh(&ar->data_lock);
- +- if (!ar->scan.in_progress) {
- +- spin_unlock_bh(&ar->data_lock);
- +- return;
- +- }
- ++ lockdep_assert_held(&ar->data_lock);
- +
- +- ath10k_warn("scan timed out, firmware problem?\n");
- +-
- +- if (ar->scan.is_roc)
- +- ieee80211_remain_on_channel_expired(ar->hw);
- +- else
- +- ieee80211_scan_completed(ar->hw, 1 /* aborted */);
- ++ switch (ar->scan.state) {
- ++ case ATH10K_SCAN_IDLE:
- ++ break;
- ++ case ATH10K_SCAN_RUNNING:
- ++ if (ar->scan.is_roc)
- ++ ieee80211_remain_on_channel_expired(ar->hw);
- ++ /* fall through */
- ++ case ATH10K_SCAN_ABORTING:
- ++ if (!ar->scan.is_roc)
- ++ ieee80211_scan_completed(ar->hw,
- ++ (ar->scan.state ==
- ++ ATH10K_SCAN_ABORTING));
- ++ /* fall through */
- ++ case ATH10K_SCAN_STARTING:
- ++ ar->scan.state = ATH10K_SCAN_IDLE;
- ++ ar->scan_channel = NULL;
- ++ ath10k_offchan_tx_purge(ar);
- ++ cancel_delayed_work(&ar->scan.timeout);
- ++ complete_all(&ar->scan.completed);
- ++ break;
- ++ }
- ++}
- +
- +- ar->scan.in_progress = false;
- +- complete_all(&ar->scan.completed);
- ++void ath10k_scan_finish(struct ath10k *ar)
- ++{
- ++ spin_lock_bh(&ar->data_lock);
- ++ __ath10k_scan_finish(ar);
- + spin_unlock_bh(&ar->data_lock);
- + }
- +
- +-static int ath10k_abort_scan(struct ath10k *ar)
- ++static int ath10k_scan_stop(struct ath10k *ar)
- + {
- + struct wmi_stop_scan_arg arg = {
- + .req_id = 1, /* FIXME */
- +@@ -2165,47 +2573,79 @@ static int ath10k_abort_scan(struct ath1
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- +- del_timer_sync(&ar->scan.timeout);
- ++ ret = ath10k_wmi_stop_scan(ar, &arg);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to stop wmi scan: %d\n", ret);
- ++ goto out;
- ++ }
- +
- +- spin_lock_bh(&ar->data_lock);
- +- if (!ar->scan.in_progress) {
- +- spin_unlock_bh(&ar->data_lock);
- +- return 0;
- ++ ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ);
- ++ if (ret == 0) {
- ++ ath10k_warn(ar, "failed to receive scan abortion completion: timed out\n");
- ++ ret = -ETIMEDOUT;
- ++ } else if (ret > 0) {
- ++ ret = 0;
- + }
- +
- +- ar->scan.aborting = true;
- ++out:
- ++ /* Scan state should be updated upon scan completion but in case
- ++ * firmware fails to deliver the event (for whatever reason) it is
- ++ * desired to clean up scan state anyway. Firmware may have just
- ++ * dropped the scan completion event delivery due to transport pipe
- ++ * being overflown with data and/or it can recover on its own before
- ++ * next scan request is submitted.
- ++ */
- ++ spin_lock_bh(&ar->data_lock);
- ++ if (ar->scan.state != ATH10K_SCAN_IDLE)
- ++ __ath10k_scan_finish(ar);
- + spin_unlock_bh(&ar->data_lock);
- +
- +- ret = ath10k_wmi_stop_scan(ar, &arg);
- +- if (ret) {
- +- ath10k_warn("failed to stop wmi scan: %d\n", ret);
- +- spin_lock_bh(&ar->data_lock);
- +- ar->scan.in_progress = false;
- +- ath10k_offchan_tx_purge(ar);
- +- spin_unlock_bh(&ar->data_lock);
- +- return -EIO;
- +- }
- ++ return ret;
- ++}
- +
- +- ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ);
- +- if (ret == 0)
- +- ath10k_warn("timed out while waiting for scan to stop\n");
- ++static void ath10k_scan_abort(struct ath10k *ar)
- ++{
- ++ int ret;
- +
- +- /* scan completion may be done right after we timeout here, so let's
- +- * check the in_progress and tell mac80211 scan is completed. if we
- +- * don't do that and FW fails to send us scan completion indication
- +- * then userspace won't be able to scan anymore */
- +- ret = 0;
- ++ lockdep_assert_held(&ar->conf_mutex);
- +
- + spin_lock_bh(&ar->data_lock);
- +- if (ar->scan.in_progress) {
- +- ath10k_warn("failed to stop scan, it's still in progress\n");
- +- ar->scan.in_progress = false;
- +- ath10k_offchan_tx_purge(ar);
- +- ret = -ETIMEDOUT;
- ++
- ++ switch (ar->scan.state) {
- ++ case ATH10K_SCAN_IDLE:
- ++ /* This can happen if timeout worker kicked in and called
- ++ * abortion while scan completion was being processed.
- ++ */
- ++ break;
- ++ case ATH10K_SCAN_STARTING:
- ++ case ATH10K_SCAN_ABORTING:
- ++ ath10k_warn(ar, "refusing scan abortion due to invalid scan state: %s (%d)\n",
- ++ ath10k_scan_state_str(ar->scan.state),
- ++ ar->scan.state);
- ++ break;
- ++ case ATH10K_SCAN_RUNNING:
- ++ ar->scan.state = ATH10K_SCAN_ABORTING;
- ++ spin_unlock_bh(&ar->data_lock);
- ++
- ++ ret = ath10k_scan_stop(ar);
- ++ if (ret)
- ++ ath10k_warn(ar, "failed to abort scan: %d\n", ret);
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++ break;
- + }
- ++
- + spin_unlock_bh(&ar->data_lock);
- ++}
- +
- +- return ret;
- ++void ath10k_scan_timeout_work(struct work_struct *work)
- ++{
- ++ struct ath10k *ar = container_of(work, struct ath10k,
- ++ scan.timeout.work);
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ ath10k_scan_abort(ar);
- ++ mutex_unlock(&ar->conf_mutex);
- + }
- +
- + static int ath10k_start_scan(struct ath10k *ar,
- +@@ -2221,17 +2661,27 @@ static int ath10k_start_scan(struct ath1
- +
- + ret = wait_for_completion_timeout(&ar->scan.started, 1*HZ);
- + if (ret == 0) {
- +- ath10k_abort_scan(ar);
- +- return ret;
- ++ ret = ath10k_scan_stop(ar);
- ++ if (ret)
- ++ ath10k_warn(ar, "failed to stop scan: %d\n", ret);
- ++
- ++ return -ETIMEDOUT;
- ++ }
- ++
- ++ /* If we failed to start the scan, return error code at
- ++ * this point. This is probably due to some issue in the
- ++ * firmware, but no need to wedge the driver due to that...
- ++ */
- ++ spin_lock_bh(&ar->data_lock);
- ++ if (ar->scan.state == ATH10K_SCAN_IDLE) {
- ++ spin_unlock_bh(&ar->data_lock);
- ++ return -EINVAL;
- + }
- ++ spin_unlock_bh(&ar->data_lock);
- +
- +- /* the scan can complete earlier, before we even
- +- * start the timer. in that case the timer handler
- +- * checks ar->scan.in_progress and bails out if its
- +- * false. Add a 200ms margin to account event/command
- +- * processing. */
- +- mod_timer(&ar->scan.timeout, jiffies +
- +- msecs_to_jiffies(arg->max_scan_time+200));
- ++ /* Add a 200ms margin to account for event/command processing */
- ++ ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
- ++ msecs_to_jiffies(arg->max_scan_time+200));
- + return 0;
- + }
- +
- +@@ -2243,90 +2693,163 @@ static void ath10k_tx(struct ieee80211_h
- + struct ieee80211_tx_control *control,
- + struct sk_buff *skb)
- + {
- ++ struct ath10k *ar = hw->priv;
- + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- ++ struct ieee80211_vif *vif = info->control.vif;
- + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- +- struct ath10k *ar = hw->priv;
- +- u8 tid, vdev_id;
- +
- + /* We should disable CCK RATE due to P2P */
- + if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
- +- ath10k_dbg(ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
- +
- +- /* we must calculate tid before we apply qos workaround
- +- * as we'd lose the qos control field */
- +- tid = ath10k_tx_h_get_tid(hdr);
- +- vdev_id = ath10k_tx_h_get_vdev_id(ar, info);
- ++ ATH10K_SKB_CB(skb)->htt.is_offchan = false;
- ++ ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
- ++ ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);
- +
- + /* it makes no sense to process injected frames like that */
- +- if (info->control.vif &&
- +- info->control.vif->type != NL80211_IFTYPE_MONITOR) {
- +- ath10k_tx_h_qos_workaround(hw, control, skb);
- +- ath10k_tx_h_update_wep_key(skb);
- +- ath10k_tx_h_add_p2p_noa_ie(ar, skb);
- +- ath10k_tx_h_seq_no(skb);
- ++ if (vif && vif->type != NL80211_IFTYPE_MONITOR) {
- ++ ath10k_tx_h_nwifi(hw, skb);
- ++ ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb);
- ++ ath10k_tx_h_seq_no(vif, skb);
- + }
- +
- +- ATH10K_SKB_CB(skb)->vdev_id = vdev_id;
- +- ATH10K_SKB_CB(skb)->htt.is_offchan = false;
- +- ATH10K_SKB_CB(skb)->htt.tid = tid;
- +-
- + if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
- + spin_lock_bh(&ar->data_lock);
- +- ATH10K_SKB_CB(skb)->htt.is_offchan = true;
- ++ ATH10K_SKB_CB(skb)->htt.freq = ar->scan.roc_freq;
- + ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id;
- + spin_unlock_bh(&ar->data_lock);
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "queued offchannel skb %p\n", skb);
- ++ if (ath10k_mac_need_offchan_tx_work(ar)) {
- ++ ATH10K_SKB_CB(skb)->htt.freq = 0;
- ++ ATH10K_SKB_CB(skb)->htt.is_offchan = true;
- +
- +- skb_queue_tail(&ar->offchan_tx_queue, skb);
- +- ieee80211_queue_work(hw, &ar->offchan_tx_work);
- +- return;
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
- ++ skb);
- ++
- ++ skb_queue_tail(&ar->offchan_tx_queue, skb);
- ++ ieee80211_queue_work(hw, &ar->offchan_tx_work);
- ++ return;
- ++ }
- + }
- +
- + ath10k_tx_htt(ar, skb);
- + }
- +
- +-/*
- +- * Initialize various parameters with default vaules.
- +- */
- ++/* Must not be called with conf_mutex held as workers can use that also. */
- ++void ath10k_drain_tx(struct ath10k *ar)
- ++{
- ++ /* make sure rcu-protected mac80211 tx path itself is drained */
- ++ synchronize_net();
- ++
- ++ ath10k_offchan_tx_purge(ar);
- ++ ath10k_mgmt_over_wmi_tx_purge(ar);
- ++
- ++ cancel_work_sync(&ar->offchan_tx_work);
- ++ cancel_work_sync(&ar->wmi_mgmt_tx_work);
- ++}
- ++
- + void ath10k_halt(struct ath10k *ar)
- + {
- + struct ath10k_vif *arvif;
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- +- if (ath10k_monitor_is_enabled(ar)) {
- +- clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
- +- ar->promisc = false;
- +- ar->monitor = false;
- ++ clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
- ++ ar->filter_flags = 0;
- ++ ar->monitor = false;
- ++
- ++ if (ar->monitor_started)
- + ath10k_monitor_stop(ar);
- +- }
- +
- +- del_timer_sync(&ar->scan.timeout);
- +- ath10k_offchan_tx_purge(ar);
- +- ath10k_mgmt_over_wmi_tx_purge(ar);
- ++ ar->monitor_started = false;
- ++
- ++ ath10k_scan_finish(ar);
- + ath10k_peer_cleanup_all(ar);
- + ath10k_core_stop(ar);
- + ath10k_hif_power_down(ar);
- +
- + spin_lock_bh(&ar->data_lock);
- +- if (ar->scan.in_progress) {
- +- del_timer(&ar->scan.timeout);
- +- ar->scan.in_progress = false;
- +- ieee80211_scan_completed(ar->hw, true);
- ++ list_for_each_entry(arvif, &ar->arvifs, list)
- ++ ath10k_mac_vif_beacon_cleanup(arvif);
- ++ spin_unlock_bh(&ar->data_lock);
- ++}
- ++
- ++static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
- ++{
- ++ struct ath10k *ar = hw->priv;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ if (ar->cfg_tx_chainmask) {
- ++ *tx_ant = ar->cfg_tx_chainmask;
- ++ *rx_ant = ar->cfg_rx_chainmask;
- ++ } else {
- ++ *tx_ant = ar->supp_tx_chainmask;
- ++ *rx_ant = ar->supp_rx_chainmask;
- + }
- +
- +- list_for_each_entry(arvif, &ar->arvifs, list) {
- +- if (!arvif->beacon)
- +- continue;
- ++ mutex_unlock(&ar->conf_mutex);
- +
- +- dma_unmap_single(arvif->ar->dev,
- +- ATH10K_SKB_CB(arvif->beacon)->paddr,
- +- arvif->beacon->len, DMA_TO_DEVICE);
- +- dev_kfree_skb_any(arvif->beacon);
- +- arvif->beacon = NULL;
- ++ return 0;
- ++}
- ++
- ++static void ath10k_check_chain_mask(struct ath10k *ar, u32 cm, const char *dbg)
- ++{
- ++ /* It is not clear that allowing gaps in chainmask
- ++ * is helpful. Probably it will not do what user
- ++ * is hoping for, so warn in that case.
- ++ */
- ++ if (cm == 15 || cm == 7 || cm == 3 || cm == 1 || cm == 0)
- ++ return;
- ++
- ++ ath10k_warn(ar, "mac %s antenna chainmask may be invalid: 0x%x. Suggested values: 15, 7, 3, 1 or 0.\n",
- ++ dbg, cm);
- ++}
- ++
- ++static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
- ++{
- ++ int ret;
- ++
- ++ lockdep_assert_held(&ar->conf_mutex);
- ++
- ++ ath10k_check_chain_mask(ar, tx_ant, "tx");
- ++ ath10k_check_chain_mask(ar, rx_ant, "rx");
- ++
- ++ ar->cfg_tx_chainmask = tx_ant;
- ++ ar->cfg_rx_chainmask = rx_ant;
- ++
- ++ if ((ar->state != ATH10K_STATE_ON) &&
- ++ (ar->state != ATH10K_STATE_RESTARTED))
- ++ return 0;
- ++
- ++ ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->tx_chain_mask,
- ++ tx_ant);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to set tx-chainmask: %d, req 0x%x\n",
- ++ ret, tx_ant);
- ++ return ret;
- + }
- +- spin_unlock_bh(&ar->data_lock);
- ++
- ++ ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rx_chain_mask,
- ++ rx_ant);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to set rx-chainmask: %d, req 0x%x\n",
- ++ ret, rx_ant);
- ++ return ret;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
- ++{
- ++ struct ath10k *ar = hw->priv;
- ++ int ret;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ ret = __ath10k_set_antenna(ar, tx_ant, rx_ant);
- ++ mutex_unlock(&ar->conf_mutex);
- ++ return ret;
- + }
- +
- + static int ath10k_start(struct ieee80211_hw *hw)
- +@@ -2334,41 +2857,61 @@ static int ath10k_start(struct ieee80211
- + struct ath10k *ar = hw->priv;
- + int ret = 0;
- +
- ++ /*
- ++ * This makes sense only when restarting hw. It is harmless to call
- ++ * uncoditionally. This is necessary to make sure no HTT/WMI tx
- ++ * commands will be submitted while restarting.
- ++ */
- ++ ath10k_drain_tx(ar);
- ++
- + mutex_lock(&ar->conf_mutex);
- +
- +- if (ar->state != ATH10K_STATE_OFF &&
- +- ar->state != ATH10K_STATE_RESTARTING) {
- ++ switch (ar->state) {
- ++ case ATH10K_STATE_OFF:
- ++ ar->state = ATH10K_STATE_ON;
- ++ break;
- ++ case ATH10K_STATE_RESTARTING:
- ++ ath10k_halt(ar);
- ++ ar->state = ATH10K_STATE_RESTARTED;
- ++ break;
- ++ case ATH10K_STATE_ON:
- ++ case ATH10K_STATE_RESTARTED:
- ++ case ATH10K_STATE_WEDGED:
- ++ WARN_ON(1);
- + ret = -EINVAL;
- +- goto exit;
- ++ goto err;
- ++ case ATH10K_STATE_UTF:
- ++ ret = -EBUSY;
- ++ goto err;
- + }
- +
- + ret = ath10k_hif_power_up(ar);
- + if (ret) {
- +- ath10k_err("Could not init hif: %d\n", ret);
- +- ar->state = ATH10K_STATE_OFF;
- +- goto exit;
- ++ ath10k_err(ar, "Could not init hif: %d\n", ret);
- ++ goto err_off;
- + }
- +
- +- ret = ath10k_core_start(ar);
- ++ ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
- + if (ret) {
- +- ath10k_err("Could not init core: %d\n", ret);
- +- ath10k_hif_power_down(ar);
- +- ar->state = ATH10K_STATE_OFF;
- +- goto exit;
- ++ ath10k_err(ar, "Could not init core: %d\n", ret);
- ++ goto err_power_down;
- + }
- +
- +- if (ar->state == ATH10K_STATE_OFF)
- +- ar->state = ATH10K_STATE_ON;
- +- else if (ar->state == ATH10K_STATE_RESTARTING)
- +- ar->state = ATH10K_STATE_RESTARTED;
- +-
- + ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1);
- +- if (ret)
- +- ath10k_warn("failed to enable PMF QOS: %d\n", ret);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to enable PMF QOS: %d\n", ret);
- ++ goto err_core_stop;
- ++ }
- +
- + ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1);
- +- if (ret)
- +- ath10k_warn("failed to enable dynamic BW: %d\n", ret);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to enable dynamic BW: %d\n", ret);
- ++ goto err_core_stop;
- ++ }
- ++
- ++ if (ar->cfg_tx_chainmask)
- ++ __ath10k_set_antenna(ar, ar->cfg_tx_chainmask,
- ++ ar->cfg_rx_chainmask);
- +
- + /*
- + * By default FW set ARP frames ac to voice (6). In that case ARP
- +@@ -2382,16 +2925,29 @@ static int ath10k_start(struct ieee80211
- + ret = ath10k_wmi_pdev_set_param(ar,
- + ar->wmi.pdev_param->arp_ac_override, 0);
- + if (ret) {
- +- ath10k_warn("failed to set arp ac override parameter: %d\n",
- ++ ath10k_warn(ar, "failed to set arp ac override parameter: %d\n",
- + ret);
- +- goto exit;
- ++ goto err_core_stop;
- + }
- +
- + ar->num_started_vdevs = 0;
- + ath10k_regd_update(ar);
- +- ret = 0;
- +
- +-exit:
- ++ ath10k_spectral_start(ar);
- ++
- ++ mutex_unlock(&ar->conf_mutex);
- ++ return 0;
- ++
- ++err_core_stop:
- ++ ath10k_core_stop(ar);
- ++
- ++err_power_down:
- ++ ath10k_hif_power_down(ar);
- ++
- ++err_off:
- ++ ar->state = ATH10K_STATE_OFF;
- ++
- ++err:
- + mutex_unlock(&ar->conf_mutex);
- + return ret;
- + }
- +@@ -2400,19 +2956,16 @@ static void ath10k_stop(struct ieee80211
- + {
- + struct ath10k *ar = hw->priv;
- +
- ++ ath10k_drain_tx(ar);
- ++
- + mutex_lock(&ar->conf_mutex);
- +- if (ar->state == ATH10K_STATE_ON ||
- +- ar->state == ATH10K_STATE_RESTARTED ||
- +- ar->state == ATH10K_STATE_WEDGED)
- ++ if (ar->state != ATH10K_STATE_OFF) {
- + ath10k_halt(ar);
- +-
- +- ar->state = ATH10K_STATE_OFF;
- ++ ar->state = ATH10K_STATE_OFF;
- ++ }
- + mutex_unlock(&ar->conf_mutex);
- +
- +- ath10k_mgmt_over_wmi_tx_purge(ar);
- +-
- +- cancel_work_sync(&ar->offchan_tx_work);
- +- cancel_work_sync(&ar->wmi_mgmt_tx_work);
- ++ cancel_delayed_work_sync(&ar->scan.timeout);
- + cancel_work_sync(&ar->restart_work);
- + }
- +
- +@@ -2426,7 +2979,7 @@ static int ath10k_config_ps(struct ath10
- + list_for_each_entry(arvif, &ar->arvifs, list) {
- + ret = ath10k_mac_vif_setup_ps(arvif);
- + if (ret) {
- +- ath10k_warn("failed to setup powersave: %d\n", ret);
- ++ ath10k_warn(ar, "failed to setup powersave: %d\n", ret);
- + break;
- + }
- + }
- +@@ -2464,7 +3017,7 @@ static void ath10k_config_chan(struct at
- +
- + lockdep_assert_held(&ar->conf_mutex);
- +
- +- ath10k_dbg(ATH10K_DBG_MAC,
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC,
- + "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n",
- + ar->chandef.chan->center_freq,
- + ar->chandef.center_freq1,
- +@@ -2474,24 +3027,27 @@ static void ath10k_config_chan(struct at
- + /* First stop monitor interface. Some FW versions crash if there's a
- + * lone monitor interface. */
- + if (ar->monitor_started)
- +- ath10k_monitor_vdev_stop(ar);
- ++ ath10k_monitor_stop(ar);
- +
- + list_for_each_entry(arvif, &ar->arvifs, list) {
- + if (!arvif->is_started)
- + continue;
- +
- ++ if (!arvif->is_up)
- ++ continue;
- ++
- + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
- + continue;
- +
- +- ret = ath10k_vdev_stop(arvif);
- ++ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
- + if (ret) {
- +- ath10k_warn("failed to stop vdev %d: %d\n",
- ++ ath10k_warn(ar, "failed to down vdev %d: %d\n",
- + arvif->vdev_id, ret);
- + continue;
- + }
- + }
- +
- +- /* all vdevs are now stopped - now attempt to restart them */
- ++ /* all vdevs are downed now - attempt to restart and re-up them */
- +
- + list_for_each_entry(arvif, &ar->arvifs, list) {
- + if (!arvif->is_started)
- +@@ -2500,9 +3056,9 @@ static void ath10k_config_chan(struct at
- + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
- + continue;
- +
- +- ret = ath10k_vdev_start(arvif);
- ++ ret = ath10k_vdev_restart(arvif);
- + if (ret) {
- +- ath10k_warn("failed to start vdev %d: %d\n",
- ++ ath10k_warn(ar, "failed to restart vdev %d: %d\n",
- + arvif->vdev_id, ret);
- + continue;
- + }
- +@@ -2513,14 +3069,70 @@ static void ath10k_config_chan(struct at
- + ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
- + arvif->bssid);
- + if (ret) {
- +- ath10k_warn("failed to bring vdev up %d: %d\n",
- ++ ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
- + arvif->vdev_id, ret);
- + continue;
- + }
- + }
- +
- +- if (ath10k_monitor_is_enabled(ar))
- +- ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id);
- ++ ath10k_monitor_recalc(ar);
- ++}
- ++
- ++static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower)
- ++{
- ++ int ret;
- ++ u32 param;
- ++
- ++ lockdep_assert_held(&ar->conf_mutex);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac txpower %d\n", txpower);
- ++
- ++ param = ar->wmi.pdev_param->txpower_limit2g;
- ++ ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to set 2g txpower %d: %d\n",
- ++ txpower, ret);
- ++ return ret;
- ++ }
- ++
- ++ param = ar->wmi.pdev_param->txpower_limit5g;
- ++ ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to set 5g txpower %d: %d\n",
- ++ txpower, ret);
- ++ return ret;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_mac_txpower_recalc(struct ath10k *ar)
- ++{
- ++ struct ath10k_vif *arvif;
- ++ int ret, txpower = -1;
- ++
- ++ lockdep_assert_held(&ar->conf_mutex);
- ++
- ++ list_for_each_entry(arvif, &ar->arvifs, list) {
- ++ WARN_ON(arvif->txpower < 0);
- ++
- ++ if (txpower == -1)
- ++ txpower = arvif->txpower;
- ++ else
- ++ txpower = min(txpower, arvif->txpower);
- ++ }
- ++
- ++ if (WARN_ON(txpower == -1))
- ++ return -EINVAL;
- ++
- ++ ret = ath10k_mac_txpower_setup(ar, txpower);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to setup tx power %d: %d\n",
- ++ txpower, ret);
- ++ return ret;
- ++ }
- ++
- ++ return 0;
- + }
- +
- + static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
- +@@ -2528,12 +3140,11 @@ static int ath10k_config(struct ieee8021
- + struct ath10k *ar = hw->priv;
- + struct ieee80211_conf *conf = &hw->conf;
- + int ret = 0;
- +- u32 param;
- +
- + mutex_lock(&ar->conf_mutex);
- +
- + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- +- ath10k_dbg(ATH10K_DBG_MAC,
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC,
- + "mac config channel %dMHz flags 0x%x radar %d\n",
- + conf->chandef.chan->center_freq,
- + conf->chandef.chan->flags,
- +@@ -2552,48 +3163,31 @@ static int ath10k_config(struct ieee8021
- + }
- + }
- +
- +- if (changed & IEEE80211_CONF_CHANGE_POWER) {
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac config power %d\n",
- +- hw->conf.power_level);
- +-
- +- param = ar->wmi.pdev_param->txpower_limit2g;
- +- ret = ath10k_wmi_pdev_set_param(ar, param,
- +- hw->conf.power_level * 2);
- +- if (ret)
- +- ath10k_warn("failed to set 2g txpower %d: %d\n",
- +- hw->conf.power_level, ret);
- +-
- +- param = ar->wmi.pdev_param->txpower_limit5g;
- +- ret = ath10k_wmi_pdev_set_param(ar, param,
- +- hw->conf.power_level * 2);
- +- if (ret)
- +- ath10k_warn("failed to set 5g txpower %d: %d\n",
- +- hw->conf.power_level, ret);
- +- }
- +-
- + if (changed & IEEE80211_CONF_CHANGE_PS)
- + ath10k_config_ps(ar);
- +
- + if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
- +- if (conf->flags & IEEE80211_CONF_MONITOR && !ar->monitor) {
- +- ar->monitor = true;
- +- ret = ath10k_monitor_start(ar);
- +- if (ret) {
- +- ath10k_warn("failed to start monitor (config): %d\n",
- +- ret);
- +- ar->monitor = false;
- +- }
- +- } else if (!(conf->flags & IEEE80211_CONF_MONITOR) &&
- +- ar->monitor) {
- +- ar->monitor = false;
- +- ath10k_monitor_stop(ar);
- +- }
- ++ ar->monitor = conf->flags & IEEE80211_CONF_MONITOR;
- ++ ret = ath10k_monitor_recalc(ar);
- ++ if (ret)
- ++ ath10k_warn(ar, "failed to recalc monitor: %d\n", ret);
- + }
- +
- + mutex_unlock(&ar->conf_mutex);
- + return ret;
- + }
- +
- ++static u32 get_nss_from_chainmask(u16 chain_mask)
- ++{
- ++ if ((chain_mask & 0x15) == 0x15)
- ++ return 4;
- ++ else if ((chain_mask & 0x7) == 0x7)
- ++ return 3;
- ++ else if ((chain_mask & 0x3) == 0x3)
- ++ return 2;
- ++ return 1;
- ++}
- ++
- + /*
- + * TODO:
- + * Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE,
- +@@ -2619,22 +3213,26 @@ static int ath10k_add_interface(struct i
- + arvif->ar = ar;
- + arvif->vif = vif;
- +
- +- INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work);
- + INIT_LIST_HEAD(&arvif->list);
- +
- +- bit = ffs(ar->free_vdev_map);
- +- if (bit == 0) {
- ++ if (ar->free_vdev_map == 0) {
- ++ ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n");
- + ret = -EBUSY;
- + goto err;
- + }
- ++ bit = __ffs64(ar->free_vdev_map);
- +
- +- arvif->vdev_id = bit - 1;
- +- arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac create vdev %i map %llx\n",
- ++ bit, ar->free_vdev_map);
- +
- +- if (ar->p2p)
- +- arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
- ++ arvif->vdev_id = bit;
- ++ arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
- +
- + switch (vif->type) {
- ++ case NL80211_IFTYPE_P2P_DEVICE:
- ++ arvif->vdev_type = WMI_VDEV_TYPE_STA;
- ++ arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
- ++ break;
- + case NL80211_IFTYPE_UNSPECIFIED:
- + case NL80211_IFTYPE_STATION:
- + arvif->vdev_type = WMI_VDEV_TYPE_STA;
- +@@ -2658,50 +3256,98 @@ static int ath10k_add_interface(struct i
- + break;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
- +- arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype);
- ++ /* Some firmware revisions don't wait for beacon tx completion before
- ++ * sending another SWBA event. This could lead to hardware using old
- ++ * (freed) beacon data in some cases, e.g. tx credit starvation
- ++ * combined with missed TBTT. This is very very rare.
- ++ *
- ++ * On non-IOMMU-enabled hosts this could be a possible security issue
- ++ * because hw could beacon some random data on the air. On
- ++ * IOMMU-enabled hosts DMAR faults would occur in most cases and target
- ++ * device would crash.
- ++ *
- ++ * Since there are no beacon tx completions (implicit nor explicit)
- ++ * propagated to host the only workaround for this is to allocate a
- ++ * DMA-coherent buffer for a lifetime of a vif and use it for all
- ++ * beacon tx commands. Worst case for this approach is some beacons may
- ++ * become corrupted, e.g. have garbled IEs or out-of-date TIM bitmap.
- ++ */
- ++ if (vif->type == NL80211_IFTYPE_ADHOC ||
- ++ vif->type == NL80211_IFTYPE_AP) {
- ++ arvif->beacon_buf = dma_zalloc_coherent(ar->dev,
- ++ IEEE80211_MAX_FRAME_LEN,
- ++ &arvif->beacon_paddr,
- ++ GFP_ATOMIC);
- ++ if (!arvif->beacon_buf) {
- ++ ret = -ENOMEM;
- ++ ath10k_warn(ar, "failed to allocate beacon buffer: %d\n",
- ++ ret);
- ++ goto err;
- ++ }
- ++ }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d bcnmode %s\n",
- ++ arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype,
- ++ arvif->beacon_buf ? "single-buf" : "per-skb");
- +
- + ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,
- + arvif->vdev_subtype, vif->addr);
- + if (ret) {
- +- ath10k_warn("failed to create WMI vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to create WMI vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + goto err;
- + }
- +
- +- ar->free_vdev_map &= ~BIT(arvif->vdev_id);
- ++ ar->free_vdev_map &= ~(1LL << arvif->vdev_id);
- + list_add(&arvif->list, &ar->arvifs);
- +
- +- vdev_param = ar->wmi.vdev_param->def_keyid;
- +- ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param,
- +- arvif->def_wep_key_idx);
- ++ /* It makes no sense to have firmware do keepalives. mac80211 already
- ++ * takes care of this with idle connection polling.
- ++ */
- ++ ret = ath10k_mac_vif_disable_keepalive(arvif);
- + if (ret) {
- +- ath10k_warn("failed to set vdev %i default key id: %d\n",
- ++ ath10k_warn(ar, "failed to disable keepalive on vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + goto err_vdev_delete;
- + }
- +
- ++ arvif->def_wep_key_idx = -1;
- ++
- + vdev_param = ar->wmi.vdev_param->tx_encap_type;
- + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
- + ATH10K_HW_TXRX_NATIVE_WIFI);
- + /* 10.X firmware does not support this VDEV parameter. Do not warn */
- + if (ret && ret != -EOPNOTSUPP) {
- +- ath10k_warn("failed to set vdev %i TX encapsulation: %d\n",
- ++ ath10k_warn(ar, "failed to set vdev %i TX encapsulation: %d\n",
- + arvif->vdev_id, ret);
- + goto err_vdev_delete;
- + }
- +
- ++ if (ar->cfg_tx_chainmask) {
- ++ u16 nss = get_nss_from_chainmask(ar->cfg_tx_chainmask);
- ++
- ++ vdev_param = ar->wmi.vdev_param->nss;
- ++ ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
- ++ nss);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to set vdev %i chainmask 0x%x, nss %i: %d\n",
- ++ arvif->vdev_id, ar->cfg_tx_chainmask, nss,
- ++ ret);
- ++ goto err_vdev_delete;
- ++ }
- ++ }
- ++
- + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
- + ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
- + if (ret) {
- +- ath10k_warn("failed to create vdev %i peer for AP: %d\n",
- ++ ath10k_warn(ar, "failed to create vdev %i peer for AP: %d\n",
- + arvif->vdev_id, ret);
- + goto err_vdev_delete;
- + }
- +
- + ret = ath10k_mac_set_kickout(arvif);
- + if (ret) {
- +- ath10k_warn("failed to set vdev %i kickout parameters: %d\n",
- ++ ath10k_warn(ar, "failed to set vdev %i kickout parameters: %d\n",
- + arvif->vdev_id, ret);
- + goto err_peer_delete;
- + }
- +@@ -2713,27 +3359,21 @@ static int ath10k_add_interface(struct i
- + ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
- + param, value);
- + if (ret) {
- +- ath10k_warn("failed to set vdev %i RX wake policy: %d\n",
- ++ ath10k_warn(ar, "failed to set vdev %i RX wake policy: %d\n",
- + arvif->vdev_id, ret);
- + goto err_peer_delete;
- + }
- +
- +- param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD;
- +- value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
- +- ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
- +- param, value);
- ++ ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif);
- + if (ret) {
- +- ath10k_warn("failed to set vdev %i TX wake thresh: %d\n",
- ++ ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + goto err_peer_delete;
- + }
- +
- +- param = WMI_STA_PS_PARAM_PSPOLL_COUNT;
- +- value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
- +- ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
- +- param, value);
- ++ ret = ath10k_mac_vif_recalc_ps_poll_count(arvif);
- + if (ret) {
- +- ath10k_warn("failed to set vdev %i PSPOLL count: %d\n",
- ++ ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + goto err_peer_delete;
- + }
- +@@ -2741,15 +3381,22 @@ static int ath10k_add_interface(struct i
- +
- + ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold);
- + if (ret) {
- +- ath10k_warn("failed to set rts threshold for vdev %d: %d\n",
- ++ ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n",
- ++ arvif->vdev_id, ret);
- ++ goto err_peer_delete;
- ++ }
- ++
- ++ ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to set frag threshold for vdev %d: %d\n",
- + arvif->vdev_id, ret);
- + goto err_peer_delete;
- + }
- +
- +- ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold);
- ++ arvif->txpower = vif->bss_conf.txpower;
- ++ ret = ath10k_mac_txpower_recalc(ar);
- + if (ret) {
- +- ath10k_warn("failed to set frag threshold for vdev %d: %d\n",
- +- arvif->vdev_id, ret);
- ++ ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
- + goto err_peer_delete;
- + }
- +
- +@@ -2762,10 +3409,16 @@ err_peer_delete:
- +
- + err_vdev_delete:
- + ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
- +- ar->free_vdev_map &= ~BIT(arvif->vdev_id);
- ++ ar->free_vdev_map |= 1LL << arvif->vdev_id;
- + list_del(&arvif->list);
- +
- + err:
- ++ if (arvif->beacon_buf) {
- ++ dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
- ++ arvif->beacon_buf, arvif->beacon_paddr);
- ++ arvif->beacon_buf = NULL;
- ++ }
- ++
- + mutex_unlock(&ar->conf_mutex);
- +
- + return ret;
- +@@ -2780,38 +3433,51 @@ static void ath10k_remove_interface(stru
- +
- + mutex_lock(&ar->conf_mutex);
- +
- +- cancel_work_sync(&arvif->wep_key_work);
- +-
- + spin_lock_bh(&ar->data_lock);
- +- if (arvif->beacon) {
- +- dma_unmap_single(arvif->ar->dev,
- +- ATH10K_SKB_CB(arvif->beacon)->paddr,
- +- arvif->beacon->len, DMA_TO_DEVICE);
- +- dev_kfree_skb_any(arvif->beacon);
- +- arvif->beacon = NULL;
- +- }
- ++ ath10k_mac_vif_beacon_cleanup(arvif);
- + spin_unlock_bh(&ar->data_lock);
- +
- +- ar->free_vdev_map |= 1 << (arvif->vdev_id);
- ++ ret = ath10k_spectral_vif_stop(arvif);
- ++ if (ret)
- ++ ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n",
- ++ arvif->vdev_id, ret);
- ++
- ++ ar->free_vdev_map |= 1LL << arvif->vdev_id;
- + list_del(&arvif->list);
- +
- + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
- +- ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr);
- ++ ret = ath10k_wmi_peer_delete(arvif->ar, arvif->vdev_id,
- ++ vif->addr);
- + if (ret)
- +- ath10k_warn("failed to remove peer for AP vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to submit AP self-peer removal on vdev %i: %d\n",
- + arvif->vdev_id, ret);
- +
- + kfree(arvif->u.ap.noa_data);
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n",
- + arvif->vdev_id);
- +
- + ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
- + if (ret)
- +- ath10k_warn("failed to delete WMI vdev %i: %d\n",
- ++ ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n",
- + arvif->vdev_id, ret);
- +
- ++ /* Some firmware revisions don't notify host about self-peer removal
- ++ * until after associated vdev is deleted.
- ++ */
- ++ if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
- ++ ret = ath10k_wait_for_peer_deleted(ar, arvif->vdev_id,
- ++ vif->addr);
- ++ if (ret)
- ++ ath10k_warn(ar, "failed to remove AP self-peer on vdev %i: %d\n",
- ++ arvif->vdev_id, ret);
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++ ar->num_peers--;
- ++ spin_unlock_bh(&ar->data_lock);
- ++ }
- ++
- + ath10k_peer_cleanup(ar, arvif->vdev_id);
- +
- + mutex_unlock(&ar->conf_mutex);
- +@@ -2844,18 +3510,9 @@ static void ath10k_configure_filter(stru
- + *total_flags &= SUPPORTED_FILTERS;
- + ar->filter_flags = *total_flags;
- +
- +- if (ar->filter_flags & FIF_PROMISC_IN_BSS && !ar->promisc) {
- +- ar->promisc = true;
- +- ret = ath10k_monitor_start(ar);
- +- if (ret) {
- +- ath10k_warn("failed to start monitor (promisc): %d\n",
- +- ret);
- +- ar->promisc = false;
- +- }
- +- } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && ar->promisc) {
- +- ar->promisc = false;
- +- ath10k_monitor_stop(ar);
- +- }
- ++ ret = ath10k_monitor_recalc(ar);
- ++ if (ret)
- ++ ath10k_warn(ar, "failed to recalc montior: %d\n", ret);
- +
- + mutex_unlock(&ar->conf_mutex);
- + }
- +@@ -2868,7 +3525,7 @@ static void ath10k_bss_info_changed(stru
- + struct ath10k *ar = hw->priv;
- + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- + int ret = 0;
- +- u32 vdev_param, pdev_param;
- ++ u32 vdev_param, pdev_param, slottime, preamble;
- +
- + mutex_lock(&ar->conf_mutex);
- +
- +@@ -2880,17 +3537,17 @@ static void ath10k_bss_info_changed(stru
- + vdev_param = ar->wmi.vdev_param->beacon_interval;
- + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
- + arvif->beacon_interval);
- +- ath10k_dbg(ATH10K_DBG_MAC,
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC,
- + "mac vdev %d beacon_interval %d\n",
- + arvif->vdev_id, arvif->beacon_interval);
- +
- + if (ret)
- +- ath10k_warn("failed to set beacon interval for vdev %d: %i\n",
- ++ ath10k_warn(ar, "failed to set beacon interval for vdev %d: %i\n",
- + arvif->vdev_id, ret);
- + }
- +
- + if (changed & BSS_CHANGED_BEACON) {
- +- ath10k_dbg(ATH10K_DBG_MAC,
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC,
- + "vdev %d set beacon tx mode to staggered\n",
- + arvif->vdev_id);
- +
- +@@ -2898,14 +3555,26 @@ static void ath10k_bss_info_changed(stru
- + ret = ath10k_wmi_pdev_set_param(ar, pdev_param,
- + WMI_BEACON_STAGGERED_MODE);
- + if (ret)
- +- ath10k_warn("failed to set beacon mode for vdev %d: %i\n",
- ++ ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n",
- ++ arvif->vdev_id, ret);
- ++
- ++ ret = ath10k_mac_setup_bcn_tmpl(arvif);
- ++ if (ret)
- ++ ath10k_warn(ar, "failed to update beacon template: %d\n",
- ++ ret);
- ++ }
- ++
- ++ if (changed & BSS_CHANGED_AP_PROBE_RESP) {
- ++ ret = ath10k_mac_setup_prb_tmpl(arvif);
- ++ if (ret)
- ++ ath10k_warn(ar, "failed to setup probe resp template on vdev %i: %d\n",
- + arvif->vdev_id, ret);
- + }
- +
- +- if (changed & BSS_CHANGED_BEACON_INFO) {
- ++ if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) {
- + arvif->dtim_period = info->dtim_period;
- +
- +- ath10k_dbg(ATH10K_DBG_MAC,
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC,
- + "mac vdev %d dtim_period %d\n",
- + arvif->vdev_id, arvif->dtim_period);
- +
- +@@ -2913,7 +3582,7 @@ static void ath10k_bss_info_changed(stru
- + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
- + arvif->dtim_period);
- + if (ret)
- +- ath10k_warn("failed to set dtim period for vdev %d: %i\n",
- ++ ath10k_warn(ar, "failed to set dtim period for vdev %d: %i\n",
- + arvif->vdev_id, ret);
- + }
- +
- +@@ -2925,91 +3594,48 @@ static void ath10k_bss_info_changed(stru
- + arvif->u.ap.hidden_ssid = info->hidden_ssid;
- + }
- +
- +- if (changed & BSS_CHANGED_BSSID) {
- +- if (!is_zero_ether_addr(info->bssid)) {
- +- ath10k_dbg(ATH10K_DBG_MAC,
- +- "mac vdev %d create peer %pM\n",
- +- arvif->vdev_id, info->bssid);
- +-
- +- ret = ath10k_peer_create(ar, arvif->vdev_id,
- +- info->bssid);
- +- if (ret)
- +- ath10k_warn("failed to add peer %pM for vdev %d when changing bssid: %i\n",
- +- info->bssid, arvif->vdev_id, ret);
- +-
- +- if (vif->type == NL80211_IFTYPE_STATION) {
- +- /*
- +- * this is never erased as we it for crypto key
- +- * clearing; this is FW requirement
- +- */
- +- memcpy(arvif->bssid, info->bssid, ETH_ALEN);
- +-
- +- ath10k_dbg(ATH10K_DBG_MAC,
- +- "mac vdev %d start %pM\n",
- +- arvif->vdev_id, info->bssid);
- +-
- +- ret = ath10k_vdev_start(arvif);
- +- if (ret) {
- +- ath10k_warn("failed to start vdev %i: %d\n",
- +- arvif->vdev_id, ret);
- +- goto exit;
- +- }
- +-
- +- arvif->is_started = true;
- +- }
- +-
- +- /*
- +- * Mac80211 does not keep IBSS bssid when leaving IBSS,
- +- * so driver need to store it. It is needed when leaving
- +- * IBSS in order to remove BSSID peer.
- +- */
- +- if (vif->type == NL80211_IFTYPE_ADHOC)
- +- memcpy(arvif->bssid, info->bssid,
- +- ETH_ALEN);
- +- }
- +- }
- ++ if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid))
- ++ ether_addr_copy(arvif->bssid, info->bssid);
- +
- + if (changed & BSS_CHANGED_BEACON_ENABLED)
- + ath10k_control_beaconing(arvif, info);
- +
- + if (changed & BSS_CHANGED_ERP_CTS_PROT) {
- + arvif->use_cts_prot = info->use_cts_prot;
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
- + arvif->vdev_id, info->use_cts_prot);
- +
- + ret = ath10k_recalc_rtscts_prot(arvif);
- + if (ret)
- +- ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
- ++ ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
- + arvif->vdev_id, ret);
- + }
- +
- + if (changed & BSS_CHANGED_ERP_SLOT) {
- +- u32 slottime;
- + if (info->use_short_slot)
- + slottime = WMI_VDEV_SLOT_TIME_SHORT; /* 9us */
- +
- + else
- + slottime = WMI_VDEV_SLOT_TIME_LONG; /* 20us */
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n",
- + arvif->vdev_id, slottime);
- +
- + vdev_param = ar->wmi.vdev_param->slot_time;
- + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
- + slottime);
- + if (ret)
- +- ath10k_warn("failed to set erp slot for vdev %d: %i\n",
- ++ ath10k_warn(ar, "failed to set erp slot for vdev %d: %i\n",
- + arvif->vdev_id, ret);
- + }
- +
- + if (changed & BSS_CHANGED_ERP_PREAMBLE) {
- +- u32 preamble;
- + if (info->use_short_preamble)
- + preamble = WMI_VDEV_PREAMBLE_SHORT;
- + else
- + preamble = WMI_VDEV_PREAMBLE_LONG;
- +
- +- ath10k_dbg(ATH10K_DBG_MAC,
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC,
- + "mac vdev %d preamble %dn",
- + arvif->vdev_id, preamble);
- +
- +@@ -3017,16 +3643,44 @@ static void ath10k_bss_info_changed(stru
- + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
- + preamble);
- + if (ret)
- +- ath10k_warn("failed to set preamble for vdev %d: %i\n",
- ++ ath10k_warn(ar, "failed to set preamble for vdev %d: %i\n",
- + arvif->vdev_id, ret);
- + }
- +
- + if (changed & BSS_CHANGED_ASSOC) {
- +- if (info->assoc)
- ++ if (info->assoc) {
- ++ /* Workaround: Make sure monitor vdev is not running
- ++ * when associating to prevent some firmware revisions
- ++ * (e.g. 10.1 and 10.2) from crashing.
- ++ */
- ++ if (ar->monitor_started)
- ++ ath10k_monitor_stop(ar);
- + ath10k_bss_assoc(hw, vif, info);
- ++ ath10k_monitor_recalc(ar);
- ++ } else {
- ++ ath10k_bss_disassoc(hw, vif);
- ++ }
- ++ }
- ++
- ++ if (changed & BSS_CHANGED_TXPOWER) {
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev_id %i txpower %d\n",
- ++ arvif->vdev_id, info->txpower);
- ++
- ++ arvif->txpower = info->txpower;
- ++ ret = ath10k_mac_txpower_recalc(ar);
- ++ if (ret)
- ++ ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
- ++ }
- ++
- ++ if (changed & BSS_CHANGED_PS) {
- ++ arvif->ps = vif->bss_conf.ps;
- ++
- ++ ret = ath10k_config_ps(ar);
- ++ if (ret)
- ++ ath10k_warn(ar, "failed to setup ps on vdev %i: %d\n",
- ++ arvif->vdev_id, ret);
- + }
- +
- +-exit:
- + mutex_unlock(&ar->conf_mutex);
- + }
- +
- +@@ -3043,20 +3697,26 @@ static int ath10k_hw_scan(struct ieee802
- + mutex_lock(&ar->conf_mutex);
- +
- + spin_lock_bh(&ar->data_lock);
- +- if (ar->scan.in_progress) {
- +- spin_unlock_bh(&ar->data_lock);
- ++ switch (ar->scan.state) {
- ++ case ATH10K_SCAN_IDLE:
- ++ reinit_completion(&ar->scan.started);
- ++ reinit_completion(&ar->scan.completed);
- ++ ar->scan.state = ATH10K_SCAN_STARTING;
- ++ ar->scan.is_roc = false;
- ++ ar->scan.vdev_id = arvif->vdev_id;
- ++ ret = 0;
- ++ break;
- ++ case ATH10K_SCAN_STARTING:
- ++ case ATH10K_SCAN_RUNNING:
- ++ case ATH10K_SCAN_ABORTING:
- + ret = -EBUSY;
- +- goto exit;
- ++ break;
- + }
- +-
- +- reinit_completion(&ar->scan.started);
- +- reinit_completion(&ar->scan.completed);
- +- ar->scan.in_progress = true;
- +- ar->scan.aborting = false;
- +- ar->scan.is_roc = false;
- +- ar->scan.vdev_id = arvif->vdev_id;
- + spin_unlock_bh(&ar->data_lock);
- +
- ++ if (ret)
- ++ goto exit;
- ++
- + memset(&arg, 0, sizeof(arg));
- + ath10k_wmi_start_scan_init(ar, &arg);
- + arg.vdev_id = arvif->vdev_id;
- +@@ -3088,9 +3748,9 @@ static int ath10k_hw_scan(struct ieee802
- +
- + ret = ath10k_start_scan(ar, &arg);
- + if (ret) {
- +- ath10k_warn("failed to start hw scan: %d\n", ret);
- ++ ath10k_warn(ar, "failed to start hw scan: %d\n", ret);
- + spin_lock_bh(&ar->data_lock);
- +- ar->scan.in_progress = false;
- ++ ar->scan.state = ATH10K_SCAN_IDLE;
- + spin_unlock_bh(&ar->data_lock);
- + }
- +
- +@@ -3103,15 +3763,12 @@ static void ath10k_cancel_hw_scan(struct
- + struct ieee80211_vif *vif)
- + {
- + struct ath10k *ar = hw->priv;
- +- int ret;
- +
- + mutex_lock(&ar->conf_mutex);
- +- ret = ath10k_abort_scan(ar);
- +- if (ret) {
- +- ath10k_warn("failed to abort scan: %d\n", ret);
- +- ieee80211_scan_completed(hw, 1 /* aborted */);
- +- }
- ++ ath10k_scan_abort(ar);
- + mutex_unlock(&ar->conf_mutex);
- ++
- ++ cancel_delayed_work_sync(&ar->scan.timeout);
- + }
- +
- + static void ath10k_set_key_h_def_keyidx(struct ath10k *ar,
- +@@ -3148,7 +3805,7 @@ static void ath10k_set_key_h_def_keyidx(
- + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
- + key->keyidx);
- + if (ret)
- +- ath10k_warn("failed to set vdev %i group key as default key: %d\n",
- ++ ath10k_warn(ar, "failed to set vdev %i group key as default key: %d\n",
- + arvif->vdev_id, ret);
- + }
- +
- +@@ -3162,6 +3819,7 @@ static int ath10k_set_key(struct ieee802
- + const u8 *peer_addr;
- + bool is_wep = key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
- + key->cipher == WLAN_CIPHER_SUITE_WEP104;
- ++ bool def_idx = false;
- + int ret = 0;
- +
- + if (key->keyidx > WMI_MAX_KEY_INDEX)
- +@@ -3186,7 +3844,7 @@ static int ath10k_set_key(struct ieee802
- +
- + if (!peer) {
- + if (cmd == SET_KEY) {
- +- ath10k_warn("failed to install key for non-existent peer %pM\n",
- ++ ath10k_warn(ar, "failed to install key for non-existent peer %pM\n",
- + peer_addr);
- + ret = -EOPNOTSUPP;
- + goto exit;
- +@@ -3207,9 +3865,16 @@ static int ath10k_set_key(struct ieee802
- + ath10k_clear_vdev_key(arvif, key);
- + }
- +
- +- ret = ath10k_install_key(arvif, key, cmd, peer_addr);
- ++ /* set TX_USAGE flag for all the keys incase of dot1x-WEP. For
- ++ * static WEP, do not set this flag for the keys whose key id
- ++ * is greater than default key id.
- ++ */
- ++ if (arvif->def_wep_key_idx == -1)
- ++ def_idx = true;
- ++
- ++ ret = ath10k_install_key(arvif, key, cmd, peer_addr, def_idx);
- + if (ret) {
- +- ath10k_warn("failed to install key for vdev %i peer %pM: %d\n",
- ++ ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n",
- + arvif->vdev_id, peer_addr, ret);
- + goto exit;
- + }
- +@@ -3224,7 +3889,7 @@ static int ath10k_set_key(struct ieee802
- + peer->keys[key->keyidx] = NULL;
- + else if (peer == NULL)
- + /* impossible unless FW goes crazy */
- +- ath10k_warn("Peer %pM disappeared!\n", peer_addr);
- ++ ath10k_warn(ar, "Peer %pM disappeared!\n", peer_addr);
- + spin_unlock_bh(&ar->data_lock);
- +
- + exit:
- +@@ -3232,6 +3897,39 @@ exit:
- + return ret;
- + }
- +
- ++static void ath10k_set_default_unicast_key(struct ieee80211_hw *hw,
- ++ struct ieee80211_vif *vif,
- ++ int keyidx)
- ++{
- ++ struct ath10k *ar = hw->priv;
- ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- ++ int ret;
- ++
- ++ mutex_lock(&arvif->ar->conf_mutex);
- ++
- ++ if (arvif->ar->state != ATH10K_STATE_ON)
- ++ goto unlock;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
- ++ arvif->vdev_id, keyidx);
- ++
- ++ ret = ath10k_wmi_vdev_set_param(arvif->ar,
- ++ arvif->vdev_id,
- ++ arvif->ar->wmi.vdev_param->def_keyid,
- ++ keyidx);
- ++
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n",
- ++ arvif->vdev_id,
- ++ ret);
- ++ goto unlock;
- ++ }
- ++
- ++ arvif->def_wep_key_idx = keyidx;
- ++unlock:
- ++ mutex_unlock(&arvif->ar->conf_mutex);
- ++}
- ++
- + static void ath10k_sta_rc_update_wk(struct work_struct *wk)
- + {
- + struct ath10k *ar;
- +@@ -3260,51 +3958,83 @@ static void ath10k_sta_rc_update_wk(stru
- + mutex_lock(&ar->conf_mutex);
- +
- + if (changed & IEEE80211_RC_BW_CHANGED) {
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
- + sta->addr, bw);
- +
- + err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
- + WMI_PEER_CHAN_WIDTH, bw);
- + if (err)
- +- ath10k_warn("failed to update STA %pM peer bw %d: %d\n",
- ++ ath10k_warn(ar, "failed to update STA %pM peer bw %d: %d\n",
- + sta->addr, bw, err);
- + }
- +
- + if (changed & IEEE80211_RC_NSS_CHANGED) {
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
- + sta->addr, nss);
- +
- + err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
- + WMI_PEER_NSS, nss);
- + if (err)
- +- ath10k_warn("failed to update STA %pM nss %d: %d\n",
- ++ ath10k_warn(ar, "failed to update STA %pM nss %d: %d\n",
- + sta->addr, nss, err);
- + }
- +
- + if (changed & IEEE80211_RC_SMPS_CHANGED) {
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
- + sta->addr, smps);
- +
- + err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
- + WMI_PEER_SMPS_STATE, smps);
- + if (err)
- +- ath10k_warn("failed to update STA %pM smps %d: %d\n",
- ++ ath10k_warn(ar, "failed to update STA %pM smps %d: %d\n",
- + sta->addr, smps, err);
- + }
- +
- +- if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
- ++ if (changed & IEEE80211_RC_SUPP_RATES_CHANGED ||
- ++ changed & IEEE80211_RC_NSS_CHANGED) {
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n",
- + sta->addr);
- +
- +- err = ath10k_station_assoc(ar, arvif, sta, true);
- ++ err = ath10k_station_assoc(ar, arvif->vif, sta, true);
- + if (err)
- +- ath10k_warn("failed to reassociate station: %pM\n",
- ++ ath10k_warn(ar, "failed to reassociate station: %pM\n",
- + sta->addr);
- + }
- +
- + mutex_unlock(&ar->conf_mutex);
- + }
- +
- ++static int ath10k_mac_inc_num_stations(struct ath10k_vif *arvif)
- ++{
- ++ struct ath10k *ar = arvif->ar;
- ++
- ++ lockdep_assert_held(&ar->conf_mutex);
- ++
- ++ if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
- ++ arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
- ++ return 0;
- ++
- ++ if (ar->num_stations >= ar->max_num_stations)
- ++ return -ENOBUFS;
- ++
- ++ ar->num_stations++;
- ++
- ++ return 0;
- ++}
- ++
- ++static void ath10k_mac_dec_num_stations(struct ath10k_vif *arvif)
- ++{
- ++ struct ath10k *ar = arvif->ar;
- ++
- ++ lockdep_assert_held(&ar->conf_mutex);
- ++
- ++ if (arvif->vdev_type != WMI_VDEV_TYPE_AP &&
- ++ arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
- ++ return;
- ++
- ++ ar->num_stations--;
- ++}
- ++
- + static int ath10k_sta_state(struct ieee80211_hw *hw,
- + struct ieee80211_vif *vif,
- + struct ieee80211_sta *sta,
- +@@ -3314,7 +4044,6 @@ static int ath10k_sta_state(struct ieee8
- + struct ath10k *ar = hw->priv;
- + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
- +- int max_num_peers;
- + int ret = 0;
- +
- + if (old_state == IEEE80211_STA_NOTEXIST &&
- +@@ -3332,46 +4061,72 @@ static int ath10k_sta_state(struct ieee8
- + mutex_lock(&ar->conf_mutex);
- +
- + if (old_state == IEEE80211_STA_NOTEXIST &&
- +- new_state == IEEE80211_STA_NONE &&
- +- vif->type != NL80211_IFTYPE_STATION) {
- ++ new_state == IEEE80211_STA_NONE) {
- + /*
- + * New station addition.
- + */
- +- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- +- max_num_peers = TARGET_10X_NUM_PEERS_MAX - 1;
- +- else
- +- max_num_peers = TARGET_NUM_PEERS;
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC,
- ++ "mac vdev %d peer create %pM (new sta) sta %d / %d peer %d / %d\n",
- ++ arvif->vdev_id, sta->addr,
- ++ ar->num_stations + 1, ar->max_num_stations,
- ++ ar->num_peers + 1, ar->max_num_peers);
- +
- +- if (ar->num_peers >= max_num_peers) {
- +- ath10k_warn("number of peers exceeded: peers number %d (max peers %d)\n",
- +- ar->num_peers, max_num_peers);
- +- ret = -ENOBUFS;
- ++ ret = ath10k_mac_inc_num_stations(arvif);
- ++ if (ret) {
- ++ ath10k_warn(ar, "refusing to associate station: too many connected already (%d)\n",
- ++ ar->max_num_stations);
- + goto exit;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_MAC,
- +- "mac vdev %d peer create %pM (new sta) num_peers %d\n",
- +- arvif->vdev_id, sta->addr, ar->num_peers);
- +-
- + ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
- +- if (ret)
- +- ath10k_warn("failed to add peer %pM for vdev %d when adding a new sta: %i\n",
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
- + sta->addr, arvif->vdev_id, ret);
- ++ ath10k_mac_dec_num_stations(arvif);
- ++ goto exit;
- ++ }
- ++
- ++ if (vif->type == NL80211_IFTYPE_STATION) {
- ++ WARN_ON(arvif->is_started);
- ++
- ++ ret = ath10k_vdev_start(arvif);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to start vdev %i: %d\n",
- ++ arvif->vdev_id, ret);
- ++ WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id,
- ++ sta->addr));
- ++ ath10k_mac_dec_num_stations(arvif);
- ++ goto exit;
- ++ }
- ++
- ++ arvif->is_started = true;
- ++ }
- + } else if ((old_state == IEEE80211_STA_NONE &&
- + new_state == IEEE80211_STA_NOTEXIST)) {
- + /*
- + * Existing station deletion.
- + */
- +- ath10k_dbg(ATH10K_DBG_MAC,
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC,
- + "mac vdev %d peer delete %pM (sta gone)\n",
- + arvif->vdev_id, sta->addr);
- ++
- ++ if (vif->type == NL80211_IFTYPE_STATION) {
- ++ WARN_ON(!arvif->is_started);
- ++
- ++ ret = ath10k_vdev_stop(arvif);
- ++ if (ret)
- ++ ath10k_warn(ar, "failed to stop vdev %i: %d\n",
- ++ arvif->vdev_id, ret);
- ++
- ++ arvif->is_started = false;
- ++ }
- ++
- + ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
- + if (ret)
- +- ath10k_warn("failed to delete peer %pM for vdev %d: %i\n",
- ++ ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
- + sta->addr, arvif->vdev_id, ret);
- +
- +- if (vif->type == NL80211_IFTYPE_STATION)
- +- ath10k_bss_disassoc(hw, vif);
- ++ ath10k_mac_dec_num_stations(arvif);
- + } else if (old_state == IEEE80211_STA_AUTH &&
- + new_state == IEEE80211_STA_ASSOC &&
- + (vif->type == NL80211_IFTYPE_AP ||
- +@@ -3379,12 +4134,12 @@ static int ath10k_sta_state(struct ieee8
- + /*
- + * New association.
- + */
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM associated\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM associated\n",
- + sta->addr);
- +
- +- ret = ath10k_station_assoc(ar, arvif, sta, false);
- ++ ret = ath10k_station_assoc(ar, vif, sta, false);
- + if (ret)
- +- ath10k_warn("failed to associate station %pM for vdev %i: %i\n",
- ++ ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
- + sta->addr, arvif->vdev_id, ret);
- + } else if (old_state == IEEE80211_STA_ASSOC &&
- + new_state == IEEE80211_STA_AUTH &&
- +@@ -3393,12 +4148,12 @@ static int ath10k_sta_state(struct ieee8
- + /*
- + * Disassociation.
- + */
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
- + sta->addr);
- +
- +- ret = ath10k_station_disassoc(ar, arvif, sta);
- ++ ret = ath10k_station_disassoc(ar, vif, sta);
- + if (ret)
- +- ath10k_warn("failed to disassociate station: %pM vdev %i: %i\n",
- ++ ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n",
- + sta->addr, arvif->vdev_id, ret);
- + }
- + exit:
- +@@ -3407,9 +4162,11 @@ exit:
- + }
- +
- + static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
- +- u16 ac, bool enable)
- ++ u16 ac, bool enable)
- + {
- + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- ++ struct wmi_sta_uapsd_auto_trig_arg arg = {};
- ++ u32 prio = 0, acc = 0;
- + u32 value = 0;
- + int ret = 0;
- +
- +@@ -3422,18 +4179,26 @@ static int ath10k_conf_tx_uapsd(struct a
- + case IEEE80211_AC_VO:
- + value = WMI_STA_PS_UAPSD_AC3_DELIVERY_EN |
- + WMI_STA_PS_UAPSD_AC3_TRIGGER_EN;
- ++ prio = 7;
- ++ acc = 3;
- + break;
- + case IEEE80211_AC_VI:
- + value = WMI_STA_PS_UAPSD_AC2_DELIVERY_EN |
- + WMI_STA_PS_UAPSD_AC2_TRIGGER_EN;
- ++ prio = 5;
- ++ acc = 2;
- + break;
- + case IEEE80211_AC_BE:
- + value = WMI_STA_PS_UAPSD_AC1_DELIVERY_EN |
- + WMI_STA_PS_UAPSD_AC1_TRIGGER_EN;
- ++ prio = 2;
- ++ acc = 1;
- + break;
- + case IEEE80211_AC_BK:
- + value = WMI_STA_PS_UAPSD_AC0_DELIVERY_EN |
- + WMI_STA_PS_UAPSD_AC0_TRIGGER_EN;
- ++ prio = 0;
- ++ acc = 0;
- + break;
- + }
- +
- +@@ -3446,7 +4211,7 @@ static int ath10k_conf_tx_uapsd(struct a
- + WMI_STA_PS_PARAM_UAPSD,
- + arvif->u.sta.uapsd);
- + if (ret) {
- +- ath10k_warn("failed to set uapsd params: %d\n", ret);
- ++ ath10k_warn(ar, "failed to set uapsd params: %d\n", ret);
- + goto exit;
- + }
- +
- +@@ -3459,7 +4224,44 @@ static int ath10k_conf_tx_uapsd(struct a
- + WMI_STA_PS_PARAM_RX_WAKE_POLICY,
- + value);
- + if (ret)
- +- ath10k_warn("failed to set rx wake param: %d\n", ret);
- ++ ath10k_warn(ar, "failed to set rx wake param: %d\n", ret);
- ++
- ++ ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n",
- ++ arvif->vdev_id, ret);
- ++ return ret;
- ++ }
- ++
- ++ ret = ath10k_mac_vif_recalc_ps_poll_count(arvif);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n",
- ++ arvif->vdev_id, ret);
- ++ return ret;
- ++ }
- ++
- ++ if (test_bit(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, ar->wmi.svc_map) ||
- ++ test_bit(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, ar->wmi.svc_map)) {
- ++ /* Only userspace can make an educated decision when to send
- ++ * trigger frame. The following effectively disables u-UAPSD
- ++ * autotrigger in firmware (which is enabled by default
- ++ * provided the autotrigger service is available).
- ++ */
- ++
- ++ arg.wmm_ac = acc;
- ++ arg.user_priority = prio;
- ++ arg.service_interval = 0;
- ++ arg.suspend_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC;
- ++ arg.delay_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC;
- ++
- ++ ret = ath10k_wmi_vdev_sta_uapsd(ar, arvif->vdev_id,
- ++ arvif->bssid, &arg, 1);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to set uapsd auto trigger %d\n",
- ++ ret);
- ++ return ret;
- ++ }
- ++ }
- +
- + exit:
- + return ret;
- +@@ -3470,6 +4272,7 @@ static int ath10k_conf_tx(struct ieee802
- + const struct ieee80211_tx_queue_params *params)
- + {
- + struct ath10k *ar = hw->priv;
- ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- + struct wmi_wmm_params_arg *p = NULL;
- + int ret;
- +
- +@@ -3477,16 +4280,16 @@ static int ath10k_conf_tx(struct ieee802
- +
- + switch (ac) {
- + case IEEE80211_AC_VO:
- +- p = &ar->wmm_params.ac_vo;
- ++ p = &arvif->wmm_params.ac_vo;
- + break;
- + case IEEE80211_AC_VI:
- +- p = &ar->wmm_params.ac_vi;
- ++ p = &arvif->wmm_params.ac_vi;
- + break;
- + case IEEE80211_AC_BE:
- +- p = &ar->wmm_params.ac_be;
- ++ p = &arvif->wmm_params.ac_be;
- + break;
- + case IEEE80211_AC_BK:
- +- p = &ar->wmm_params.ac_bk;
- ++ p = &arvif->wmm_params.ac_bk;
- + break;
- + }
- +
- +@@ -3506,16 +4309,28 @@ static int ath10k_conf_tx(struct ieee802
- + */
- + p->txop = params->txop * 32;
- +
- +- /* FIXME: FW accepts wmm params per hw, not per vif */
- +- ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params);
- +- if (ret) {
- +- ath10k_warn("failed to set wmm params: %d\n", ret);
- +- goto exit;
- ++ if (ar->wmi.ops->gen_vdev_wmm_conf) {
- ++ ret = ath10k_wmi_vdev_wmm_conf(ar, arvif->vdev_id,
- ++ &arvif->wmm_params);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to set vdev wmm params on vdev %i: %d\n",
- ++ arvif->vdev_id, ret);
- ++ goto exit;
- ++ }
- ++ } else {
- ++ /* This won't work well with multi-interface cases but it's
- ++ * better than nothing.
- ++ */
- ++ ret = ath10k_wmi_pdev_set_wmm_params(ar, &arvif->wmm_params);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to set wmm params: %d\n", ret);
- ++ goto exit;
- ++ }
- + }
- +
- + ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
- + if (ret)
- +- ath10k_warn("failed to set sta uapsd: %d\n", ret);
- ++ ath10k_warn(ar, "failed to set sta uapsd: %d\n", ret);
- +
- + exit:
- + mutex_unlock(&ar->conf_mutex);
- +@@ -3533,27 +4348,35 @@ static int ath10k_remain_on_channel(stru
- + struct ath10k *ar = hw->priv;
- + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- + struct wmi_start_scan_arg arg;
- +- int ret;
- ++ int ret = 0;
- +
- + mutex_lock(&ar->conf_mutex);
- +
- + spin_lock_bh(&ar->data_lock);
- +- if (ar->scan.in_progress) {
- +- spin_unlock_bh(&ar->data_lock);
- ++ switch (ar->scan.state) {
- ++ case ATH10K_SCAN_IDLE:
- ++ reinit_completion(&ar->scan.started);
- ++ reinit_completion(&ar->scan.completed);
- ++ reinit_completion(&ar->scan.on_channel);
- ++ ar->scan.state = ATH10K_SCAN_STARTING;
- ++ ar->scan.is_roc = true;
- ++ ar->scan.vdev_id = arvif->vdev_id;
- ++ ar->scan.roc_freq = chan->center_freq;
- ++ ret = 0;
- ++ break;
- ++ case ATH10K_SCAN_STARTING:
- ++ case ATH10K_SCAN_RUNNING:
- ++ case ATH10K_SCAN_ABORTING:
- + ret = -EBUSY;
- +- goto exit;
- ++ break;
- + }
- +-
- +- reinit_completion(&ar->scan.started);
- +- reinit_completion(&ar->scan.completed);
- +- reinit_completion(&ar->scan.on_channel);
- +- ar->scan.in_progress = true;
- +- ar->scan.aborting = false;
- +- ar->scan.is_roc = true;
- +- ar->scan.vdev_id = arvif->vdev_id;
- +- ar->scan.roc_freq = chan->center_freq;
- + spin_unlock_bh(&ar->data_lock);
- +
- ++ if (ret)
- ++ goto exit;
- ++
- ++ duration = max(duration, WMI_SCAN_CHAN_MIN_TIME_MSEC);
- ++
- + memset(&arg, 0, sizeof(arg));
- + ath10k_wmi_start_scan_init(ar, &arg);
- + arg.vdev_id = arvif->vdev_id;
- +@@ -3568,17 +4391,21 @@ static int ath10k_remain_on_channel(stru
- +
- + ret = ath10k_start_scan(ar, &arg);
- + if (ret) {
- +- ath10k_warn("failed to start roc scan: %d\n", ret);
- ++ ath10k_warn(ar, "failed to start roc scan: %d\n", ret);
- + spin_lock_bh(&ar->data_lock);
- +- ar->scan.in_progress = false;
- ++ ar->scan.state = ATH10K_SCAN_IDLE;
- + spin_unlock_bh(&ar->data_lock);
- + goto exit;
- + }
- +
- + ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ);
- + if (ret == 0) {
- +- ath10k_warn("failed to switch to channel for roc scan\n");
- +- ath10k_abort_scan(ar);
- ++ ath10k_warn(ar, "failed to switch to channel for roc scan\n");
- ++
- ++ ret = ath10k_scan_stop(ar);
- ++ if (ret)
- ++ ath10k_warn(ar, "failed to stop scan: %d\n", ret);
- ++
- + ret = -ETIMEDOUT;
- + goto exit;
- + }
- +@@ -3594,9 +4421,11 @@ static int ath10k_cancel_remain_on_chann
- + struct ath10k *ar = hw->priv;
- +
- + mutex_lock(&ar->conf_mutex);
- +- ath10k_abort_scan(ar);
- ++ ath10k_scan_abort(ar);
- + mutex_unlock(&ar->conf_mutex);
- +
- ++ cancel_delayed_work_sync(&ar->scan.timeout);
- ++
- + return 0;
- + }
- +
- +@@ -3613,35 +4442,12 @@ static int ath10k_set_rts_threshold(stru
- +
- + mutex_lock(&ar->conf_mutex);
- + list_for_each_entry(arvif, &ar->arvifs, list) {
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n",
- +- arvif->vdev_id, value);
- +-
- +- ret = ath10k_mac_set_rts(arvif, value);
- +- if (ret) {
- +- ath10k_warn("failed to set rts threshold for vdev %d: %d\n",
- +- arvif->vdev_id, ret);
- +- break;
- +- }
- +- }
- +- mutex_unlock(&ar->conf_mutex);
- +-
- +- return ret;
- +-}
- +-
- +-static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
- +-{
- +- struct ath10k *ar = hw->priv;
- +- struct ath10k_vif *arvif;
- +- int ret = 0;
- +-
- +- mutex_lock(&ar->conf_mutex);
- +- list_for_each_entry(arvif, &ar->arvifs, list) {
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n",
- + arvif->vdev_id, value);
- +
- + ret = ath10k_mac_set_rts(arvif, value);
- + if (ret) {
- +- ath10k_warn("failed to set fragmentation threshold for vdev %d: %d\n",
- ++ ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n",
- + arvif->vdev_id, ret);
- + break;
- + }
- +@@ -3675,13 +4481,15 @@ static void ath10k_flush(struct ieee8021
- + empty = (ar->htt.num_pending_tx == 0);
- + spin_unlock_bh(&ar->htt.tx_lock);
- +
- +- skip = (ar->state == ATH10K_STATE_WEDGED);
- ++ skip = (ar->state == ATH10K_STATE_WEDGED) ||
- ++ test_bit(ATH10K_FLAG_CRASH_FLUSH,
- ++ &ar->dev_flags);
- +
- + (empty || skip);
- + }), ATH10K_FLUSH_TIMEOUT_HZ);
- +
- + if (ret <= 0 || skip)
- +- ath10k_warn("failed to flush transmit queue (skip %i ar-state %i): %i\n",
- ++ ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %i\n",
- + skip, ar->state, ret);
- +
- + skip:
- +@@ -3716,7 +4524,7 @@ static int ath10k_suspend(struct ieee802
- +
- + ret = ath10k_hif_suspend(ar);
- + if (ret) {
- +- ath10k_warn("failed to suspend hif: %d\n", ret);
- ++ ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
- + goto resume;
- + }
- +
- +@@ -3725,7 +4533,7 @@ static int ath10k_suspend(struct ieee802
- + resume:
- + ret = ath10k_wmi_pdev_resume_target(ar);
- + if (ret)
- +- ath10k_warn("failed to resume target: %d\n", ret);
- ++ ath10k_warn(ar, "failed to resume target: %d\n", ret);
- +
- + ret = 1;
- + exit:
- +@@ -3742,14 +4550,14 @@ static int ath10k_resume(struct ieee8021
- +
- + ret = ath10k_hif_resume(ar);
- + if (ret) {
- +- ath10k_warn("failed to resume hif: %d\n", ret);
- ++ ath10k_warn(ar, "failed to resume hif: %d\n", ret);
- + ret = 1;
- + goto exit;
- + }
- +
- + ret = ath10k_wmi_pdev_resume_target(ar);
- + if (ret) {
- +- ath10k_warn("failed to resume target: %d\n", ret);
- ++ ath10k_warn(ar, "failed to resume target: %d\n", ret);
- + ret = 1;
- + goto exit;
- + }
- +@@ -3770,8 +4578,9 @@ static void ath10k_restart_complete(stru
- + /* If device failed to restart it will be in a different state, e.g.
- + * ATH10K_STATE_WEDGED */
- + if (ar->state == ATH10K_STATE_RESTARTED) {
- +- ath10k_info("device successfully recovered\n");
- ++ ath10k_info(ar, "device successfully recovered\n");
- + ar->state = ATH10K_STATE_ON;
- ++ ieee80211_wake_queues(ar->hw);
- + }
- +
- + mutex_unlock(&ar->conf_mutex);
- +@@ -3807,6 +4616,9 @@ static int ath10k_get_survey(struct ieee
- +
- + survey->channel = &sband->channels[idx];
- +
- ++ if (ar->rx_channel == survey->channel)
- ++ survey->filled |= SURVEY_INFO_IN_USE;
- ++
- + exit:
- + mutex_unlock(&ar->conf_mutex);
- + return ret;
- +@@ -3854,6 +4666,10 @@ ath10k_default_bitrate_mask(struct ath10
- + u32 legacy = 0x00ff;
- + u8 ht = 0xff, i;
- + u16 vht = 0x3ff;
- ++ u16 nrf = ar->num_rf_chains;
- ++
- ++ if (ar->cfg_tx_chainmask)
- ++ nrf = get_nss_from_chainmask(ar->cfg_tx_chainmask);
- +
- + switch (band) {
- + case IEEE80211_BAND_2GHZ:
- +@@ -3869,11 +4685,11 @@ ath10k_default_bitrate_mask(struct ath10
- + if (mask->control[band].legacy != legacy)
- + return false;
- +
- +- for (i = 0; i < ar->num_rf_chains; i++)
- ++ for (i = 0; i < nrf; i++)
- + if (mask->control[band].ht_mcs[i] != ht)
- + return false;
- +
- +- for (i = 0; i < ar->num_rf_chains; i++)
- ++ for (i = 0; i < nrf; i++)
- + if (mask->control[band].vht_mcs[i] != vht)
- + return false;
- +
- +@@ -3897,8 +4713,8 @@ ath10k_bitrate_mask_nss(const struct cfg
- + continue;
- + else if (mask->control[band].ht_mcs[i] == 0x00)
- + break;
- +- else
- +- return false;
- ++
- ++ return false;
- + }
- +
- + ht_nss = i;
- +@@ -3909,8 +4725,8 @@ ath10k_bitrate_mask_nss(const struct cfg
- + continue;
- + else if (mask->control[band].vht_mcs[i] == 0x0000)
- + break;
- +- else
- +- return false;
- ++
- ++ return false;
- + }
- +
- + vht_nss = i;
- +@@ -3967,7 +4783,8 @@ ath10k_bitrate_mask_correct(const struct
- + }
- +
- + static bool
- +-ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask,
- ++ath10k_bitrate_mask_rate(struct ath10k *ar,
- ++ const struct cfg80211_bitrate_mask *mask,
- + enum ieee80211_band band,
- + u8 *fixed_rate,
- + u8 *fixed_nss)
- +@@ -4025,7 +4842,7 @@ ath10k_bitrate_mask_rate(const struct cf
- + nss <<= 4;
- + pream <<= 6;
- +
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
- + pream, nss, rate);
- +
- + *fixed_rate = pream | nss | rate;
- +@@ -4033,7 +4850,8 @@ ath10k_bitrate_mask_rate(const struct cf
- + return true;
- + }
- +
- +-static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask,
- ++static bool ath10k_get_fixed_rate_nss(struct ath10k *ar,
- ++ const struct cfg80211_bitrate_mask *mask,
- + enum ieee80211_band band,
- + u8 *fixed_rate,
- + u8 *fixed_nss)
- +@@ -4043,7 +4861,7 @@ static bool ath10k_get_fixed_rate_nss(co
- + return true;
- +
- + /* Next Check single rate is set */
- +- return ath10k_bitrate_mask_rate(mask, band, fixed_rate, fixed_nss);
- ++ return ath10k_bitrate_mask_rate(ar, mask, band, fixed_rate, fixed_nss);
- + }
- +
- + static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
- +@@ -4063,16 +4881,16 @@ static int ath10k_set_fixed_rate_param(s
- + goto exit;
- +
- + if (fixed_rate == WMI_FIXED_RATE_NONE)
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
- +
- + if (force_sgi)
- +- ath10k_dbg(ATH10K_DBG_MAC, "mac force sgi\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac force sgi\n");
- +
- + vdev_param = ar->wmi.vdev_param->fixed_rate;
- + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
- + vdev_param, fixed_rate);
- + if (ret) {
- +- ath10k_warn("failed to set fixed rate param 0x%02x: %d\n",
- ++ ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n",
- + fixed_rate, ret);
- + ret = -EINVAL;
- + goto exit;
- +@@ -4085,7 +4903,7 @@ static int ath10k_set_fixed_rate_param(s
- + vdev_param, fixed_nss);
- +
- + if (ret) {
- +- ath10k_warn("failed to set fixed nss param %d: %d\n",
- ++ ath10k_warn(ar, "failed to set fixed nss param %d: %d\n",
- + fixed_nss, ret);
- + ret = -EINVAL;
- + goto exit;
- +@@ -4098,7 +4916,7 @@ static int ath10k_set_fixed_rate_param(s
- + force_sgi);
- +
- + if (ret) {
- +- ath10k_warn("failed to set sgi param %d: %d\n",
- ++ ath10k_warn(ar, "failed to set sgi param %d: %d\n",
- + force_sgi, ret);
- + ret = -EINVAL;
- + goto exit;
- +@@ -4122,19 +4940,22 @@ static int ath10k_set_bitrate_mask(struc
- + u8 fixed_nss = ar->num_rf_chains;
- + u8 force_sgi;
- +
- ++ if (ar->cfg_tx_chainmask)
- ++ fixed_nss = get_nss_from_chainmask(ar->cfg_tx_chainmask);
- ++
- + force_sgi = mask->control[band].gi;
- + if (force_sgi == NL80211_TXRATE_FORCE_LGI)
- + return -EINVAL;
- +
- + if (!ath10k_default_bitrate_mask(ar, band, mask)) {
- +- if (!ath10k_get_fixed_rate_nss(mask, band,
- ++ if (!ath10k_get_fixed_rate_nss(ar, mask, band,
- + &fixed_rate,
- + &fixed_nss))
- + return -EINVAL;
- + }
- +
- + if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) {
- +- ath10k_warn("failed to force SGI usage for default rate settings\n");
- ++ ath10k_warn(ar, "failed to force SGI usage for default rate settings\n");
- + return -EINVAL;
- + }
- +
- +@@ -4153,7 +4974,7 @@ static void ath10k_sta_rc_update(struct
- +
- + spin_lock_bh(&ar->data_lock);
- +
- +- ath10k_dbg(ATH10K_DBG_MAC,
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC,
- + "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
- + sta->addr, changed, sta->bandwidth, sta->rx_nss,
- + sta->smps_mode);
- +@@ -4172,7 +4993,7 @@ static void ath10k_sta_rc_update(struct
- + bw = WMI_PEER_CHWIDTH_80MHZ;
- + break;
- + case IEEE80211_STA_RX_BW_160:
- +- ath10k_warn("Invalid bandwith %d in rc update for %pM\n",
- ++ ath10k_warn(ar, "Invalid bandwith %d in rc update for %pM\n",
- + sta->bandwidth, sta->addr);
- + bw = WMI_PEER_CHWIDTH_20MHZ;
- + break;
- +@@ -4199,7 +5020,7 @@ static void ath10k_sta_rc_update(struct
- + smps = WMI_PEER_SMPS_DYNAMIC;
- + break;
- + case IEEE80211_SMPS_NUM_MODES:
- +- ath10k_warn("Invalid smps %d in sta rc update for %pM\n",
- ++ ath10k_warn(ar, "Invalid smps %d in sta rc update for %pM\n",
- + sta->smps_mode, sta->addr);
- + smps = WMI_PEER_SMPS_PS_NONE;
- + break;
- +@@ -4225,6 +5046,39 @@ static u64 ath10k_get_tsf(struct ieee802
- + return 0;
- + }
- +
- ++static int ath10k_ampdu_action(struct ieee80211_hw *hw,
- ++ struct ieee80211_vif *vif,
- ++ enum ieee80211_ampdu_mlme_action action,
- ++ struct ieee80211_sta *sta, u16 tid, u16 *ssn,
- ++ u8 buf_size)
- ++{
- ++ struct ath10k *ar = hw->priv;
- ++ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n",
- ++ arvif->vdev_id, sta->addr, tid, action);
- ++
- ++ switch (action) {
- ++ case IEEE80211_AMPDU_RX_START:
- ++ case IEEE80211_AMPDU_RX_STOP:
- ++ /* HTT AddBa/DelBa events trigger mac80211 Rx BA session
- ++ * creation/removal. Do we need to verify this?
- ++ */
- ++ return 0;
- ++ case IEEE80211_AMPDU_TX_START:
- ++ case IEEE80211_AMPDU_TX_STOP_CONT:
- ++ case IEEE80211_AMPDU_TX_STOP_FLUSH:
- ++ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
- ++ case IEEE80211_AMPDU_TX_OPERATIONAL:
- ++ /* Firmware offloads Tx aggregation entirely so deny mac80211
- ++ * Tx aggregation requests.
- ++ */
- ++ return -EOPNOTSUPP;
- ++ }
- ++
- ++ return -EINVAL;
- ++}
- ++
- + static const struct ieee80211_ops ath10k_ops = {
- + .tx = ath10k_tx,
- + .start = ath10k_start,
- +@@ -4237,23 +5091,35 @@ static const struct ieee80211_ops ath10k
- + .hw_scan = ath10k_hw_scan,
- + .cancel_hw_scan = ath10k_cancel_hw_scan,
- + .set_key = ath10k_set_key,
- ++ .set_default_unicast_key = ath10k_set_default_unicast_key,
- + .sta_state = ath10k_sta_state,
- + .conf_tx = ath10k_conf_tx,
- + .remain_on_channel = ath10k_remain_on_channel,
- + .cancel_remain_on_channel = ath10k_cancel_remain_on_channel,
- + .set_rts_threshold = ath10k_set_rts_threshold,
- +- .set_frag_threshold = ath10k_set_frag_threshold,
- + .flush = ath10k_flush,
- + .tx_last_beacon = ath10k_tx_last_beacon,
- ++ .set_antenna = ath10k_set_antenna,
- ++ .get_antenna = ath10k_get_antenna,
- + .restart_complete = ath10k_restart_complete,
- + .get_survey = ath10k_get_survey,
- + .set_bitrate_mask = ath10k_set_bitrate_mask,
- + .sta_rc_update = ath10k_sta_rc_update,
- + .get_tsf = ath10k_get_tsf,
- ++ .ampdu_action = ath10k_ampdu_action,
- ++ .get_et_sset_count = ath10k_debug_get_et_sset_count,
- ++ .get_et_stats = ath10k_debug_get_et_stats,
- ++ .get_et_strings = ath10k_debug_get_et_strings,
- ++
- ++ CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
- ++
- + #ifdef CONFIG_PM
- + .suspend = ath10k_suspend,
- + .resume = ath10k_resume,
- + #endif
- ++#ifdef CPTCFG_MAC80211_DEBUGFS
- ++ .sta_add_debugfs = ath10k_sta_add_debugfs,
- ++#endif
- + };
- +
- + #define RATETAB_ENT(_rate, _rateid, _flags) { \
- +@@ -4324,6 +5190,9 @@ static const struct ieee80211_channel at
- + CHAN5G(165, 5825, 0),
- + };
- +
- ++/* Note: Be careful if you re-order these. There is code which depends on this
- ++ * ordering.
- ++ */
- + static struct ieee80211_rate ath10k_rates[] = {
- + /* CCK */
- + RATETAB_ENT(10, 0x82, 0),
- +@@ -4346,12 +5215,12 @@ static struct ieee80211_rate ath10k_rate
- + #define ath10k_g_rates (ath10k_rates + 0)
- + #define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates))
- +
- +-struct ath10k *ath10k_mac_create(void)
- ++struct ath10k *ath10k_mac_create(size_t priv_size)
- + {
- + struct ieee80211_hw *hw;
- + struct ath10k *ar;
- +
- +- hw = ieee80211_alloc_hw(sizeof(struct ath10k), &ath10k_ops);
- ++ hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, &ath10k_ops);
- + if (!hw)
- + return NULL;
- +
- +@@ -4377,6 +5246,10 @@ static const struct ieee80211_iface_limi
- + .types = BIT(NL80211_IFTYPE_P2P_GO)
- + },
- + {
- ++ .max = 1,
- ++ .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
- ++ },
- ++ {
- + .max = 7,
- + .types = BIT(NL80211_IFTYPE_AP)
- + },
- +@@ -4501,7 +5374,6 @@ static struct ieee80211_sta_ht_cap ath10
- + return ht_cap;
- + }
- +
- +-
- + static void ath10k_get_arvif_iter(void *data, u8 *mac,
- + struct ieee80211_vif *vif)
- + {
- +@@ -4526,7 +5398,7 @@ struct ath10k_vif *ath10k_get_arvif(stru
- + ath10k_get_arvif_iter,
- + &arvif_iter);
- + if (!arvif_iter.arvif) {
- +- ath10k_warn("No VIF found for vdev %d\n", vdev_id);
- ++ ath10k_warn(ar, "No VIF found for vdev %d\n", vdev_id);
- + return NULL;
- + }
- +
- +@@ -4564,7 +5436,8 @@ int ath10k_mac_register(struct ath10k *a
- + band->bitrates = ath10k_g_rates;
- + band->ht_cap = ht_cap;
- +
- +- /* vht is not supported in 2.4 GHz */
- ++ /* Enable the VHT support at 2.4 GHz */
- ++ band->vht_cap = vht_cap;
- +
- + ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = band;
- + }
- +@@ -4590,18 +5463,20 @@ int ath10k_mac_register(struct ath10k *a
- +
- + ar->hw->wiphy->interface_modes =
- + BIT(NL80211_IFTYPE_STATION) |
- +- BIT(NL80211_IFTYPE_ADHOC) |
- + BIT(NL80211_IFTYPE_AP);
- +
- ++ ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask;
- ++ ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask;
- ++
- + if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features))
- + ar->hw->wiphy->interface_modes |=
- ++ BIT(NL80211_IFTYPE_P2P_DEVICE) |
- + BIT(NL80211_IFTYPE_P2P_CLIENT) |
- + BIT(NL80211_IFTYPE_P2P_GO);
- +
- + ar->hw->flags = IEEE80211_HW_SIGNAL_DBM |
- + IEEE80211_HW_SUPPORTS_PS |
- + IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- +- IEEE80211_HW_SUPPORTS_UAPSD |
- + IEEE80211_HW_MFP_CAPABLE |
- + IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- + IEEE80211_HW_HAS_RATE_CONTROL |
- +@@ -4609,10 +5484,6 @@ int ath10k_mac_register(struct ath10k *a
- + IEEE80211_HW_AP_LINK_PS |
- + IEEE80211_HW_SPECTRUM_MGMT;
- +
- +- /* MSDU can have HTT TX fragment pushed in front. The additional 4
- +- * bytes is used for padding/alignment if necessary. */
- +- ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4;
- +-
- + if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
- + ar->hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;
- +
- +@@ -4629,25 +5500,52 @@ int ath10k_mac_register(struct ath10k *a
- +
- + ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
- +
- ++ if (test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) {
- ++ ar->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
- ++
- ++ /* Firmware delivers WPS/P2P Probe Requests frames to driver so
- ++ * that userspace (e.g. wpa_supplicant/hostapd) can generate
- ++ * correct Probe Responses. This is more of a hack advert..
- ++ */
- ++ ar->hw->wiphy->probe_resp_offload |=
- ++ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
- ++ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
- ++ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
- ++ }
- ++
- + ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
- + ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
- + ar->hw->wiphy->max_remain_on_channel_duration = 5000;
- +
- + ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
- ++ ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
- ++
- + /*
- + * on LL hardware queues are managed entirely by the FW
- + * so we only advertise to mac we can do the queues thing
- + */
- + ar->hw->queues = 4;
- +
- +- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- +- ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
- +- ar->hw->wiphy->n_iface_combinations =
- +- ARRAY_SIZE(ath10k_10x_if_comb);
- +- } else {
- ++ switch (ar->wmi.op_version) {
- ++ case ATH10K_FW_WMI_OP_VERSION_MAIN:
- ++ case ATH10K_FW_WMI_OP_VERSION_TLV:
- + ar->hw->wiphy->iface_combinations = ath10k_if_comb;
- + ar->hw->wiphy->n_iface_combinations =
- + ARRAY_SIZE(ath10k_if_comb);
- ++ ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
- ++ break;
- ++ case ATH10K_FW_WMI_OP_VERSION_10_1:
- ++ case ATH10K_FW_WMI_OP_VERSION_10_2:
- ++ case ATH10K_FW_WMI_OP_VERSION_10_2_4:
- ++ ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
- ++ ar->hw->wiphy->n_iface_combinations =
- ++ ARRAY_SIZE(ath10k_10x_if_comb);
- ++ break;
- ++ case ATH10K_FW_WMI_OP_VERSION_UNSET:
- ++ case ATH10K_FW_WMI_OP_VERSION_MAX:
- ++ WARN_ON(1);
- ++ ret = -EINVAL;
- ++ goto err_free;
- + }
- +
- + ar->hw->netdev_features = NETIF_F_HW_CSUM;
- +@@ -4659,19 +5557,19 @@ int ath10k_mac_register(struct ath10k *a
- + NL80211_DFS_UNSET);
- +
- + if (!ar->dfs_detector)
- +- ath10k_warn("failed to initialise DFS pattern detector\n");
- ++ ath10k_warn(ar, "failed to initialise DFS pattern detector\n");
- + }
- +
- + ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
- + ath10k_reg_notifier);
- + if (ret) {
- +- ath10k_err("failed to initialise regulatory: %i\n", ret);
- ++ ath10k_err(ar, "failed to initialise regulatory: %i\n", ret);
- + goto err_free;
- + }
- +
- + ret = ieee80211_register_hw(ar->hw);
- + if (ret) {
- +- ath10k_err("failed to register ieee80211: %d\n", ret);
- ++ ath10k_err(ar, "failed to register ieee80211: %d\n", ret);
- + goto err_free;
- + }
- +
- +--- a/drivers/net/wireless/ath/ath10k/mac.h
- ++++ b/drivers/net/wireless/ath/ath10k/mac.h
- +@@ -21,33 +21,41 @@
- + #include <net/mac80211.h>
- + #include "core.h"
- +
- ++#define WEP_KEYID_SHIFT 6
- ++
- + struct ath10k_generic_iter {
- + struct ath10k *ar;
- + int ret;
- + };
- +
- +-struct ath10k *ath10k_mac_create(void);
- ++struct ath10k *ath10k_mac_create(size_t priv_size);
- + void ath10k_mac_destroy(struct ath10k *ar);
- + int ath10k_mac_register(struct ath10k *ar);
- + void ath10k_mac_unregister(struct ath10k *ar);
- + struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id);
- +-void ath10k_reset_scan(unsigned long ptr);
- ++void __ath10k_scan_finish(struct ath10k *ar);
- ++void ath10k_scan_finish(struct ath10k *ar);
- ++void ath10k_scan_timeout_work(struct work_struct *work);
- + void ath10k_offchan_tx_purge(struct ath10k *ar);
- + void ath10k_offchan_tx_work(struct work_struct *work);
- + void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar);
- + void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work);
- + void ath10k_halt(struct ath10k *ar);
- ++void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
- ++void ath10k_drain_tx(struct ath10k *ar);
- ++bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
- ++ u8 keyidx);
- +
- + static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
- + {
- + return (struct ath10k_vif *)vif->drv_priv;
- + }
- +
- +-static inline void ath10k_tx_h_seq_no(struct sk_buff *skb)
- ++static inline void ath10k_tx_h_seq_no(struct ieee80211_vif *vif,
- ++ struct sk_buff *skb)
- + {
- + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- +- struct ieee80211_vif *vif = info->control.vif;
- + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- +
- + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
- +--- a/drivers/net/wireless/ath/ath10k/pci.c
- ++++ b/drivers/net/wireless/ath/ath10k/pci.c
- +@@ -44,13 +44,9 @@ enum ath10k_pci_reset_mode {
- + ATH10K_PCI_RESET_WARM_ONLY = 1,
- + };
- +
- +-static unsigned int ath10k_pci_target_ps;
- + static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO;
- + static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO;
- +
- +-module_param_named(target_ps, ath10k_pci_target_ps, uint, 0644);
- +-MODULE_PARM_DESC(target_ps, "Enable ath10k Target (SoC) PS option");
- +-
- + module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644);
- + MODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)");
- +
- +@@ -59,21 +55,31 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1
- +
- + /* how long wait to wait for target to initialise, in ms */
- + #define ATH10K_PCI_TARGET_WAIT 3000
- ++#define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3
- +
- + #define QCA988X_2_0_DEVICE_ID (0x003c)
- ++#define QCA6174_2_1_DEVICE_ID (0x003e)
- +
- +-static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = {
- ++static const struct pci_device_id ath10k_pci_id_table[] = {
- + { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */
- ++ { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */
- + {0}
- + };
- +
- +-static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
- +- u32 *data);
- ++static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {
- ++ /* QCA988X pre 2.0 chips are not supported because they need some nasty
- ++ * hacks. ath10k doesn't have them and these devices crash horribly
- ++ * because of that.
- ++ */
- ++ { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV },
- ++ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV },
- ++ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_2_CHIP_ID_REV },
- ++ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV },
- ++ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV },
- ++ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV },
- ++};
- +
- +-static int ath10k_pci_post_rx(struct ath10k *ar);
- +-static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
- +- int num);
- +-static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
- ++static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
- + static int ath10k_pci_cold_reset(struct ath10k *ar);
- + static int ath10k_pci_warm_reset(struct ath10k *ar);
- + static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
- +@@ -98,7 +104,7 @@ static const struct ce_attr host_ce_conf
- + {
- + .flags = CE_ATTR_FLAGS,
- + .src_nentries = 0,
- +- .src_sz_max = 512,
- ++ .src_sz_max = 2048,
- + .dest_nentries = 512,
- + },
- +
- +@@ -155,79 +161,175 @@ static const struct ce_attr host_ce_conf
- + static const struct ce_pipe_config target_ce_config_wlan[] = {
- + /* CE0: host->target HTC control and raw streams */
- + {
- +- .pipenum = 0,
- +- .pipedir = PIPEDIR_OUT,
- +- .nentries = 32,
- +- .nbytes_max = 256,
- +- .flags = CE_ATTR_FLAGS,
- +- .reserved = 0,
- ++ .pipenum = __cpu_to_le32(0),
- ++ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
- ++ .nentries = __cpu_to_le32(32),
- ++ .nbytes_max = __cpu_to_le32(256),
- ++ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
- ++ .reserved = __cpu_to_le32(0),
- + },
- +
- + /* CE1: target->host HTT + HTC control */
- + {
- +- .pipenum = 1,
- +- .pipedir = PIPEDIR_IN,
- +- .nentries = 32,
- +- .nbytes_max = 512,
- +- .flags = CE_ATTR_FLAGS,
- +- .reserved = 0,
- ++ .pipenum = __cpu_to_le32(1),
- ++ .pipedir = __cpu_to_le32(PIPEDIR_IN),
- ++ .nentries = __cpu_to_le32(32),
- ++ .nbytes_max = __cpu_to_le32(2048),
- ++ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
- ++ .reserved = __cpu_to_le32(0),
- + },
- +
- + /* CE2: target->host WMI */
- + {
- +- .pipenum = 2,
- +- .pipedir = PIPEDIR_IN,
- +- .nentries = 32,
- +- .nbytes_max = 2048,
- +- .flags = CE_ATTR_FLAGS,
- +- .reserved = 0,
- ++ .pipenum = __cpu_to_le32(2),
- ++ .pipedir = __cpu_to_le32(PIPEDIR_IN),
- ++ .nentries = __cpu_to_le32(32),
- ++ .nbytes_max = __cpu_to_le32(2048),
- ++ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
- ++ .reserved = __cpu_to_le32(0),
- + },
- +
- + /* CE3: host->target WMI */
- + {
- +- .pipenum = 3,
- +- .pipedir = PIPEDIR_OUT,
- +- .nentries = 32,
- +- .nbytes_max = 2048,
- +- .flags = CE_ATTR_FLAGS,
- +- .reserved = 0,
- ++ .pipenum = __cpu_to_le32(3),
- ++ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
- ++ .nentries = __cpu_to_le32(32),
- ++ .nbytes_max = __cpu_to_le32(2048),
- ++ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
- ++ .reserved = __cpu_to_le32(0),
- + },
- +
- + /* CE4: host->target HTT */
- + {
- +- .pipenum = 4,
- +- .pipedir = PIPEDIR_OUT,
- +- .nentries = 256,
- +- .nbytes_max = 256,
- +- .flags = CE_ATTR_FLAGS,
- +- .reserved = 0,
- ++ .pipenum = __cpu_to_le32(4),
- ++ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
- ++ .nentries = __cpu_to_le32(256),
- ++ .nbytes_max = __cpu_to_le32(256),
- ++ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
- ++ .reserved = __cpu_to_le32(0),
- + },
- +
- + /* NB: 50% of src nentries, since tx has 2 frags */
- +
- + /* CE5: unused */
- + {
- +- .pipenum = 5,
- +- .pipedir = PIPEDIR_OUT,
- +- .nentries = 32,
- +- .nbytes_max = 2048,
- +- .flags = CE_ATTR_FLAGS,
- +- .reserved = 0,
- ++ .pipenum = __cpu_to_le32(5),
- ++ .pipedir = __cpu_to_le32(PIPEDIR_OUT),
- ++ .nentries = __cpu_to_le32(32),
- ++ .nbytes_max = __cpu_to_le32(2048),
- ++ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
- ++ .reserved = __cpu_to_le32(0),
- + },
- +
- + /* CE6: Reserved for target autonomous hif_memcpy */
- + {
- +- .pipenum = 6,
- +- .pipedir = PIPEDIR_INOUT,
- +- .nentries = 32,
- +- .nbytes_max = 4096,
- +- .flags = CE_ATTR_FLAGS,
- +- .reserved = 0,
- ++ .pipenum = __cpu_to_le32(6),
- ++ .pipedir = __cpu_to_le32(PIPEDIR_INOUT),
- ++ .nentries = __cpu_to_le32(32),
- ++ .nbytes_max = __cpu_to_le32(4096),
- ++ .flags = __cpu_to_le32(CE_ATTR_FLAGS),
- ++ .reserved = __cpu_to_le32(0),
- + },
- +
- + /* CE7 used only by Host */
- + };
- +
- ++/*
- ++ * Map from service/endpoint to Copy Engine.
- ++ * This table is derived from the CE_PCI TABLE, above.
- ++ * It is passed to the Target at startup for use by firmware.
- ++ */
- ++static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
- ++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
- ++ __cpu_to_le32(3),
- ++ },
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
- ++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
- ++ __cpu_to_le32(2),
- ++ },
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
- ++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
- ++ __cpu_to_le32(3),
- ++ },
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
- ++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
- ++ __cpu_to_le32(2),
- ++ },
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
- ++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
- ++ __cpu_to_le32(3),
- ++ },
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
- ++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
- ++ __cpu_to_le32(2),
- ++ },
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
- ++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
- ++ __cpu_to_le32(3),
- ++ },
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
- ++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
- ++ __cpu_to_le32(2),
- ++ },
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
- ++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
- ++ __cpu_to_le32(3),
- ++ },
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
- ++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
- ++ __cpu_to_le32(2),
- ++ },
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
- ++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
- ++ __cpu_to_le32(0),
- ++ },
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
- ++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
- ++ __cpu_to_le32(1),
- ++ },
- ++ { /* not used */
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
- ++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
- ++ __cpu_to_le32(0),
- ++ },
- ++ { /* not used */
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
- ++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
- ++ __cpu_to_le32(1),
- ++ },
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
- ++ __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
- ++ __cpu_to_le32(4),
- ++ },
- ++ {
- ++ __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
- ++ __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */
- ++ __cpu_to_le32(1),
- ++ },
- ++
- ++ /* (Additions here) */
- ++
- ++ { /* must be last */
- ++ __cpu_to_le32(0),
- ++ __cpu_to_le32(0),
- ++ __cpu_to_le32(0),
- ++ },
- ++};
- ++
- + static bool ath10k_pci_irq_pending(struct ath10k *ar)
- + {
- + u32 cause;
- +@@ -253,8 +355,8 @@ static void ath10k_pci_disable_and_clear
- +
- + /* IMPORTANT: this extra read transaction is required to
- + * flush the posted write buffer. */
- +- (void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
- +- PCIE_INTR_ENABLE_ADDRESS);
- ++ (void)ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
- ++ PCIE_INTR_ENABLE_ADDRESS);
- + }
- +
- + static void ath10k_pci_enable_legacy_irq(struct ath10k *ar)
- +@@ -265,48 +367,116 @@ static void ath10k_pci_enable_legacy_irq
- +
- + /* IMPORTANT: this extra read transaction is required to
- + * flush the posted write buffer. */
- +- (void) ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
- +- PCIE_INTR_ENABLE_ADDRESS);
- ++ (void)ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
- ++ PCIE_INTR_ENABLE_ADDRESS);
- + }
- +
- +-static irqreturn_t ath10k_pci_early_irq_handler(int irq, void *arg)
- ++static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar)
- + {
- +- struct ath10k *ar = arg;
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +
- +- if (ar_pci->num_msi_intrs == 0) {
- +- if (!ath10k_pci_irq_pending(ar))
- +- return IRQ_NONE;
- +-
- +- ath10k_pci_disable_and_clear_legacy_irq(ar);
- +- }
- ++ if (ar_pci->num_msi_intrs > 1)
- ++ return "msi-x";
- +
- +- tasklet_schedule(&ar_pci->early_irq_tasklet);
- ++ if (ar_pci->num_msi_intrs == 1)
- ++ return "msi";
- +
- +- return IRQ_HANDLED;
- ++ return "legacy";
- + }
- +
- +-static int ath10k_pci_request_early_irq(struct ath10k *ar)
- ++static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe)
- + {
- ++ struct ath10k *ar = pipe->hif_ce_state;
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++ struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
- ++ struct sk_buff *skb;
- ++ dma_addr_t paddr;
- + int ret;
- +
- +- /* Regardless whether MSI-X/MSI/legacy irqs have been set up the first
- +- * interrupt from irq vector is triggered in all cases for FW
- +- * indication/errors */
- +- ret = request_irq(ar_pci->pdev->irq, ath10k_pci_early_irq_handler,
- +- IRQF_SHARED, "ath10k_pci (early)", ar);
- ++ lockdep_assert_held(&ar_pci->ce_lock);
- ++
- ++ skb = dev_alloc_skb(pipe->buf_sz);
- ++ if (!skb)
- ++ return -ENOMEM;
- ++
- ++ WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
- ++
- ++ paddr = dma_map_single(ar->dev, skb->data,
- ++ skb->len + skb_tailroom(skb),
- ++ DMA_FROM_DEVICE);
- ++ if (unlikely(dma_mapping_error(ar->dev, paddr))) {
- ++ ath10k_warn(ar, "failed to dma map pci rx buf\n");
- ++ dev_kfree_skb_any(skb);
- ++ return -EIO;
- ++ }
- ++
- ++ ATH10K_SKB_RXCB(skb)->paddr = paddr;
- ++
- ++ ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr);
- + if (ret) {
- +- ath10k_warn("failed to request early irq: %d\n", ret);
- ++ ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret);
- ++ dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb),
- ++ DMA_FROM_DEVICE);
- ++ dev_kfree_skb_any(skb);
- + return ret;
- + }
- +
- + return 0;
- + }
- +
- +-static void ath10k_pci_free_early_irq(struct ath10k *ar)
- ++static void __ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
- ++{
- ++ struct ath10k *ar = pipe->hif_ce_state;
- ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++ struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
- ++ int ret, num;
- ++
- ++ lockdep_assert_held(&ar_pci->ce_lock);
- ++
- ++ if (pipe->buf_sz == 0)
- ++ return;
- ++
- ++ if (!ce_pipe->dest_ring)
- ++ return;
- ++
- ++ num = __ath10k_ce_rx_num_free_bufs(ce_pipe);
- ++ while (num--) {
- ++ ret = __ath10k_pci_rx_post_buf(pipe);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret);
- ++ mod_timer(&ar_pci->rx_post_retry, jiffies +
- ++ ATH10K_PCI_RX_POST_RETRY_MS);
- ++ break;
- ++ }
- ++ }
- ++}
- ++
- ++static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
- ++{
- ++ struct ath10k *ar = pipe->hif_ce_state;
- ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++
- ++ spin_lock_bh(&ar_pci->ce_lock);
- ++ __ath10k_pci_rx_post_pipe(pipe);
- ++ spin_unlock_bh(&ar_pci->ce_lock);
- ++}
- ++
- ++static void ath10k_pci_rx_post(struct ath10k *ar)
- ++{
- ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++ int i;
- ++
- ++ spin_lock_bh(&ar_pci->ce_lock);
- ++ for (i = 0; i < CE_COUNT; i++)
- ++ __ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]);
- ++ spin_unlock_bh(&ar_pci->ce_lock);
- ++}
- ++
- ++static void ath10k_pci_rx_replenish_retry(unsigned long ptr)
- + {
- +- free_irq(ath10k_pci_priv(ar)->pdev->irq, ar);
- ++ struct ath10k *ar = (void *)ptr;
- ++
- ++ ath10k_pci_rx_post(ar);
- + }
- +
- + /*
- +@@ -330,24 +500,7 @@ static int ath10k_pci_diag_read_mem(stru
- + void *data_buf = NULL;
- + int i;
- +
- +- /*
- +- * This code cannot handle reads to non-memory space. Redirect to the
- +- * register read fn but preserve the multi word read capability of
- +- * this fn
- +- */
- +- if (address < DRAM_BASE_ADDRESS) {
- +- if (!IS_ALIGNED(address, 4) ||
- +- !IS_ALIGNED((unsigned long)data, 4))
- +- return -EIO;
- +-
- +- while ((nbytes >= 4) && ((ret = ath10k_pci_diag_read_access(
- +- ar, address, (u32 *)data)) == 0)) {
- +- nbytes -= sizeof(u32);
- +- address += sizeof(u32);
- +- data += sizeof(u32);
- +- }
- +- return ret;
- +- }
- ++ spin_lock_bh(&ar_pci->ce_lock);
- +
- + ce_diag = ar_pci->ce_diag;
- +
- +@@ -375,7 +528,7 @@ static int ath10k_pci_diag_read_mem(stru
- + nbytes = min_t(unsigned int, remaining_bytes,
- + DIAG_TRANSFER_LIMIT);
- +
- +- ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, ce_data);
- ++ ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data);
- + if (ret != 0)
- + goto done;
- +
- +@@ -388,20 +541,18 @@ static int ath10k_pci_diag_read_mem(stru
- + * convert it from Target CPU virtual address space
- + * to CE address space
- + */
- +- ath10k_pci_wake(ar);
- + address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem,
- + address);
- +- ath10k_pci_sleep(ar);
- +
- +- ret = ath10k_ce_send(ce_diag, NULL, (u32)address, nbytes, 0,
- +- 0);
- ++ ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0,
- ++ 0);
- + if (ret)
- + goto done;
- +
- + i = 0;
- +- while (ath10k_ce_completed_send_next(ce_diag, NULL, &buf,
- +- &completed_nbytes,
- +- &id) != 0) {
- ++ while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf,
- ++ &completed_nbytes,
- ++ &id) != 0) {
- + mdelay(1);
- + if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
- + ret = -EBUSY;
- +@@ -414,15 +565,15 @@ static int ath10k_pci_diag_read_mem(stru
- + goto done;
- + }
- +
- +- if (buf != (u32) address) {
- ++ if (buf != (u32)address) {
- + ret = -EIO;
- + goto done;
- + }
- +
- + i = 0;
- +- while (ath10k_ce_completed_recv_next(ce_diag, NULL, &buf,
- +- &completed_nbytes,
- +- &id, &flags) != 0) {
- ++ while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf,
- ++ &completed_nbytes,
- ++ &id, &flags) != 0) {
- + mdelay(1);
- +
- + if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
- +@@ -447,38 +598,60 @@ static int ath10k_pci_diag_read_mem(stru
- + }
- +
- + done:
- +- if (ret == 0) {
- +- /* Copy data from allocated DMA buf to caller's buf */
- +- WARN_ON_ONCE(orig_nbytes & 3);
- +- for (i = 0; i < orig_nbytes / sizeof(__le32); i++) {
- +- ((u32 *)data)[i] =
- +- __le32_to_cpu(((__le32 *)data_buf)[i]);
- +- }
- +- } else
- +- ath10k_warn("failed to read diag value at 0x%x: %d\n",
- ++ if (ret == 0)
- ++ memcpy(data, data_buf, orig_nbytes);
- ++ else
- ++ ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n",
- + address, ret);
- +
- + if (data_buf)
- + dma_free_coherent(ar->dev, orig_nbytes, data_buf,
- + ce_data_base);
- +
- ++ spin_unlock_bh(&ar_pci->ce_lock);
- ++
- + return ret;
- + }
- +
- +-/* Read 4-byte aligned data from Target memory or register */
- +-static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
- +- u32 *data)
- +-{
- +- /* Assume range doesn't cross this boundary */
- +- if (address >= DRAM_BASE_ADDRESS)
- +- return ath10k_pci_diag_read_mem(ar, address, data, sizeof(u32));
- ++static int ath10k_pci_diag_read32(struct ath10k *ar, u32 address, u32 *value)
- ++{
- ++ __le32 val = 0;
- ++ int ret;
- ++
- ++ ret = ath10k_pci_diag_read_mem(ar, address, &val, sizeof(val));
- ++ *value = __le32_to_cpu(val);
- ++
- ++ return ret;
- ++}
- ++
- ++static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest,
- ++ u32 src, u32 len)
- ++{
- ++ u32 host_addr, addr;
- ++ int ret;
- ++
- ++ host_addr = host_interest_item_address(src);
- ++
- ++ ret = ath10k_pci_diag_read32(ar, host_addr, &addr);
- ++ if (ret != 0) {
- ++ ath10k_warn(ar, "failed to get memcpy hi address for firmware address %d: %d\n",
- ++ src, ret);
- ++ return ret;
- ++ }
- ++
- ++ ret = ath10k_pci_diag_read_mem(ar, addr, dest, len);
- ++ if (ret != 0) {
- ++ ath10k_warn(ar, "failed to memcpy firmware memory from %d (%d B): %d\n",
- ++ addr, len, ret);
- ++ return ret;
- ++ }
- +
- +- ath10k_pci_wake(ar);
- +- *data = ath10k_pci_read32(ar, address);
- +- ath10k_pci_sleep(ar);
- + return 0;
- + }
- +
- ++#define ath10k_pci_diag_read_hi(ar, dest, src, len) \
- ++ __ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len)
- ++
- + static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
- + const void *data, int nbytes)
- + {
- +@@ -494,6 +667,8 @@ static int ath10k_pci_diag_write_mem(str
- + dma_addr_t ce_data_base = 0;
- + int i;
- +
- ++ spin_lock_bh(&ar_pci->ce_lock);
- ++
- + ce_diag = ar_pci->ce_diag;
- +
- + /*
- +@@ -513,9 +688,7 @@ static int ath10k_pci_diag_write_mem(str
- + }
- +
- + /* Copy caller's data to allocated DMA buf */
- +- WARN_ON_ONCE(orig_nbytes & 3);
- +- for (i = 0; i < orig_nbytes / sizeof(__le32); i++)
- +- ((__le32 *)data_buf)[i] = __cpu_to_le32(((u32 *)data)[i]);
- ++ memcpy(data_buf, data, orig_nbytes);
- +
- + /*
- + * The address supplied by the caller is in the
- +@@ -527,9 +700,7 @@ static int ath10k_pci_diag_write_mem(str
- + * to
- + * CE address space
- + */
- +- ath10k_pci_wake(ar);
- + address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address);
- +- ath10k_pci_sleep(ar);
- +
- + remaining_bytes = orig_nbytes;
- + ce_data = ce_data_base;
- +@@ -538,7 +709,7 @@ static int ath10k_pci_diag_write_mem(str
- + nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT);
- +
- + /* Set up to receive directly into Target(!) address */
- +- ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, address);
- ++ ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, address);
- + if (ret != 0)
- + goto done;
- +
- +@@ -546,15 +717,15 @@ static int ath10k_pci_diag_write_mem(str
- + * Request CE to send caller-supplied data that
- + * was copied to bounce buffer to Target(!) address.
- + */
- +- ret = ath10k_ce_send(ce_diag, NULL, (u32) ce_data,
- +- nbytes, 0, 0);
- ++ ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)ce_data,
- ++ nbytes, 0, 0);
- + if (ret != 0)
- + goto done;
- +
- + i = 0;
- +- while (ath10k_ce_completed_send_next(ce_diag, NULL, &buf,
- +- &completed_nbytes,
- +- &id) != 0) {
- ++ while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf,
- ++ &completed_nbytes,
- ++ &id) != 0) {
- + mdelay(1);
- +
- + if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
- +@@ -574,9 +745,9 @@ static int ath10k_pci_diag_write_mem(str
- + }
- +
- + i = 0;
- +- while (ath10k_ce_completed_recv_next(ce_diag, NULL, &buf,
- +- &completed_nbytes,
- +- &id, &flags) != 0) {
- ++ while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf,
- ++ &completed_nbytes,
- ++ &id, &flags) != 0) {
- + mdelay(1);
- +
- + if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
- +@@ -607,66 +778,36 @@ done:
- + }
- +
- + if (ret != 0)
- +- ath10k_warn("failed to write diag value at 0x%x: %d\n",
- ++ ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n",
- + address, ret);
- +
- ++ spin_unlock_bh(&ar_pci->ce_lock);
- ++
- + return ret;
- + }
- +
- +-/* Write 4B data to Target memory or register */
- +-static int ath10k_pci_diag_write_access(struct ath10k *ar, u32 address,
- +- u32 data)
- +-{
- +- /* Assume range doesn't cross this boundary */
- +- if (address >= DRAM_BASE_ADDRESS)
- +- return ath10k_pci_diag_write_mem(ar, address, &data,
- +- sizeof(u32));
- ++static int ath10k_pci_diag_write32(struct ath10k *ar, u32 address, u32 value)
- ++{
- ++ __le32 val = __cpu_to_le32(value);
- +
- +- ath10k_pci_wake(ar);
- +- ath10k_pci_write32(ar, address, data);
- +- ath10k_pci_sleep(ar);
- +- return 0;
- ++ return ath10k_pci_diag_write_mem(ar, address, &val, sizeof(val));
- + }
- +
- +-static bool ath10k_pci_target_is_awake(struct ath10k *ar)
- ++static bool ath10k_pci_is_awake(struct ath10k *ar)
- + {
- +- void __iomem *mem = ath10k_pci_priv(ar)->mem;
- +- u32 val;
- +- val = ioread32(mem + PCIE_LOCAL_BASE_ADDRESS +
- +- RTC_STATE_ADDRESS);
- +- return (RTC_STATE_V_GET(val) == RTC_STATE_V_ON);
- ++ u32 val = ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS);
- ++
- ++ return RTC_STATE_V_GET(val) == RTC_STATE_V_ON;
- + }
- +
- +-int ath10k_do_pci_wake(struct ath10k *ar)
- ++static int ath10k_pci_wake_wait(struct ath10k *ar)
- + {
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +- void __iomem *pci_addr = ar_pci->mem;
- + int tot_delay = 0;
- + int curr_delay = 5;
- +
- +- if (atomic_read(&ar_pci->keep_awake_count) == 0) {
- +- /* Force AWAKE */
- +- iowrite32(PCIE_SOC_WAKE_V_MASK,
- +- pci_addr + PCIE_LOCAL_BASE_ADDRESS +
- +- PCIE_SOC_WAKE_ADDRESS);
- +- }
- +- atomic_inc(&ar_pci->keep_awake_count);
- +-
- +- if (ar_pci->verified_awake)
- +- return 0;
- +-
- +- for (;;) {
- +- if (ath10k_pci_target_is_awake(ar)) {
- +- ar_pci->verified_awake = true;
- ++ while (tot_delay < PCIE_WAKE_TIMEOUT) {
- ++ if (ath10k_pci_is_awake(ar))
- + return 0;
- +- }
- +-
- +- if (tot_delay > PCIE_WAKE_TIMEOUT) {
- +- ath10k_warn("target took longer %d us to wake up (awake count %d)\n",
- +- PCIE_WAKE_TIMEOUT,
- +- atomic_read(&ar_pci->keep_awake_count));
- +- return -ETIMEDOUT;
- +- }
- +
- + udelay(curr_delay);
- + tot_delay += curr_delay;
- +@@ -674,20 +815,21 @@ int ath10k_do_pci_wake(struct ath10k *ar
- + if (curr_delay < 50)
- + curr_delay += 5;
- + }
- ++
- ++ return -ETIMEDOUT;
- + }
- +
- +-void ath10k_do_pci_sleep(struct ath10k *ar)
- ++static int ath10k_pci_wake(struct ath10k *ar)
- + {
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +- void __iomem *pci_addr = ar_pci->mem;
- ++ ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
- ++ PCIE_SOC_WAKE_V_MASK);
- ++ return ath10k_pci_wake_wait(ar);
- ++}
- +
- +- if (atomic_dec_and_test(&ar_pci->keep_awake_count)) {
- +- /* Allow sleep */
- +- ar_pci->verified_awake = false;
- +- iowrite32(PCIE_SOC_WAKE_RESET,
- +- pci_addr + PCIE_LOCAL_BASE_ADDRESS +
- +- PCIE_SOC_WAKE_ADDRESS);
- +- }
- ++static void ath10k_pci_sleep(struct ath10k *ar)
- ++{
- ++ ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
- ++ PCIE_SOC_WAKE_RESET);
- + }
- +
- + /* Called by lower (CE) layer when a send to Target completes. */
- +@@ -696,20 +838,24 @@ static void ath10k_pci_ce_send_done(stru
- + struct ath10k *ar = ce_state->ar;
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- + struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
- +- void *transfer_context;
- ++ struct sk_buff_head list;
- ++ struct sk_buff *skb;
- + u32 ce_data;
- + unsigned int nbytes;
- + unsigned int transfer_id;
- +
- +- while (ath10k_ce_completed_send_next(ce_state, &transfer_context,
- +- &ce_data, &nbytes,
- +- &transfer_id) == 0) {
- ++ __skb_queue_head_init(&list);
- ++ while (ath10k_ce_completed_send_next(ce_state, (void **)&skb, &ce_data,
- ++ &nbytes, &transfer_id) == 0) {
- + /* no need to call tx completion for NULL pointers */
- +- if (transfer_context == NULL)
- ++ if (skb == NULL)
- + continue;
- +
- +- cb->tx_completion(ar, transfer_context, transfer_id);
- ++ __skb_queue_tail(&list, skb);
- + }
- ++
- ++ while ((skb = __skb_dequeue(&list)))
- ++ cb->tx_completion(ar, skb);
- + }
- +
- + /* Called by lower (CE) layer when data is received from the Target. */
- +@@ -720,38 +866,43 @@ static void ath10k_pci_ce_recv_data(stru
- + struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id];
- + struct ath10k_hif_cb *cb = &ar_pci->msg_callbacks_current;
- + struct sk_buff *skb;
- ++ struct sk_buff_head list;
- + void *transfer_context;
- + u32 ce_data;
- + unsigned int nbytes, max_nbytes;
- + unsigned int transfer_id;
- + unsigned int flags;
- +- int err;
- +
- ++ __skb_queue_head_init(&list);
- + while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
- + &ce_data, &nbytes, &transfer_id,
- + &flags) == 0) {
- +- err = ath10k_pci_post_rx_pipe(pipe_info, 1);
- +- if (unlikely(err)) {
- +- /* FIXME: retry */
- +- ath10k_warn("failed to replenish CE rx ring %d: %d\n",
- +- pipe_info->pipe_num, err);
- +- }
- +-
- + skb = transfer_context;
- + max_nbytes = skb->len + skb_tailroom(skb);
- +- dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
- ++ dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,
- + max_nbytes, DMA_FROM_DEVICE);
- +
- + if (unlikely(max_nbytes < nbytes)) {
- +- ath10k_warn("rxed more than expected (nbytes %d, max %d)",
- ++ ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)",
- + nbytes, max_nbytes);
- + dev_kfree_skb_any(skb);
- + continue;
- + }
- +
- + skb_put(skb, nbytes);
- +- cb->rx_completion(ar, skb, pipe_info->pipe_num);
- ++ __skb_queue_tail(&list, skb);
- ++ }
- ++
- ++ while ((skb = __skb_dequeue(&list))) {
- ++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n",
- ++ ce_state->id, skb->len);
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ",
- ++ skb->data, skb->len);
- ++
- ++ cb->rx_completion(ar, skb);
- + }
- ++
- ++ ath10k_pci_rx_post_pipe(pipe_info);
- + }
- +
- + static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
- +@@ -761,24 +912,28 @@ static int ath10k_pci_hif_tx_sg(struct a
- + struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id];
- + struct ath10k_ce_pipe *ce_pipe = pci_pipe->ce_hdl;
- + struct ath10k_ce_ring *src_ring = ce_pipe->src_ring;
- +- unsigned int nentries_mask = src_ring->nentries_mask;
- +- unsigned int sw_index = src_ring->sw_index;
- +- unsigned int write_index = src_ring->write_index;
- +- int err, i;
- ++ unsigned int nentries_mask;
- ++ unsigned int sw_index;
- ++ unsigned int write_index;
- ++ int err, i = 0;
- +
- + spin_lock_bh(&ar_pci->ce_lock);
- +
- ++ nentries_mask = src_ring->nentries_mask;
- ++ sw_index = src_ring->sw_index;
- ++ write_index = src_ring->write_index;
- ++
- + if (unlikely(CE_RING_DELTA(nentries_mask,
- + write_index, sw_index - 1) < n_items)) {
- + err = -ENOBUFS;
- +- goto unlock;
- ++ goto err;
- + }
- +
- + for (i = 0; i < n_items - 1; i++) {
- +- ath10k_dbg(ATH10K_DBG_PCI,
- ++ ath10k_dbg(ar, ATH10K_DBG_PCI,
- + "pci tx item %d paddr 0x%08x len %d n_items %d\n",
- + i, items[i].paddr, items[i].len, n_items);
- +- ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ",
- + items[i].vaddr, items[i].len);
- +
- + err = ath10k_ce_send_nolock(ce_pipe,
- +@@ -788,15 +943,15 @@ static int ath10k_pci_hif_tx_sg(struct a
- + items[i].transfer_id,
- + CE_SEND_FLAG_GATHER);
- + if (err)
- +- goto unlock;
- ++ goto err;
- + }
- +
- + /* `i` is equal to `n_items -1` after for() */
- +
- +- ath10k_dbg(ATH10K_DBG_PCI,
- ++ ath10k_dbg(ar, ATH10K_DBG_PCI,
- + "pci tx item %d paddr 0x%08x len %d n_items %d\n",
- + i, items[i].paddr, items[i].len, n_items);
- +- ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ",
- + items[i].vaddr, items[i].len);
- +
- + err = ath10k_ce_send_nolock(ce_pipe,
- +@@ -806,64 +961,89 @@ static int ath10k_pci_hif_tx_sg(struct a
- + items[i].transfer_id,
- + 0);
- + if (err)
- +- goto unlock;
- ++ goto err;
- ++
- ++ spin_unlock_bh(&ar_pci->ce_lock);
- ++ return 0;
- ++
- ++err:
- ++ for (; i > 0; i--)
- ++ __ath10k_ce_send_revert(ce_pipe);
- +
- +- err = 0;
- +-unlock:
- + spin_unlock_bh(&ar_pci->ce_lock);
- + return err;
- + }
- +
- ++static int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
- ++ size_t buf_len)
- ++{
- ++ return ath10k_pci_diag_read_mem(ar, address, buf, buf_len);
- ++}
- ++
- + static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
- + {
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +
- +- ath10k_dbg(ATH10K_DBG_PCI, "pci hif get free queue number\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get free queue number\n");
- +
- + return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);
- + }
- +
- +-static void ath10k_pci_hif_dump_area(struct ath10k *ar)
- ++static void ath10k_pci_dump_registers(struct ath10k *ar,
- ++ struct ath10k_fw_crash_data *crash_data)
- + {
- +- u32 reg_dump_area = 0;
- +- u32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {};
- +- u32 host_addr;
- +- int ret;
- +- u32 i;
- +-
- +- ath10k_err("firmware crashed!\n");
- +- ath10k_err("hardware name %s version 0x%x\n",
- +- ar->hw_params.name, ar->target_version);
- +- ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version);
- +-
- +- host_addr = host_interest_item_address(HI_ITEM(hi_failure_state));
- +- ret = ath10k_pci_diag_read_mem(ar, host_addr,
- +- ®_dump_area, sizeof(u32));
- +- if (ret) {
- +- ath10k_err("failed to read FW dump area address: %d\n", ret);
- +- return;
- +- }
- ++ __le32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {};
- ++ int i, ret;
- +
- +- ath10k_err("target register Dump Location: 0x%08X\n", reg_dump_area);
- ++ lockdep_assert_held(&ar->data_lock);
- +
- +- ret = ath10k_pci_diag_read_mem(ar, reg_dump_area,
- +- ®_dump_values[0],
- +- REG_DUMP_COUNT_QCA988X * sizeof(u32));
- +- if (ret != 0) {
- +- ath10k_err("failed to read FW dump area: %d\n", ret);
- ++ ret = ath10k_pci_diag_read_hi(ar, ®_dump_values[0],
- ++ hi_failure_state,
- ++ REG_DUMP_COUNT_QCA988X * sizeof(__le32));
- ++ if (ret) {
- ++ ath10k_err(ar, "failed to read firmware dump area: %d\n", ret);
- + return;
- + }
- +
- + BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4);
- +
- +- ath10k_err("target Register Dump\n");
- ++ ath10k_err(ar, "firmware register dump:\n");
- + for (i = 0; i < REG_DUMP_COUNT_QCA988X; i += 4)
- +- ath10k_err("[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n",
- ++ ath10k_err(ar, "[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n",
- + i,
- +- reg_dump_values[i],
- +- reg_dump_values[i + 1],
- +- reg_dump_values[i + 2],
- +- reg_dump_values[i + 3]);
- ++ __le32_to_cpu(reg_dump_values[i]),
- ++ __le32_to_cpu(reg_dump_values[i + 1]),
- ++ __le32_to_cpu(reg_dump_values[i + 2]),
- ++ __le32_to_cpu(reg_dump_values[i + 3]));
- ++
- ++ if (!crash_data)
- ++ return;
- ++
- ++ for (i = 0; i < REG_DUMP_COUNT_QCA988X; i++)
- ++ crash_data->registers[i] = reg_dump_values[i];
- ++}
- ++
- ++static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
- ++{
- ++ struct ath10k_fw_crash_data *crash_data;
- ++ char uuid[50];
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++
- ++ ar->stats.fw_crash_counter++;
- ++
- ++ crash_data = ath10k_debug_get_new_fw_crash_data(ar);
- ++
- ++ if (crash_data)
- ++ scnprintf(uuid, sizeof(uuid), "%pUl", &crash_data->uuid);
- ++ else
- ++ scnprintf(uuid, sizeof(uuid), "n/a");
- ++
- ++ ath10k_err(ar, "firmware crashed! (uuid %s)\n", uuid);
- ++ ath10k_print_driver_info(ar);
- ++ ath10k_pci_dump_registers(ar, crash_data);
- ++
- ++ spin_unlock_bh(&ar->data_lock);
- +
- + queue_work(ar->workqueue, &ar->restart_work);
- + }
- +@@ -871,7 +1051,7 @@ static void ath10k_pci_hif_dump_area(str
- + static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
- + int force)
- + {
- +- ath10k_dbg(ATH10K_DBG_PCI, "pci hif send complete check\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n");
- +
- + if (!force) {
- + int resources;
- +@@ -899,43 +1079,12 @@ static void ath10k_pci_hif_set_callbacks
- + {
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +
- +- ath10k_dbg(ATH10K_DBG_PCI, "pci hif set callbacks\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif set callbacks\n");
- +
- + memcpy(&ar_pci->msg_callbacks_current, callbacks,
- + sizeof(ar_pci->msg_callbacks_current));
- + }
- +
- +-static int ath10k_pci_setup_ce_irq(struct ath10k *ar)
- +-{
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +- const struct ce_attr *attr;
- +- struct ath10k_pci_pipe *pipe_info;
- +- int pipe_num, disable_interrupts;
- +-
- +- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
- +- pipe_info = &ar_pci->pipe_info[pipe_num];
- +-
- +- /* Handle Diagnostic CE specially */
- +- if (pipe_info->ce_hdl == ar_pci->ce_diag)
- +- continue;
- +-
- +- attr = &host_ce_config_wlan[pipe_num];
- +-
- +- if (attr->src_nentries) {
- +- disable_interrupts = attr->flags & CE_ATTR_DIS_INTR;
- +- ath10k_ce_send_cb_register(pipe_info->ce_hdl,
- +- ath10k_pci_ce_send_done,
- +- disable_interrupts);
- +- }
- +-
- +- if (attr->dest_nentries)
- +- ath10k_ce_recv_cb_register(pipe_info->ce_hdl,
- +- ath10k_pci_ce_recv_data);
- +- }
- +-
- +- return 0;
- +-}
- +-
- + static void ath10k_pci_kill_tasklet(struct ath10k *ar)
- + {
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +@@ -943,82 +1092,72 @@ static void ath10k_pci_kill_tasklet(stru
- +
- + tasklet_kill(&ar_pci->intr_tq);
- + tasklet_kill(&ar_pci->msi_fw_err);
- +- tasklet_kill(&ar_pci->early_irq_tasklet);
- +
- + for (i = 0; i < CE_COUNT; i++)
- + tasklet_kill(&ar_pci->pipe_info[i].intr);
- ++
- ++ del_timer_sync(&ar_pci->rx_post_retry);
- + }
- +
- +-/* TODO - temporary mapping while we have too few CE's */
- + static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar,
- + u16 service_id, u8 *ul_pipe,
- + u8 *dl_pipe, int *ul_is_polled,
- + int *dl_is_polled)
- + {
- +- int ret = 0;
- ++ const struct service_to_pipe *entry;
- ++ bool ul_set = false, dl_set = false;
- ++ int i;
- +
- +- ath10k_dbg(ATH10K_DBG_PCI, "pci hif map service\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n");
- +
- + /* polling for received messages not supported */
- + *dl_is_polled = 0;
- +
- +- switch (service_id) {
- +- case ATH10K_HTC_SVC_ID_HTT_DATA_MSG:
- +- /*
- +- * Host->target HTT gets its own pipe, so it can be polled
- +- * while other pipes are interrupt driven.
- +- */
- +- *ul_pipe = 4;
- +- /*
- +- * Use the same target->host pipe for HTC ctrl, HTC raw
- +- * streams, and HTT.
- +- */
- +- *dl_pipe = 1;
- +- break;
- ++ for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
- ++ entry = &target_service_to_ce_map_wlan[i];
- +
- +- case ATH10K_HTC_SVC_ID_RSVD_CTRL:
- +- case ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS:
- +- /*
- +- * Note: HTC_RAW_STREAMS_SVC is currently unused, and
- +- * HTC_CTRL_RSVD_SVC could share the same pipe as the
- +- * WMI services. So, if another CE is needed, change
- +- * this to *ul_pipe = 3, which frees up CE 0.
- +- */
- +- /* *ul_pipe = 3; */
- +- *ul_pipe = 0;
- +- *dl_pipe = 1;
- +- break;
- ++ if (__le32_to_cpu(entry->service_id) != service_id)
- ++ continue;
- +
- +- case ATH10K_HTC_SVC_ID_WMI_DATA_BK:
- +- case ATH10K_HTC_SVC_ID_WMI_DATA_BE:
- +- case ATH10K_HTC_SVC_ID_WMI_DATA_VI:
- +- case ATH10K_HTC_SVC_ID_WMI_DATA_VO:
- +-
- +- case ATH10K_HTC_SVC_ID_WMI_CONTROL:
- +- *ul_pipe = 3;
- +- *dl_pipe = 2;
- +- break;
- ++ switch (__le32_to_cpu(entry->pipedir)) {
- ++ case PIPEDIR_NONE:
- ++ break;
- ++ case PIPEDIR_IN:
- ++ WARN_ON(dl_set);
- ++ *dl_pipe = __le32_to_cpu(entry->pipenum);
- ++ dl_set = true;
- ++ break;
- ++ case PIPEDIR_OUT:
- ++ WARN_ON(ul_set);
- ++ *ul_pipe = __le32_to_cpu(entry->pipenum);
- ++ ul_set = true;
- ++ break;
- ++ case PIPEDIR_INOUT:
- ++ WARN_ON(dl_set);
- ++ WARN_ON(ul_set);
- ++ *dl_pipe = __le32_to_cpu(entry->pipenum);
- ++ *ul_pipe = __le32_to_cpu(entry->pipenum);
- ++ dl_set = true;
- ++ ul_set = true;
- ++ break;
- ++ }
- ++ }
- +
- +- /* pipe 5 unused */
- +- /* pipe 6 reserved */
- +- /* pipe 7 reserved */
- ++ if (WARN_ON(!ul_set || !dl_set))
- ++ return -ENOENT;
- +
- +- default:
- +- ret = -1;
- +- break;
- +- }
- + *ul_is_polled =
- + (host_ce_config_wlan[*ul_pipe].flags & CE_ATTR_DIS_INTR) != 0;
- +
- +- return ret;
- ++ return 0;
- + }
- +
- + static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
- +- u8 *ul_pipe, u8 *dl_pipe)
- ++ u8 *ul_pipe, u8 *dl_pipe)
- + {
- + int ul_is_polled, dl_is_polled;
- +
- +- ath10k_dbg(ATH10K_DBG_PCI, "pci hif get default pipe\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n");
- +
- + (void)ath10k_pci_hif_map_service_to_pipe(ar,
- + ATH10K_HTC_SVC_ID_RSVD_CTRL,
- +@@ -1028,209 +1167,127 @@ static void ath10k_pci_hif_get_default_p
- + &dl_is_polled);
- + }
- +
- +-static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
- +- int num)
- ++static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
- + {
- +- struct ath10k *ar = pipe_info->hif_ce_state;
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +- struct ath10k_ce_pipe *ce_state = pipe_info->ce_hdl;
- +- struct sk_buff *skb;
- +- dma_addr_t ce_data;
- +- int i, ret = 0;
- ++ u32 val;
- +
- +- if (pipe_info->buf_sz == 0)
- +- return 0;
- ++ val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS);
- ++ val &= ~CORE_CTRL_PCIE_REG_31_MASK;
- +
- +- for (i = 0; i < num; i++) {
- +- skb = dev_alloc_skb(pipe_info->buf_sz);
- +- if (!skb) {
- +- ath10k_warn("failed to allocate skbuff for pipe %d\n",
- +- num);
- +- ret = -ENOMEM;
- +- goto err;
- +- }
- ++ ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val);
- ++}
- +
- +- WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
- ++static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
- ++{
- ++ u32 val;
- +
- +- ce_data = dma_map_single(ar->dev, skb->data,
- +- skb->len + skb_tailroom(skb),
- +- DMA_FROM_DEVICE);
- ++ val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS);
- ++ val |= CORE_CTRL_PCIE_REG_31_MASK;
- +
- +- if (unlikely(dma_mapping_error(ar->dev, ce_data))) {
- +- ath10k_warn("failed to DMA map sk_buff\n");
- +- dev_kfree_skb_any(skb);
- +- ret = -EIO;
- +- goto err;
- +- }
- ++ ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val);
- ++}
- +
- +- ATH10K_SKB_CB(skb)->paddr = ce_data;
- ++static void ath10k_pci_irq_disable(struct ath10k *ar)
- ++{
- ++ ath10k_ce_disable_interrupts(ar);
- ++ ath10k_pci_disable_and_clear_legacy_irq(ar);
- ++ ath10k_pci_irq_msi_fw_mask(ar);
- ++}
- +
- +- pci_dma_sync_single_for_device(ar_pci->pdev, ce_data,
- +- pipe_info->buf_sz,
- +- PCI_DMA_FROMDEVICE);
- +-
- +- ret = ath10k_ce_recv_buf_enqueue(ce_state, (void *)skb,
- +- ce_data);
- +- if (ret) {
- +- ath10k_warn("failed to enqueue to pipe %d: %d\n",
- +- num, ret);
- +- goto err;
- +- }
- +- }
- +-
- +- return ret;
- +-
- +-err:
- +- ath10k_pci_rx_pipe_cleanup(pipe_info);
- +- return ret;
- +-}
- +-
- +-static int ath10k_pci_post_rx(struct ath10k *ar)
- ++static void ath10k_pci_irq_sync(struct ath10k *ar)
- + {
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +- struct ath10k_pci_pipe *pipe_info;
- +- const struct ce_attr *attr;
- +- int pipe_num, ret = 0;
- +-
- +- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
- +- pipe_info = &ar_pci->pipe_info[pipe_num];
- +- attr = &host_ce_config_wlan[pipe_num];
- +-
- +- if (attr->dest_nentries == 0)
- +- continue;
- +-
- +- ret = ath10k_pci_post_rx_pipe(pipe_info,
- +- attr->dest_nentries - 1);
- +- if (ret) {
- +- ath10k_warn("failed to post RX buffer for pipe %d: %d\n",
- +- pipe_num, ret);
- ++ int i;
- +
- +- for (; pipe_num >= 0; pipe_num--) {
- +- pipe_info = &ar_pci->pipe_info[pipe_num];
- +- ath10k_pci_rx_pipe_cleanup(pipe_info);
- +- }
- +- return ret;
- +- }
- +- }
- ++ for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
- ++ synchronize_irq(ar_pci->pdev->irq + i);
- ++}
- +
- +- return 0;
- ++static void ath10k_pci_irq_enable(struct ath10k *ar)
- ++{
- ++ ath10k_ce_enable_interrupts(ar);
- ++ ath10k_pci_enable_legacy_irq(ar);
- ++ ath10k_pci_irq_msi_fw_unmask(ar);
- + }
- +
- + static int ath10k_pci_hif_start(struct ath10k *ar)
- + {
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +- int ret, ret_early;
- +-
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n");
- +-
- +- ath10k_pci_free_early_irq(ar);
- +- ath10k_pci_kill_tasklet(ar);
- +-
- +- ret = ath10k_pci_request_irq(ar);
- +- if (ret) {
- +- ath10k_warn("failed to post RX buffers for all pipes: %d\n",
- +- ret);
- +- goto err_early_irq;
- +- }
- +-
- +- ret = ath10k_pci_setup_ce_irq(ar);
- +- if (ret) {
- +- ath10k_warn("failed to setup CE interrupts: %d\n", ret);
- +- goto err_stop;
- +- }
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
- +
- +- /* Post buffers once to start things off. */
- +- ret = ath10k_pci_post_rx(ar);
- +- if (ret) {
- +- ath10k_warn("failed to post RX buffers for all pipes: %d\n",
- +- ret);
- +- goto err_stop;
- +- }
- ++ ath10k_pci_irq_enable(ar);
- ++ ath10k_pci_rx_post(ar);
- +
- +- ar_pci->started = 1;
- + return 0;
- +-
- +-err_stop:
- +- ath10k_ce_disable_interrupts(ar);
- +- ath10k_pci_free_irq(ar);
- +- ath10k_pci_kill_tasklet(ar);
- +-err_early_irq:
- +- /* Though there should be no interrupts (device was reset)
- +- * power_down() expects the early IRQ to be installed as per the
- +- * driver lifecycle. */
- +- ret_early = ath10k_pci_request_early_irq(ar);
- +- if (ret_early)
- +- ath10k_warn("failed to re-enable early irq: %d\n", ret_early);
- +-
- +- return ret;
- + }
- +
- +-static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
- ++static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
- + {
- + struct ath10k *ar;
- +- struct ath10k_pci *ar_pci;
- +- struct ath10k_ce_pipe *ce_hdl;
- +- u32 buf_sz;
- +- struct sk_buff *netbuf;
- +- u32 ce_data;
- ++ struct ath10k_ce_pipe *ce_pipe;
- ++ struct ath10k_ce_ring *ce_ring;
- ++ struct sk_buff *skb;
- ++ int i;
- +
- +- buf_sz = pipe_info->buf_sz;
- ++ ar = pci_pipe->hif_ce_state;
- ++ ce_pipe = pci_pipe->ce_hdl;
- ++ ce_ring = ce_pipe->dest_ring;
- +
- +- /* Unused Copy Engine */
- +- if (buf_sz == 0)
- ++ if (!ce_ring)
- + return;
- +
- +- ar = pipe_info->hif_ce_state;
- +- ar_pci = ath10k_pci_priv(ar);
- +-
- +- if (!ar_pci->started)
- ++ if (!pci_pipe->buf_sz)
- + return;
- +
- +- ce_hdl = pipe_info->ce_hdl;
- ++ for (i = 0; i < ce_ring->nentries; i++) {
- ++ skb = ce_ring->per_transfer_context[i];
- ++ if (!skb)
- ++ continue;
- ++
- ++ ce_ring->per_transfer_context[i] = NULL;
- +
- +- while (ath10k_ce_revoke_recv_next(ce_hdl, (void **)&netbuf,
- +- &ce_data) == 0) {
- +- dma_unmap_single(ar->dev, ATH10K_SKB_CB(netbuf)->paddr,
- +- netbuf->len + skb_tailroom(netbuf),
- ++ dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,
- ++ skb->len + skb_tailroom(skb),
- + DMA_FROM_DEVICE);
- +- dev_kfree_skb_any(netbuf);
- ++ dev_kfree_skb_any(skb);
- + }
- + }
- +
- +-static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
- ++static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
- + {
- + struct ath10k *ar;
- + struct ath10k_pci *ar_pci;
- +- struct ath10k_ce_pipe *ce_hdl;
- +- struct sk_buff *netbuf;
- +- u32 ce_data;
- +- unsigned int nbytes;
- ++ struct ath10k_ce_pipe *ce_pipe;
- ++ struct ath10k_ce_ring *ce_ring;
- ++ struct ce_desc *ce_desc;
- ++ struct sk_buff *skb;
- + unsigned int id;
- +- u32 buf_sz;
- ++ int i;
- +
- +- buf_sz = pipe_info->buf_sz;
- ++ ar = pci_pipe->hif_ce_state;
- ++ ar_pci = ath10k_pci_priv(ar);
- ++ ce_pipe = pci_pipe->ce_hdl;
- ++ ce_ring = ce_pipe->src_ring;
- +
- +- /* Unused Copy Engine */
- +- if (buf_sz == 0)
- ++ if (!ce_ring)
- + return;
- +
- +- ar = pipe_info->hif_ce_state;
- +- ar_pci = ath10k_pci_priv(ar);
- +-
- +- if (!ar_pci->started)
- ++ if (!pci_pipe->buf_sz)
- + return;
- +
- +- ce_hdl = pipe_info->ce_hdl;
- ++ ce_desc = ce_ring->shadow_base;
- ++ if (WARN_ON(!ce_desc))
- ++ return;
- +
- +- while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf,
- +- &ce_data, &nbytes, &id) == 0) {
- +- /* no need to call tx completion for NULL pointers */
- +- if (!netbuf)
- ++ for (i = 0; i < ce_ring->nentries; i++) {
- ++ skb = ce_ring->per_transfer_context[i];
- ++ if (!skb)
- + continue;
- +
- +- ar_pci->msg_callbacks_current.tx_completion(ar,
- +- netbuf,
- +- id);
- ++ ce_ring->per_transfer_context[i] = NULL;
- ++ id = MS(__le16_to_cpu(ce_desc[i].flags),
- ++ CE_DESC_FLAGS_META_DATA);
- ++
- ++ ar_pci->msg_callbacks_current.tx_completion(ar, skb);
- + }
- + }
- +
- +@@ -1264,38 +1321,32 @@ static void ath10k_pci_ce_deinit(struct
- + ath10k_ce_deinit_pipe(ar, i);
- + }
- +
- +-static void ath10k_pci_hif_stop(struct ath10k *ar)
- ++static void ath10k_pci_flush(struct ath10k *ar)
- + {
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +- int ret;
- +-
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n");
- +-
- +- ret = ath10k_ce_disable_interrupts(ar);
- +- if (ret)
- +- ath10k_warn("failed to disable CE interrupts: %d\n", ret);
- +-
- +- ath10k_pci_free_irq(ar);
- + ath10k_pci_kill_tasklet(ar);
- +-
- +- ret = ath10k_pci_request_early_irq(ar);
- +- if (ret)
- +- ath10k_warn("failed to re-enable early irq: %d\n", ret);
- +-
- +- /* At this point, asynchronous threads are stopped, the target should
- +- * not DMA nor interrupt. We process the leftovers and then free
- +- * everything else up. */
- +-
- + ath10k_pci_buffer_cleanup(ar);
- ++}
- +
- +- /* Make the sure the device won't access any structures on the host by
- +- * resetting it. The device was fed with PCI CE ringbuffer
- +- * configuration during init. If ringbuffers are freed and the device
- +- * were to access them this could lead to memory corruption on the
- +- * host. */
- ++static void ath10k_pci_hif_stop(struct ath10k *ar)
- ++{
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
- ++
- ++ /* Most likely the device has HTT Rx ring configured. The only way to
- ++ * prevent the device from accessing (and possible corrupting) host
- ++ * memory is to reset the chip now.
- ++ *
- ++ * There's also no known way of masking MSI interrupts on the device.
- ++ * For ranged MSI the CE-related interrupts can be masked. However
- ++ * regardless how many MSI interrupts are assigned the first one
- ++ * is always used for firmware indications (crashes) and cannot be
- ++ * masked. To prevent the device from asserting the interrupt reset it
- ++ * before proceeding with cleanup.
- ++ */
- + ath10k_pci_warm_reset(ar);
- +
- +- ar_pci->started = 0;
- ++ ath10k_pci_irq_disable(ar);
- ++ ath10k_pci_irq_sync(ar);
- ++ ath10k_pci_flush(ar);
- + }
- +
- + static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
- +@@ -1346,11 +1397,9 @@ static int ath10k_pci_hif_exchange_bmi_m
- + xfer.wait_for_resp = true;
- + xfer.resp_len = 0;
- +
- +- ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr);
- ++ ath10k_ce_rx_post_buf(ce_rx, &xfer, resp_paddr);
- + }
- +
- +- init_completion(&xfer.done);
- +-
- + ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0);
- + if (ret)
- + goto err_resp;
- +@@ -1401,14 +1450,12 @@ static void ath10k_pci_bmi_send_done(str
- + &nbytes, &transfer_id))
- + return;
- +
- +- if (xfer->wait_for_resp)
- +- return;
- +-
- +- complete(&xfer->done);
- ++ xfer->tx_done = true;
- + }
- +
- + static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
- + {
- ++ struct ath10k *ar = ce_state->ar;
- + struct bmi_xfer *xfer;
- + u32 ce_data;
- + unsigned int nbytes;
- +@@ -1419,13 +1466,16 @@ static void ath10k_pci_bmi_recv_data(str
- + &nbytes, &transfer_id, &flags))
- + return;
- +
- ++ if (WARN_ON_ONCE(!xfer))
- ++ return;
- ++
- + if (!xfer->wait_for_resp) {
- +- ath10k_warn("unexpected: BMI data received; ignoring\n");
- ++ ath10k_warn(ar, "unexpected: BMI data received; ignoring\n");
- + return;
- + }
- +
- + xfer->resp_len = nbytes;
- +- complete(&xfer->done);
- ++ xfer->rx_done = true;
- + }
- +
- + static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
- +@@ -1438,7 +1488,7 @@ static int ath10k_pci_bmi_wait(struct at
- + ath10k_pci_bmi_send_done(tx_pipe);
- + ath10k_pci_bmi_recv_data(rx_pipe);
- +
- +- if (completion_done(&xfer->done))
- ++ if (xfer->tx_done && (xfer->rx_done == xfer->wait_for_resp))
- + return 0;
- +
- + schedule();
- +@@ -1448,131 +1498,48 @@ static int ath10k_pci_bmi_wait(struct at
- + }
- +
- + /*
- +- * Map from service/endpoint to Copy Engine.
- +- * This table is derived from the CE_PCI TABLE, above.
- +- * It is passed to the Target at startup for use by firmware.
- +- */
- +-static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
- +- {
- +- ATH10K_HTC_SVC_ID_WMI_DATA_VO,
- +- PIPEDIR_OUT, /* out = UL = host -> target */
- +- 3,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_WMI_DATA_VO,
- +- PIPEDIR_IN, /* in = DL = target -> host */
- +- 2,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_WMI_DATA_BK,
- +- PIPEDIR_OUT, /* out = UL = host -> target */
- +- 3,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_WMI_DATA_BK,
- +- PIPEDIR_IN, /* in = DL = target -> host */
- +- 2,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_WMI_DATA_BE,
- +- PIPEDIR_OUT, /* out = UL = host -> target */
- +- 3,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_WMI_DATA_BE,
- +- PIPEDIR_IN, /* in = DL = target -> host */
- +- 2,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_WMI_DATA_VI,
- +- PIPEDIR_OUT, /* out = UL = host -> target */
- +- 3,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_WMI_DATA_VI,
- +- PIPEDIR_IN, /* in = DL = target -> host */
- +- 2,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_WMI_CONTROL,
- +- PIPEDIR_OUT, /* out = UL = host -> target */
- +- 3,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_WMI_CONTROL,
- +- PIPEDIR_IN, /* in = DL = target -> host */
- +- 2,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_RSVD_CTRL,
- +- PIPEDIR_OUT, /* out = UL = host -> target */
- +- 0, /* could be moved to 3 (share with WMI) */
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_RSVD_CTRL,
- +- PIPEDIR_IN, /* in = DL = target -> host */
- +- 1,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */
- +- PIPEDIR_OUT, /* out = UL = host -> target */
- +- 0,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS, /* not currently used */
- +- PIPEDIR_IN, /* in = DL = target -> host */
- +- 1,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_HTT_DATA_MSG,
- +- PIPEDIR_OUT, /* out = UL = host -> target */
- +- 4,
- +- },
- +- {
- +- ATH10K_HTC_SVC_ID_HTT_DATA_MSG,
- +- PIPEDIR_IN, /* in = DL = target -> host */
- +- 1,
- +- },
- +-
- +- /* (Additions here) */
- +-
- +- { /* Must be last */
- +- 0,
- +- 0,
- +- 0,
- +- },
- +-};
- +-
- +-/*
- + * Send an interrupt to the device to wake up the Target CPU
- + * so it has an opportunity to notice any changed state.
- + */
- + static int ath10k_pci_wake_target_cpu(struct ath10k *ar)
- + {
- +- int ret;
- +- u32 core_ctrl;
- ++ u32 addr, val;
- +
- +- ret = ath10k_pci_diag_read_access(ar, SOC_CORE_BASE_ADDRESS |
- +- CORE_CTRL_ADDRESS,
- +- &core_ctrl);
- +- if (ret) {
- +- ath10k_warn("failed to read core_ctrl: %d\n", ret);
- +- return ret;
- +- }
- ++ addr = SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS;
- ++ val = ath10k_pci_read32(ar, addr);
- ++ val |= CORE_CTRL_CPU_INTR_MASK;
- ++ ath10k_pci_write32(ar, addr, val);
- +
- +- /* A_INUM_FIRMWARE interrupt to Target CPU */
- +- core_ctrl |= CORE_CTRL_CPU_INTR_MASK;
- ++ return 0;
- ++}
- +
- +- ret = ath10k_pci_diag_write_access(ar, SOC_CORE_BASE_ADDRESS |
- +- CORE_CTRL_ADDRESS,
- +- core_ctrl);
- +- if (ret) {
- +- ath10k_warn("failed to set target CPU interrupt mask: %d\n",
- +- ret);
- +- return ret;
- ++static int ath10k_pci_get_num_banks(struct ath10k *ar)
- ++{
- ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++
- ++ switch (ar_pci->pdev->device) {
- ++ case QCA988X_2_0_DEVICE_ID:
- ++ return 1;
- ++ case QCA6174_2_1_DEVICE_ID:
- ++ switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) {
- ++ case QCA6174_HW_1_0_CHIP_ID_REV:
- ++ case QCA6174_HW_1_1_CHIP_ID_REV:
- ++ return 3;
- ++ case QCA6174_HW_1_3_CHIP_ID_REV:
- ++ return 2;
- ++ case QCA6174_HW_2_1_CHIP_ID_REV:
- ++ case QCA6174_HW_2_2_CHIP_ID_REV:
- ++ return 6;
- ++ case QCA6174_HW_3_0_CHIP_ID_REV:
- ++ case QCA6174_HW_3_1_CHIP_ID_REV:
- ++ case QCA6174_HW_3_2_CHIP_ID_REV:
- ++ return 9;
- ++ }
- ++ break;
- + }
- +
- +- return 0;
- ++ ath10k_warn(ar, "unknown number of banks, assuming 1\n");
- ++ return 1;
- + }
- +
- + static int ath10k_pci_init_config(struct ath10k *ar)
- +@@ -1593,144 +1560,162 @@ static int ath10k_pci_init_config(struct
- + host_interest_item_address(HI_ITEM(hi_interconnect_state));
- +
- + /* Supply Target-side CE configuration */
- +- ret = ath10k_pci_diag_read_access(ar, interconnect_targ_addr,
- +- &pcie_state_targ_addr);
- ++ ret = ath10k_pci_diag_read32(ar, interconnect_targ_addr,
- ++ &pcie_state_targ_addr);
- + if (ret != 0) {
- +- ath10k_err("Failed to get pcie state addr: %d\n", ret);
- ++ ath10k_err(ar, "Failed to get pcie state addr: %d\n", ret);
- + return ret;
- + }
- +
- + if (pcie_state_targ_addr == 0) {
- + ret = -EIO;
- +- ath10k_err("Invalid pcie state addr\n");
- ++ ath10k_err(ar, "Invalid pcie state addr\n");
- + return ret;
- + }
- +
- +- ret = ath10k_pci_diag_read_access(ar, pcie_state_targ_addr +
- ++ ret = ath10k_pci_diag_read32(ar, (pcie_state_targ_addr +
- + offsetof(struct pcie_state,
- +- pipe_cfg_addr),
- +- &pipe_cfg_targ_addr);
- ++ pipe_cfg_addr)),
- ++ &pipe_cfg_targ_addr);
- + if (ret != 0) {
- +- ath10k_err("Failed to get pipe cfg addr: %d\n", ret);
- ++ ath10k_err(ar, "Failed to get pipe cfg addr: %d\n", ret);
- + return ret;
- + }
- +
- + if (pipe_cfg_targ_addr == 0) {
- + ret = -EIO;
- +- ath10k_err("Invalid pipe cfg addr\n");
- ++ ath10k_err(ar, "Invalid pipe cfg addr\n");
- + return ret;
- + }
- +
- + ret = ath10k_pci_diag_write_mem(ar, pipe_cfg_targ_addr,
- +- target_ce_config_wlan,
- +- sizeof(target_ce_config_wlan));
- ++ target_ce_config_wlan,
- ++ sizeof(target_ce_config_wlan));
- +
- + if (ret != 0) {
- +- ath10k_err("Failed to write pipe cfg: %d\n", ret);
- ++ ath10k_err(ar, "Failed to write pipe cfg: %d\n", ret);
- + return ret;
- + }
- +
- +- ret = ath10k_pci_diag_read_access(ar, pcie_state_targ_addr +
- ++ ret = ath10k_pci_diag_read32(ar, (pcie_state_targ_addr +
- + offsetof(struct pcie_state,
- +- svc_to_pipe_map),
- +- &svc_to_pipe_map);
- ++ svc_to_pipe_map)),
- ++ &svc_to_pipe_map);
- + if (ret != 0) {
- +- ath10k_err("Failed to get svc/pipe map: %d\n", ret);
- ++ ath10k_err(ar, "Failed to get svc/pipe map: %d\n", ret);
- + return ret;
- + }
- +
- + if (svc_to_pipe_map == 0) {
- + ret = -EIO;
- +- ath10k_err("Invalid svc_to_pipe map\n");
- ++ ath10k_err(ar, "Invalid svc_to_pipe map\n");
- + return ret;
- + }
- +
- + ret = ath10k_pci_diag_write_mem(ar, svc_to_pipe_map,
- +- target_service_to_ce_map_wlan,
- +- sizeof(target_service_to_ce_map_wlan));
- ++ target_service_to_ce_map_wlan,
- ++ sizeof(target_service_to_ce_map_wlan));
- + if (ret != 0) {
- +- ath10k_err("Failed to write svc/pipe map: %d\n", ret);
- ++ ath10k_err(ar, "Failed to write svc/pipe map: %d\n", ret);
- + return ret;
- + }
- +
- +- ret = ath10k_pci_diag_read_access(ar, pcie_state_targ_addr +
- ++ ret = ath10k_pci_diag_read32(ar, (pcie_state_targ_addr +
- + offsetof(struct pcie_state,
- +- config_flags),
- +- &pcie_config_flags);
- ++ config_flags)),
- ++ &pcie_config_flags);
- + if (ret != 0) {
- +- ath10k_err("Failed to get pcie config_flags: %d\n", ret);
- ++ ath10k_err(ar, "Failed to get pcie config_flags: %d\n", ret);
- + return ret;
- + }
- +
- + pcie_config_flags &= ~PCIE_CONFIG_FLAG_ENABLE_L1;
- +
- +- ret = ath10k_pci_diag_write_mem(ar, pcie_state_targ_addr +
- +- offsetof(struct pcie_state, config_flags),
- +- &pcie_config_flags,
- +- sizeof(pcie_config_flags));
- ++ ret = ath10k_pci_diag_write32(ar, (pcie_state_targ_addr +
- ++ offsetof(struct pcie_state,
- ++ config_flags)),
- ++ pcie_config_flags);
- + if (ret != 0) {
- +- ath10k_err("Failed to write pcie config_flags: %d\n", ret);
- ++ ath10k_err(ar, "Failed to write pcie config_flags: %d\n", ret);
- + return ret;
- + }
- +
- + /* configure early allocation */
- + ealloc_targ_addr = host_interest_item_address(HI_ITEM(hi_early_alloc));
- +
- +- ret = ath10k_pci_diag_read_access(ar, ealloc_targ_addr, &ealloc_value);
- ++ ret = ath10k_pci_diag_read32(ar, ealloc_targ_addr, &ealloc_value);
- + if (ret != 0) {
- +- ath10k_err("Faile to get early alloc val: %d\n", ret);
- ++ ath10k_err(ar, "Faile to get early alloc val: %d\n", ret);
- + return ret;
- + }
- +
- + /* first bank is switched to IRAM */
- + ealloc_value |= ((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) &
- + HI_EARLY_ALLOC_MAGIC_MASK);
- +- ealloc_value |= ((1 << HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) &
- ++ ealloc_value |= ((ath10k_pci_get_num_banks(ar) <<
- ++ HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) &
- + HI_EARLY_ALLOC_IRAM_BANKS_MASK);
- +
- +- ret = ath10k_pci_diag_write_access(ar, ealloc_targ_addr, ealloc_value);
- ++ ret = ath10k_pci_diag_write32(ar, ealloc_targ_addr, ealloc_value);
- + if (ret != 0) {
- +- ath10k_err("Failed to set early alloc val: %d\n", ret);
- ++ ath10k_err(ar, "Failed to set early alloc val: %d\n", ret);
- + return ret;
- + }
- +
- + /* Tell Target to proceed with initialization */
- + flag2_targ_addr = host_interest_item_address(HI_ITEM(hi_option_flag2));
- +
- +- ret = ath10k_pci_diag_read_access(ar, flag2_targ_addr, &flag2_value);
- ++ ret = ath10k_pci_diag_read32(ar, flag2_targ_addr, &flag2_value);
- + if (ret != 0) {
- +- ath10k_err("Failed to get option val: %d\n", ret);
- ++ ath10k_err(ar, "Failed to get option val: %d\n", ret);
- + return ret;
- + }
- +
- + flag2_value |= HI_OPTION_EARLY_CFG_DONE;
- +
- +- ret = ath10k_pci_diag_write_access(ar, flag2_targ_addr, flag2_value);
- ++ ret = ath10k_pci_diag_write32(ar, flag2_targ_addr, flag2_value);
- + if (ret != 0) {
- +- ath10k_err("Failed to set option val: %d\n", ret);
- ++ ath10k_err(ar, "Failed to set option val: %d\n", ret);
- + return ret;
- + }
- +
- + return 0;
- + }
- +
- +-static int ath10k_pci_alloc_ce(struct ath10k *ar)
- ++static int ath10k_pci_alloc_pipes(struct ath10k *ar)
- + {
- ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++ struct ath10k_pci_pipe *pipe;
- + int i, ret;
- +
- + for (i = 0; i < CE_COUNT; i++) {
- +- ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
- ++ pipe = &ar_pci->pipe_info[i];
- ++ pipe->ce_hdl = &ar_pci->ce_states[i];
- ++ pipe->pipe_num = i;
- ++ pipe->hif_ce_state = ar;
- ++
- ++ ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i],
- ++ ath10k_pci_ce_send_done,
- ++ ath10k_pci_ce_recv_data);
- + if (ret) {
- +- ath10k_err("failed to allocate copy engine pipe %d: %d\n",
- ++ ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",
- + i, ret);
- + return ret;
- + }
- ++
- ++ /* Last CE is Diagnostic Window */
- ++ if (i == CE_COUNT - 1) {
- ++ ar_pci->ce_diag = pipe->ce_hdl;
- ++ continue;
- ++ }
- ++
- ++ pipe->buf_sz = (size_t)(host_ce_config_wlan[i].src_sz_max);
- + }
- +
- + return 0;
- + }
- +
- +-static void ath10k_pci_free_ce(struct ath10k *ar)
- ++static void ath10k_pci_free_pipes(struct ath10k *ar)
- + {
- + int i;
- +
- +@@ -1738,305 +1723,319 @@ static void ath10k_pci_free_ce(struct at
- + ath10k_ce_free_pipe(ar, i);
- + }
- +
- +-static int ath10k_pci_ce_init(struct ath10k *ar)
- ++static int ath10k_pci_init_pipes(struct ath10k *ar)
- + {
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +- struct ath10k_pci_pipe *pipe_info;
- +- const struct ce_attr *attr;
- +- int pipe_num, ret;
- +-
- +- for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
- +- pipe_info = &ar_pci->pipe_info[pipe_num];
- +- pipe_info->ce_hdl = &ar_pci->ce_states[pipe_num];
- +- pipe_info->pipe_num = pipe_num;
- +- pipe_info->hif_ce_state = ar;
- +- attr = &host_ce_config_wlan[pipe_num];
- ++ int i, ret;
- +
- +- ret = ath10k_ce_init_pipe(ar, pipe_num, attr);
- ++ for (i = 0; i < CE_COUNT; i++) {
- ++ ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]);
- + if (ret) {
- +- ath10k_err("failed to initialize copy engine pipe %d: %d\n",
- +- pipe_num, ret);
- ++ ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",
- ++ i, ret);
- + return ret;
- + }
- +-
- +- if (pipe_num == CE_COUNT - 1) {
- +- /*
- +- * Reserve the ultimate CE for
- +- * diagnostic Window support
- +- */
- +- ar_pci->ce_diag = pipe_info->ce_hdl;
- +- continue;
- +- }
- +-
- +- pipe_info->buf_sz = (size_t) (attr->src_sz_max);
- + }
- +
- + return 0;
- + }
- +
- +-static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
- ++static bool ath10k_pci_has_fw_crashed(struct ath10k *ar)
- + {
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +- u32 fw_indicator;
- +-
- +- ath10k_pci_wake(ar);
- +-
- +- fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
- +-
- +- if (fw_indicator & FW_IND_EVENT_PENDING) {
- +- /* ACK: clear Target-side pending event */
- +- ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
- +- fw_indicator & ~FW_IND_EVENT_PENDING);
- +-
- +- if (ar_pci->started) {
- +- ath10k_pci_hif_dump_area(ar);
- +- } else {
- +- /*
- +- * Probable Target failure before we're prepared
- +- * to handle it. Generally unexpected.
- +- */
- +- ath10k_warn("early firmware event indicated\n");
- +- }
- +- }
- +-
- +- ath10k_pci_sleep(ar);
- ++ return ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS) &
- ++ FW_IND_EVENT_PENDING;
- + }
- +
- +-static int ath10k_pci_warm_reset(struct ath10k *ar)
- ++static void ath10k_pci_fw_crashed_clear(struct ath10k *ar)
- + {
- +- int ret = 0;
- + u32 val;
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n");
- ++ val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
- ++ val &= ~FW_IND_EVENT_PENDING;
- ++ ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val);
- ++}
- +
- +- ret = ath10k_do_pci_wake(ar);
- +- if (ret) {
- +- ath10k_err("failed to wake up target: %d\n", ret);
- +- return ret;
- +- }
- ++/* this function effectively clears target memory controller assert line */
- ++static void ath10k_pci_warm_reset_si0(struct ath10k *ar)
- ++{
- ++ u32 val;
- +
- +- /* debug */
- +- val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
- +- PCIE_INTR_CAUSE_ADDRESS);
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
- ++ val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
- ++ ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS,
- ++ val | SOC_RESET_CONTROL_SI0_RST_MASK);
- ++ val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
- +
- +- val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
- +- CPU_INTR_ADDRESS);
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
- +- val);
- ++ msleep(10);
- +
- +- /* disable pending irqs */
- +- ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
- +- PCIE_INTR_ENABLE_ADDRESS, 0);
- ++ val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
- ++ ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS,
- ++ val & ~SOC_RESET_CONTROL_SI0_RST_MASK);
- ++ val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
- +
- +- ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
- +- PCIE_INTR_CLR_ADDRESS, ~0);
- ++ msleep(10);
- ++}
- +
- +- msleep(100);
- ++static void ath10k_pci_warm_reset_cpu(struct ath10k *ar)
- ++{
- ++ u32 val;
- +
- +- /* clear fw indicator */
- + ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0);
- +
- +- /* clear target LF timer interrupts */
- + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
- +- SOC_LF_TIMER_CONTROL0_ADDRESS);
- +- ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS +
- +- SOC_LF_TIMER_CONTROL0_ADDRESS,
- +- val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK);
- ++ SOC_RESET_CONTROL_ADDRESS);
- ++ ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
- ++ val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK);
- ++}
- ++
- ++static void ath10k_pci_warm_reset_ce(struct ath10k *ar)
- ++{
- ++ u32 val;
- +
- +- /* reset CE */
- + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
- + SOC_RESET_CONTROL_ADDRESS);
- ++
- + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
- + val | SOC_RESET_CONTROL_CE_RST_MASK);
- +- val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
- +- SOC_RESET_CONTROL_ADDRESS);
- + msleep(10);
- +-
- +- /* unreset CE */
- + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
- + val & ~SOC_RESET_CONTROL_CE_RST_MASK);
- +- val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
- +- SOC_RESET_CONTROL_ADDRESS);
- +- msleep(10);
- ++}
- +
- +- /* debug */
- +- val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
- +- PCIE_INTR_CAUSE_ADDRESS);
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
- +-
- +- val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
- +- CPU_INTR_ADDRESS);
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
- +- val);
- ++static void ath10k_pci_warm_reset_clear_lf(struct ath10k *ar)
- ++{
- ++ u32 val;
- +
- +- /* CPU warm reset */
- + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
- +- SOC_RESET_CONTROL_ADDRESS);
- +- ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS,
- +- val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK);
- ++ SOC_LF_TIMER_CONTROL0_ADDRESS);
- ++ ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS +
- ++ SOC_LF_TIMER_CONTROL0_ADDRESS,
- ++ val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK);
- ++}
- +
- +- val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
- +- SOC_RESET_CONTROL_ADDRESS);
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", val);
- ++static int ath10k_pci_warm_reset(struct ath10k *ar)
- ++{
- ++ int ret;
- +
- +- msleep(100);
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n");
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n");
- ++ spin_lock_bh(&ar->data_lock);
- ++ ar->stats.fw_warm_reset_counter++;
- ++ spin_unlock_bh(&ar->data_lock);
- ++
- ++ ath10k_pci_irq_disable(ar);
- ++
- ++ /* Make sure the target CPU is not doing anything dangerous, e.g. if it
- ++ * were to access copy engine while host performs copy engine reset
- ++ * then it is possible for the device to confuse pci-e controller to
- ++ * the point of bringing host system to a complete stop (i.e. hang).
- ++ */
- ++ ath10k_pci_warm_reset_si0(ar);
- ++ ath10k_pci_warm_reset_cpu(ar);
- ++ ath10k_pci_init_pipes(ar);
- ++ ath10k_pci_wait_for_target_init(ar);
- ++
- ++ ath10k_pci_warm_reset_clear_lf(ar);
- ++ ath10k_pci_warm_reset_ce(ar);
- ++ ath10k_pci_warm_reset_cpu(ar);
- ++ ath10k_pci_init_pipes(ar);
- +
- +- ath10k_do_pci_sleep(ar);
- +- return ret;
- ++ ret = ath10k_pci_wait_for_target_init(ar);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to wait for target init: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset complete\n");
- ++
- ++ return 0;
- + }
- +
- +-static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
- ++static int ath10k_pci_qca988x_chip_reset(struct ath10k *ar)
- + {
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +- const char *irq_mode;
- +- int ret;
- ++ int i, ret;
- ++ u32 val;
- +
- +- /*
- +- * Bring the target up cleanly.
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot 988x chip reset\n");
- ++
- ++ /* Some hardware revisions (e.g. CUS223v2) has issues with cold reset.
- ++ * It is thus preferred to use warm reset which is safer but may not be
- ++ * able to recover the device from all possible fail scenarios.
- + *
- +- * The target may be in an undefined state with an AUX-powered Target
- +- * and a Host in WoW mode. If the Host crashes, loses power, or is
- +- * restarted (without unloading the driver) then the Target is left
- +- * (aux) powered and running. On a subsequent driver load, the Target
- +- * is in an unexpected state. We try to catch that here in order to
- +- * reset the Target and retry the probe.
- ++ * Warm reset doesn't always work on first try so attempt it a few
- ++ * times before giving up.
- + */
- +- if (cold_reset)
- +- ret = ath10k_pci_cold_reset(ar);
- +- else
- ++ for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) {
- + ret = ath10k_pci_warm_reset(ar);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to warm reset attempt %d of %d: %d\n",
- ++ i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS,
- ++ ret);
- ++ continue;
- ++ }
- ++
- ++ /* FIXME: Sometimes copy engine doesn't recover after warm
- ++ * reset. In most cases this needs cold reset. In some of these
- ++ * cases the device is in such a state that a cold reset may
- ++ * lock up the host.
- ++ *
- ++ * Reading any host interest register via copy engine is
- ++ * sufficient to verify if device is capable of booting
- ++ * firmware blob.
- ++ */
- ++ ret = ath10k_pci_init_pipes(ar);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to init copy engine: %d\n",
- ++ ret);
- ++ continue;
- ++ }
- ++
- ++ ret = ath10k_pci_diag_read32(ar, QCA988X_HOST_INTEREST_ADDRESS,
- ++ &val);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to poke copy engine: %d\n",
- ++ ret);
- ++ continue;
- ++ }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset complete (warm)\n");
- ++ return 0;
- ++ }
- +
- ++ if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY) {
- ++ ath10k_warn(ar, "refusing cold reset as requested\n");
- ++ return -EPERM;
- ++ }
- ++
- ++ ret = ath10k_pci_cold_reset(ar);
- + if (ret) {
- +- ath10k_err("failed to reset target: %d\n", ret);
- +- goto err;
- ++ ath10k_warn(ar, "failed to cold reset: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ret = ath10k_pci_wait_for_target_init(ar);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to wait for target after cold reset: %d\n",
- ++ ret);
- ++ return ret;
- + }
- +
- +- if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- +- /* Force AWAKE forever */
- +- ath10k_do_pci_wake(ar);
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca988x chip reset complete (cold)\n");
- +
- +- ret = ath10k_pci_ce_init(ar);
- ++ return 0;
- ++}
- ++
- ++static int ath10k_pci_qca6174_chip_reset(struct ath10k *ar)
- ++{
- ++ int ret;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca6174 chip reset\n");
- ++
- ++ /* FIXME: QCA6174 requires cold + warm reset to work. */
- ++
- ++ ret = ath10k_pci_cold_reset(ar);
- + if (ret) {
- +- ath10k_err("failed to initialize CE: %d\n", ret);
- +- goto err_ps;
- ++ ath10k_warn(ar, "failed to cold reset: %d\n", ret);
- ++ return ret;
- + }
- +
- +- ret = ath10k_ce_disable_interrupts(ar);
- ++ ret = ath10k_pci_wait_for_target_init(ar);
- + if (ret) {
- +- ath10k_err("failed to disable CE interrupts: %d\n", ret);
- +- goto err_ce;
- ++ ath10k_warn(ar, "failed to wait for target after cold reset: %d\n",
- ++ ret);
- ++ return ret;
- + }
- +
- +- ret = ath10k_pci_init_irq(ar);
- ++ ret = ath10k_pci_warm_reset(ar);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to warm reset: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca6174 chip reset complete (cold)\n");
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_pci_chip_reset(struct ath10k *ar)
- ++{
- ++ if (QCA_REV_988X(ar))
- ++ return ath10k_pci_qca988x_chip_reset(ar);
- ++ else if (QCA_REV_6174(ar))
- ++ return ath10k_pci_qca6174_chip_reset(ar);
- ++ else
- ++ return -ENOTSUPP;
- ++}
- ++
- ++static int ath10k_pci_hif_power_up(struct ath10k *ar)
- ++{
- ++ int ret;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n");
- ++
- ++ ret = ath10k_pci_wake(ar);
- ++ if (ret) {
- ++ ath10k_err(ar, "failed to wake up target: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ /*
- ++ * Bring the target up cleanly.
- ++ *
- ++ * The target may be in an undefined state with an AUX-powered Target
- ++ * and a Host in WoW mode. If the Host crashes, loses power, or is
- ++ * restarted (without unloading the driver) then the Target is left
- ++ * (aux) powered and running. On a subsequent driver load, the Target
- ++ * is in an unexpected state. We try to catch that here in order to
- ++ * reset the Target and retry the probe.
- ++ */
- ++ ret = ath10k_pci_chip_reset(ar);
- + if (ret) {
- +- ath10k_err("failed to init irqs: %d\n", ret);
- +- goto err_ce;
- +- }
- ++ if (ath10k_pci_has_fw_crashed(ar)) {
- ++ ath10k_warn(ar, "firmware crashed during chip reset\n");
- ++ ath10k_pci_fw_crashed_clear(ar);
- ++ ath10k_pci_fw_crashed_dump(ar);
- ++ }
- +
- +- ret = ath10k_pci_request_early_irq(ar);
- +- if (ret) {
- +- ath10k_err("failed to request early irq: %d\n", ret);
- +- goto err_deinit_irq;
- ++ ath10k_err(ar, "failed to reset chip: %d\n", ret);
- ++ goto err_sleep;
- + }
- +
- +- ret = ath10k_pci_wait_for_target_init(ar);
- ++ ret = ath10k_pci_init_pipes(ar);
- + if (ret) {
- +- ath10k_err("failed to wait for target to init: %d\n", ret);
- +- goto err_free_early_irq;
- ++ ath10k_err(ar, "failed to initialize CE: %d\n", ret);
- ++ goto err_sleep;
- + }
- +
- + ret = ath10k_pci_init_config(ar);
- + if (ret) {
- +- ath10k_err("failed to setup init config: %d\n", ret);
- +- goto err_free_early_irq;
- ++ ath10k_err(ar, "failed to setup init config: %d\n", ret);
- ++ goto err_ce;
- + }
- +
- + ret = ath10k_pci_wake_target_cpu(ar);
- + if (ret) {
- +- ath10k_err("could not wake up target CPU: %d\n", ret);
- +- goto err_free_early_irq;
- ++ ath10k_err(ar, "could not wake up target CPU: %d\n", ret);
- ++ goto err_ce;
- + }
- +
- +- if (ar_pci->num_msi_intrs > 1)
- +- irq_mode = "MSI-X";
- +- else if (ar_pci->num_msi_intrs == 1)
- +- irq_mode = "MSI";
- +- else
- +- irq_mode = "legacy";
- +-
- +- if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
- +- ath10k_info("pci irq %s irq_mode %d reset_mode %d\n",
- +- irq_mode, ath10k_pci_irq_mode,
- +- ath10k_pci_reset_mode);
- +-
- + return 0;
- +
- +-err_free_early_irq:
- +- ath10k_pci_free_early_irq(ar);
- +-err_deinit_irq:
- +- ath10k_pci_deinit_irq(ar);
- + err_ce:
- + ath10k_pci_ce_deinit(ar);
- +- ath10k_pci_warm_reset(ar);
- +-err_ps:
- +- if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- +- ath10k_do_pci_sleep(ar);
- +-err:
- +- return ret;
- +-}
- +-
- +-static int ath10k_pci_hif_power_up(struct ath10k *ar)
- +-{
- +- int ret;
- +-
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power up\n");
- +-
- +- /*
- +- * Hardware CUS232 version 2 has some issues with cold reset and the
- +- * preferred (and safer) way to perform a device reset is through a
- +- * warm reset.
- +- *
- +- * Warm reset doesn't always work though (notably after a firmware
- +- * crash) so fall back to cold reset if necessary.
- +- */
- +- ret = __ath10k_pci_hif_power_up(ar, false);
- +- if (ret) {
- +- ath10k_warn("failed to power up target using warm reset: %d\n",
- +- ret);
- +-
- +- if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY)
- +- return ret;
- +
- +- ath10k_warn("trying cold reset\n");
- +-
- +- ret = __ath10k_pci_hif_power_up(ar, true);
- +- if (ret) {
- +- ath10k_err("failed to power up target using cold reset too (%d)\n",
- +- ret);
- +- return ret;
- +- }
- +- }
- +-
- +- return 0;
- ++err_sleep:
- ++ ath10k_pci_sleep(ar);
- ++ return ret;
- + }
- +
- + static void ath10k_pci_hif_power_down(struct ath10k *ar)
- + {
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n");
- +-
- +- ath10k_pci_free_early_irq(ar);
- +- ath10k_pci_kill_tasklet(ar);
- +- ath10k_pci_deinit_irq(ar);
- +- ath10k_pci_ce_deinit(ar);
- +- ath10k_pci_warm_reset(ar);
- ++ /* Currently hif_power_up performs effectively a reset and hif_stop
- ++ * resets the chip as well so there's no point in resetting here.
- ++ */
- +
- +- if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- +- ath10k_do_pci_sleep(ar);
- ++ ath10k_pci_sleep(ar);
- + }
- +
- + #ifdef CONFIG_PM
- +@@ -2090,6 +2089,8 @@ static int ath10k_pci_hif_resume(struct
- +
- + static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
- + .tx_sg = ath10k_pci_hif_tx_sg,
- ++ .diag_read = ath10k_pci_hif_diag_read,
- ++ .diag_write = ath10k_pci_diag_write_mem,
- + .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg,
- + .start = ath10k_pci_hif_start,
- + .stop = ath10k_pci_hif_stop,
- +@@ -2100,6 +2101,8 @@ static const struct ath10k_hif_ops ath10
- + .get_free_queue_number = ath10k_pci_hif_get_free_queue_number,
- + .power_up = ath10k_pci_hif_power_up,
- + .power_down = ath10k_pci_hif_power_down,
- ++ .read32 = ath10k_pci_read32,
- ++ .write32 = ath10k_pci_write32,
- + #ifdef CONFIG_PM
- + .suspend = ath10k_pci_hif_suspend,
- + .resume = ath10k_pci_hif_resume,
- +@@ -2118,7 +2121,14 @@ static void ath10k_msi_err_tasklet(unsig
- + {
- + struct ath10k *ar = (struct ath10k *)data;
- +
- +- ath10k_pci_fw_interrupt_handler(ar);
- ++ if (!ath10k_pci_has_fw_crashed(ar)) {
- ++ ath10k_warn(ar, "received unsolicited fw crash interrupt\n");
- ++ return;
- ++ }
- ++
- ++ ath10k_pci_irq_disable(ar);
- ++ ath10k_pci_fw_crashed_clear(ar);
- ++ ath10k_pci_fw_crashed_dump(ar);
- + }
- +
- + /*
- +@@ -2132,7 +2142,8 @@ static irqreturn_t ath10k_pci_per_engine
- + int ce_id = irq - ar_pci->pdev->irq - MSI_ASSIGN_CE_INITIAL;
- +
- + if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_pci->pipe_info)) {
- +- ath10k_warn("unexpected/invalid irq %d ce_id %d\n", irq, ce_id);
- ++ ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq,
- ++ ce_id);
- + return IRQ_HANDLED;
- + }
- +
- +@@ -2179,39 +2190,18 @@ static irqreturn_t ath10k_pci_interrupt_
- + return IRQ_HANDLED;
- + }
- +
- +-static void ath10k_pci_early_irq_tasklet(unsigned long data)
- ++static void ath10k_pci_tasklet(unsigned long data)
- + {
- + struct ath10k *ar = (struct ath10k *)data;
- +- u32 fw_ind;
- +- int ret;
- ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +
- +- ret = ath10k_pci_wake(ar);
- +- if (ret) {
- +- ath10k_warn("failed to wake target in early irq tasklet: %d\n",
- +- ret);
- ++ if (ath10k_pci_has_fw_crashed(ar)) {
- ++ ath10k_pci_irq_disable(ar);
- ++ ath10k_pci_fw_crashed_clear(ar);
- ++ ath10k_pci_fw_crashed_dump(ar);
- + return;
- + }
- +
- +- fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
- +- if (fw_ind & FW_IND_EVENT_PENDING) {
- +- ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
- +- fw_ind & ~FW_IND_EVENT_PENDING);
- +-
- +- /* Some structures are unavailable during early boot or at
- +- * driver teardown so just print that the device has crashed. */
- +- ath10k_warn("device crashed - no diagnostics available\n");
- +- }
- +-
- +- ath10k_pci_sleep(ar);
- +- ath10k_pci_enable_legacy_irq(ar);
- +-}
- +-
- +-static void ath10k_pci_tasklet(unsigned long data)
- +-{
- +- struct ath10k *ar = (struct ath10k *)data;
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +-
- +- ath10k_pci_fw_interrupt_handler(ar); /* FIXME: Handle FW error */
- + ath10k_ce_per_engine_service_any(ar);
- +
- + /* Re-enable legacy irq that was disabled in the irq handler */
- +@@ -2228,7 +2218,7 @@ static int ath10k_pci_request_irq_msix(s
- + ath10k_pci_msi_fw_handler,
- + IRQF_SHARED, "ath10k_pci", ar);
- + if (ret) {
- +- ath10k_warn("failed to request MSI-X fw irq %d: %d\n",
- ++ ath10k_warn(ar, "failed to request MSI-X fw irq %d: %d\n",
- + ar_pci->pdev->irq + MSI_ASSIGN_FW, ret);
- + return ret;
- + }
- +@@ -2238,7 +2228,7 @@ static int ath10k_pci_request_irq_msix(s
- + ath10k_pci_per_engine_handler,
- + IRQF_SHARED, "ath10k_pci", ar);
- + if (ret) {
- +- ath10k_warn("failed to request MSI-X ce irq %d: %d\n",
- ++ ath10k_warn(ar, "failed to request MSI-X ce irq %d: %d\n",
- + ar_pci->pdev->irq + i, ret);
- +
- + for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--)
- +@@ -2261,7 +2251,7 @@ static int ath10k_pci_request_irq_msi(st
- + ath10k_pci_interrupt_handler,
- + IRQF_SHARED, "ath10k_pci", ar);
- + if (ret) {
- +- ath10k_warn("failed to request MSI irq %d: %d\n",
- ++ ath10k_warn(ar, "failed to request MSI irq %d: %d\n",
- + ar_pci->pdev->irq, ret);
- + return ret;
- + }
- +@@ -2278,7 +2268,7 @@ static int ath10k_pci_request_irq_legacy
- + ath10k_pci_interrupt_handler,
- + IRQF_SHARED, "ath10k_pci", ar);
- + if (ret) {
- +- ath10k_warn("failed to request legacy irq %d: %d\n",
- ++ ath10k_warn(ar, "failed to request legacy irq %d: %d\n",
- + ar_pci->pdev->irq, ret);
- + return ret;
- + }
- +@@ -2299,7 +2289,7 @@ static int ath10k_pci_request_irq(struct
- + return ath10k_pci_request_irq_msix(ar);
- + }
- +
- +- ath10k_warn("unknown irq configuration upon request\n");
- ++ ath10k_warn(ar, "unknown irq configuration upon request\n");
- + return -EINVAL;
- + }
- +
- +@@ -2322,8 +2312,6 @@ static void ath10k_pci_init_irq_tasklets
- + tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
- + tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
- + (unsigned long)ar);
- +- tasklet_init(&ar_pci->early_irq_tasklet, ath10k_pci_early_irq_tasklet,
- +- (unsigned long)ar);
- +
- + for (i = 0; i < CE_COUNT; i++) {
- + ar_pci->pipe_info[i].ar_pci = ar_pci;
- +@@ -2335,21 +2323,19 @@ static void ath10k_pci_init_irq_tasklets
- + static int ath10k_pci_init_irq(struct ath10k *ar)
- + {
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +- bool msix_supported = test_bit(ATH10K_PCI_FEATURE_MSI_X,
- +- ar_pci->features);
- + int ret;
- +
- + ath10k_pci_init_irq_tasklets(ar);
- +
- +- if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO &&
- +- !test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
- +- ath10k_info("limiting irq mode to: %d\n", ath10k_pci_irq_mode);
- ++ if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO)
- ++ ath10k_info(ar, "limiting irq mode to: %d\n",
- ++ ath10k_pci_irq_mode);
- +
- + /* Try MSI-X */
- +- if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) {
- ++ if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO) {
- + ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
- + ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
- +- ar_pci->num_msi_intrs);
- ++ ar_pci->num_msi_intrs);
- + if (ret > 0)
- + return 0;
- +
- +@@ -2376,34 +2362,16 @@ static int ath10k_pci_init_irq(struct at
- + * synchronization checking. */
- + ar_pci->num_msi_intrs = 0;
- +
- +- ret = ath10k_pci_wake(ar);
- +- if (ret) {
- +- ath10k_warn("failed to wake target: %d\n", ret);
- +- return ret;
- +- }
- +-
- + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
- + PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
- +- ath10k_pci_sleep(ar);
- +
- + return 0;
- + }
- +
- +-static int ath10k_pci_deinit_irq_legacy(struct ath10k *ar)
- ++static void ath10k_pci_deinit_irq_legacy(struct ath10k *ar)
- + {
- +- int ret;
- +-
- +- ret = ath10k_pci_wake(ar);
- +- if (ret) {
- +- ath10k_warn("failed to wake target: %d\n", ret);
- +- return ret;
- +- }
- +-
- + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
- + 0);
- +- ath10k_pci_sleep(ar);
- +-
- +- return 0;
- + }
- +
- + static int ath10k_pci_deinit_irq(struct ath10k *ar)
- +@@ -2412,7 +2380,8 @@ static int ath10k_pci_deinit_irq(struct
- +
- + switch (ar_pci->num_msi_intrs) {
- + case 0:
- +- return ath10k_pci_deinit_irq_legacy(ar);
- ++ ath10k_pci_deinit_irq_legacy(ar);
- ++ return 0;
- + case 1:
- + /* fall-through */
- + case MSI_NUM_REQUEST:
- +@@ -2422,7 +2391,7 @@ static int ath10k_pci_deinit_irq(struct
- + pci_disable_msi(ar_pci->pdev);
- + }
- +
- +- ath10k_warn("unknown irq configuration upon deinit\n");
- ++ ath10k_warn(ar, "unknown irq configuration upon deinit\n");
- + return -EINVAL;
- + }
- +
- +@@ -2430,23 +2399,17 @@ static int ath10k_pci_wait_for_target_in
- + {
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- + unsigned long timeout;
- +- int ret;
- + u32 val;
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot waiting target to initialise\n");
- +-
- +- ret = ath10k_pci_wake(ar);
- +- if (ret) {
- +- ath10k_err("failed to wake up target for init: %d\n", ret);
- +- return ret;
- +- }
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot waiting target to initialise\n");
- +
- + timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT);
- +
- + do {
- + val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot target indicator %x\n", val);
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target indicator %x\n",
- ++ val);
- +
- + /* target should never return this */
- + if (val == 0xffffffff)
- +@@ -2461,52 +2424,46 @@ static int ath10k_pci_wait_for_target_in
- +
- + if (ar_pci->num_msi_intrs == 0)
- + /* Fix potential race by repeating CORE_BASE writes */
- +- ath10k_pci_soc_write32(ar, PCIE_INTR_ENABLE_ADDRESS,
- +- PCIE_INTR_FIRMWARE_MASK |
- +- PCIE_INTR_CE_MASK_ALL);
- ++ ath10k_pci_enable_legacy_irq(ar);
- +
- + mdelay(10);
- + } while (time_before(jiffies, timeout));
- +
- ++ ath10k_pci_disable_and_clear_legacy_irq(ar);
- ++ ath10k_pci_irq_msi_fw_mask(ar);
- ++
- + if (val == 0xffffffff) {
- +- ath10k_err("failed to read device register, device is gone\n");
- +- ret = -EIO;
- +- goto out;
- ++ ath10k_err(ar, "failed to read device register, device is gone\n");
- ++ return -EIO;
- + }
- +
- + if (val & FW_IND_EVENT_PENDING) {
- +- ath10k_warn("device has crashed during init\n");
- +- ret = -ECOMM;
- +- goto out;
- ++ ath10k_warn(ar, "device has crashed during init\n");
- ++ return -ECOMM;
- + }
- +
- + if (!(val & FW_IND_INITIALIZED)) {
- +- ath10k_err("failed to receive initialized event from target: %08x\n",
- ++ ath10k_err(ar, "failed to receive initialized event from target: %08x\n",
- + val);
- +- ret = -ETIMEDOUT;
- +- goto out;
- ++ return -ETIMEDOUT;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot target initialised\n");
- +-
- +-out:
- +- ath10k_pci_sleep(ar);
- +- return ret;
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target initialised\n");
- ++ return 0;
- + }
- +
- + static int ath10k_pci_cold_reset(struct ath10k *ar)
- + {
- +- int i, ret;
- ++ int i;
- + u32 val;
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n");
- +
- +- ret = ath10k_do_pci_wake(ar);
- +- if (ret) {
- +- ath10k_err("failed to wake up target: %d\n",
- +- ret);
- +- return ret;
- +- }
- ++ spin_lock_bh(&ar->data_lock);
- ++
- ++ ar->stats.fw_cold_reset_counter++;
- ++
- ++ spin_unlock_bh(&ar->data_lock);
- +
- + /* Put Target, including PCIe, into RESET. */
- + val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS);
- +@@ -2531,181 +2488,227 @@ static int ath10k_pci_cold_reset(struct
- + msleep(1);
- + }
- +
- +- ath10k_do_pci_sleep(ar);
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n");
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_pci_claim(struct ath10k *ar)
- ++{
- ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++ struct pci_dev *pdev = ar_pci->pdev;
- ++ u32 lcr_val;
- ++ int ret;
- ++
- ++ pci_set_drvdata(pdev, ar);
- ++
- ++ ret = pci_enable_device(pdev);
- ++ if (ret) {
- ++ ath10k_err(ar, "failed to enable pci device: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ret = pci_request_region(pdev, BAR_NUM, "ath");
- ++ if (ret) {
- ++ ath10k_err(ar, "failed to request region BAR%d: %d\n", BAR_NUM,
- ++ ret);
- ++ goto err_device;
- ++ }
- ++
- ++ /* Target expects 32 bit DMA. Enforce it. */
- ++ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- ++ if (ret) {
- ++ ath10k_err(ar, "failed to set dma mask to 32-bit: %d\n", ret);
- ++ goto err_region;
- ++ }
- ++
- ++ ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
- ++ if (ret) {
- ++ ath10k_err(ar, "failed to set consistent dma mask to 32-bit: %d\n",
- ++ ret);
- ++ goto err_region;
- ++ }
- ++
- ++ pci_set_master(pdev);
- ++
- ++ /* Workaround: Disable ASPM */
- ++ pci_read_config_dword(pdev, 0x80, &lcr_val);
- ++ pci_write_config_dword(pdev, 0x80, (lcr_val & 0xffffff00));
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n");
- ++ /* Arrange for access to Target SoC registers. */
- ++ ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0);
- ++ if (!ar_pci->mem) {
- ++ ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM);
- ++ ret = -EIO;
- ++ goto err_master;
- ++ }
- +
- ++ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem);
- + return 0;
- ++
- ++err_master:
- ++ pci_clear_master(pdev);
- ++
- ++err_region:
- ++ pci_release_region(pdev, BAR_NUM);
- ++
- ++err_device:
- ++ pci_disable_device(pdev);
- ++
- ++ return ret;
- + }
- +
- +-static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
- ++static void ath10k_pci_release(struct ath10k *ar)
- + {
- ++ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- ++ struct pci_dev *pdev = ar_pci->pdev;
- ++
- ++ pci_iounmap(pdev, ar_pci->mem);
- ++ pci_release_region(pdev, BAR_NUM);
- ++ pci_clear_master(pdev);
- ++ pci_disable_device(pdev);
- ++}
- ++
- ++static bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id)
- ++{
- ++ const struct ath10k_pci_supp_chip *supp_chip;
- + int i;
- ++ u32 rev_id = MS(chip_id, SOC_CHIP_ID_REV);
- +
- +- for (i = 0; i < ATH10K_PCI_FEATURE_COUNT; i++) {
- +- if (!test_bit(i, ar_pci->features))
- +- continue;
- ++ for (i = 0; i < ARRAY_SIZE(ath10k_pci_supp_chips); i++) {
- ++ supp_chip = &ath10k_pci_supp_chips[i];
- +
- +- switch (i) {
- +- case ATH10K_PCI_FEATURE_MSI_X:
- +- ath10k_dbg(ATH10K_DBG_BOOT, "device supports MSI-X\n");
- +- break;
- +- case ATH10K_PCI_FEATURE_SOC_POWER_SAVE:
- +- ath10k_dbg(ATH10K_DBG_BOOT, "QCA98XX SoC power save enabled\n");
- +- break;
- +- }
- ++ if (supp_chip->dev_id == dev_id &&
- ++ supp_chip->rev_id == rev_id)
- ++ return true;
- + }
- ++
- ++ return false;
- + }
- +
- + static int ath10k_pci_probe(struct pci_dev *pdev,
- + const struct pci_device_id *pci_dev)
- + {
- +- void __iomem *mem;
- + int ret = 0;
- + struct ath10k *ar;
- + struct ath10k_pci *ar_pci;
- +- u32 lcr_val, chip_id;
- +-
- +- ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n");
- +-
- +- ar_pci = kzalloc(sizeof(*ar_pci), GFP_KERNEL);
- +- if (ar_pci == NULL)
- +- return -ENOMEM;
- +-
- +- ar_pci->pdev = pdev;
- +- ar_pci->dev = &pdev->dev;
- ++ enum ath10k_hw_rev hw_rev;
- ++ u32 chip_id;
- +
- + switch (pci_dev->device) {
- + case QCA988X_2_0_DEVICE_ID:
- +- set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features);
- ++ hw_rev = ATH10K_HW_QCA988X;
- ++ break;
- ++ case QCA6174_2_1_DEVICE_ID:
- ++ hw_rev = ATH10K_HW_QCA6174;
- + break;
- + default:
- +- ret = -ENODEV;
- +- ath10k_err("Unknown device ID: %d\n", pci_dev->device);
- +- goto err_ar_pci;
- ++ WARN_ON(1);
- ++ return -ENOTSUPP;
- + }
- +
- +- if (ath10k_pci_target_ps)
- +- set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features);
- +-
- +- ath10k_pci_dump_features(ar_pci);
- +-
- +- ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops);
- ++ ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, ATH10K_BUS_PCI,
- ++ hw_rev, &ath10k_pci_hif_ops);
- + if (!ar) {
- +- ath10k_err("failed to create driver core\n");
- +- ret = -EINVAL;
- +- goto err_ar_pci;
- ++ dev_err(&pdev->dev, "failed to allocate core\n");
- ++ return -ENOMEM;
- + }
- +
- ++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci probe\n");
- ++
- ++ ar_pci = ath10k_pci_priv(ar);
- ++ ar_pci->pdev = pdev;
- ++ ar_pci->dev = &pdev->dev;
- + ar_pci->ar = ar;
- +- atomic_set(&ar_pci->keep_awake_count, 0);
- +
- +- pci_set_drvdata(pdev, ar);
- ++ spin_lock_init(&ar_pci->ce_lock);
- ++ setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
- ++ (unsigned long)ar);
- +
- +- /*
- +- * Without any knowledge of the Host, the Target may have been reset or
- +- * power cycled and its Config Space may no longer reflect the PCI
- +- * address space that was assigned earlier by the PCI infrastructure.
- +- * Refresh it now.
- +- */
- +- ret = pci_assign_resource(pdev, BAR_NUM);
- ++ ret = ath10k_pci_claim(ar);
- + if (ret) {
- +- ath10k_err("failed to assign PCI space: %d\n", ret);
- +- goto err_ar;
- ++ ath10k_err(ar, "failed to claim device: %d\n", ret);
- ++ goto err_core_destroy;
- + }
- +
- +- ret = pci_enable_device(pdev);
- ++ ret = ath10k_pci_wake(ar);
- + if (ret) {
- +- ath10k_err("failed to enable PCI device: %d\n", ret);
- +- goto err_ar;
- ++ ath10k_err(ar, "failed to wake up: %d\n", ret);
- ++ goto err_release;
- + }
- +
- +- /* Request MMIO resources */
- +- ret = pci_request_region(pdev, BAR_NUM, "ath");
- ++ ret = ath10k_pci_alloc_pipes(ar);
- + if (ret) {
- +- ath10k_err("failed to request MMIO region: %d\n", ret);
- +- goto err_device;
- ++ ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
- ++ ret);
- ++ goto err_sleep;
- + }
- +
- +- /*
- +- * Target structures have a limit of 32 bit DMA pointers.
- +- * DMA pointers can be wider than 32 bits by default on some systems.
- +- */
- +- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- +- if (ret) {
- +- ath10k_err("failed to set DMA mask to 32-bit: %d\n", ret);
- +- goto err_region;
- +- }
- ++ ath10k_pci_ce_deinit(ar);
- ++ ath10k_pci_irq_disable(ar);
- +
- +- ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
- ++ ret = ath10k_pci_init_irq(ar);
- + if (ret) {
- +- ath10k_err("failed to set consistent DMA mask to 32-bit\n");
- +- goto err_region;
- ++ ath10k_err(ar, "failed to init irqs: %d\n", ret);
- ++ goto err_free_pipes;
- + }
- +
- +- /* Set bus master bit in PCI_COMMAND to enable DMA */
- +- pci_set_master(pdev);
- +-
- +- /*
- +- * Temporary FIX: disable ASPM
- +- * Will be removed after the OTP is programmed
- +- */
- +- pci_read_config_dword(pdev, 0x80, &lcr_val);
- +- pci_write_config_dword(pdev, 0x80, (lcr_val & 0xffffff00));
- ++ ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n",
- ++ ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs,
- ++ ath10k_pci_irq_mode, ath10k_pci_reset_mode);
- +
- +- /* Arrange for access to Target SoC registers. */
- +- mem = pci_iomap(pdev, BAR_NUM, 0);
- +- if (!mem) {
- +- ath10k_err("failed to perform IOMAP for BAR%d\n", BAR_NUM);
- +- ret = -EIO;
- +- goto err_master;
- ++ ret = ath10k_pci_request_irq(ar);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to request irqs: %d\n", ret);
- ++ goto err_deinit_irq;
- + }
- +
- +- ar_pci->mem = mem;
- +-
- +- spin_lock_init(&ar_pci->ce_lock);
- +-
- +- ret = ath10k_do_pci_wake(ar);
- ++ ret = ath10k_pci_chip_reset(ar);
- + if (ret) {
- +- ath10k_err("Failed to get chip id: %d\n", ret);
- +- goto err_iomap;
- ++ ath10k_err(ar, "failed to reset chip: %d\n", ret);
- ++ goto err_free_irq;
- + }
- +
- + chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
- ++ if (chip_id == 0xffffffff) {
- ++ ath10k_err(ar, "failed to get chip id\n");
- ++ goto err_free_irq;
- ++ }
- +
- +- ath10k_do_pci_sleep(ar);
- +-
- +- ret = ath10k_pci_alloc_ce(ar);
- +- if (ret) {
- +- ath10k_err("failed to allocate copy engine pipes: %d\n", ret);
- +- goto err_iomap;
- ++ if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) {
- ++ ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
- ++ pdev->device, chip_id);
- ++ goto err_sleep;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem);
- ++ ath10k_pci_sleep(ar);
- +
- + ret = ath10k_core_register(ar, chip_id);
- + if (ret) {
- +- ath10k_err("failed to register driver core: %d\n", ret);
- +- goto err_free_ce;
- ++ ath10k_err(ar, "failed to register driver core: %d\n", ret);
- ++ goto err_free_irq;
- + }
- +
- + return 0;
- +
- +-err_free_ce:
- +- ath10k_pci_free_ce(ar);
- +-err_iomap:
- +- pci_iounmap(pdev, mem);
- +-err_master:
- +- pci_clear_master(pdev);
- +-err_region:
- +- pci_release_region(pdev, BAR_NUM);
- +-err_device:
- +- pci_disable_device(pdev);
- +-err_ar:
- ++err_free_irq:
- ++ ath10k_pci_free_irq(ar);
- ++ ath10k_pci_kill_tasklet(ar);
- ++
- ++err_deinit_irq:
- ++ ath10k_pci_deinit_irq(ar);
- ++
- ++err_free_pipes:
- ++ ath10k_pci_free_pipes(ar);
- ++
- ++err_sleep:
- ++ ath10k_pci_sleep(ar);
- ++
- ++err_release:
- ++ ath10k_pci_release(ar);
- ++
- ++err_core_destroy:
- + ath10k_core_destroy(ar);
- +-err_ar_pci:
- +- /* call HIF PCI free here */
- +- kfree(ar_pci);
- +
- + return ret;
- + }
- +@@ -2715,7 +2718,7 @@ static void ath10k_pci_remove(struct pci
- + struct ath10k *ar = pci_get_drvdata(pdev);
- + struct ath10k_pci *ar_pci;
- +
- +- ath10k_dbg(ATH10K_DBG_PCI, "pci remove\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_PCI, "pci remove\n");
- +
- + if (!ar)
- + return;
- +@@ -2725,18 +2728,14 @@ static void ath10k_pci_remove(struct pci
- + if (!ar_pci)
- + return;
- +
- +- tasklet_kill(&ar_pci->msi_fw_err);
- +-
- + ath10k_core_unregister(ar);
- +- ath10k_pci_free_ce(ar);
- +-
- +- pci_iounmap(pdev, ar_pci->mem);
- +- pci_release_region(pdev, BAR_NUM);
- +- pci_clear_master(pdev);
- +- pci_disable_device(pdev);
- +-
- ++ ath10k_pci_free_irq(ar);
- ++ ath10k_pci_kill_tasklet(ar);
- ++ ath10k_pci_deinit_irq(ar);
- ++ ath10k_pci_ce_deinit(ar);
- ++ ath10k_pci_free_pipes(ar);
- ++ ath10k_pci_release(ar);
- + ath10k_core_destroy(ar);
- +- kfree(ar_pci);
- + }
- +
- + MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table);
- +@@ -2754,7 +2753,8 @@ static int __init ath10k_pci_init(void)
- +
- + ret = pci_register_driver(&ath10k_pci_driver);
- + if (ret)
- +- ath10k_err("failed to register PCI driver: %d\n", ret);
- ++ printk(KERN_ERR "failed to register ath10k pci driver: %d\n",
- ++ ret);
- +
- + return ret;
- + }
- +@@ -2770,5 +2770,7 @@ module_exit(ath10k_pci_exit);
- + MODULE_AUTHOR("Qualcomm Atheros");
- + MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
- + MODULE_LICENSE("Dual BSD/GPL");
- +-MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_2_FILE);
- ++MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE);
- ++MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API2_FILE);
- ++MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE);
- + MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
- +--- a/drivers/net/wireless/ath/ath10k/pci.h
- ++++ b/drivers/net/wireless/ath/ath10k/pci.h
- +@@ -23,9 +23,6 @@
- + #include "hw.h"
- + #include "ce.h"
- +
- +-/* FW dump area */
- +-#define REG_DUMP_COUNT_QCA988X 60
- +-
- + /*
- + * maximum number of bytes that can be handled atomically by DiagRead/DiagWrite
- + */
- +@@ -38,7 +35,8 @@
- + #define DIAG_TRANSFER_LIMIT 2048
- +
- + struct bmi_xfer {
- +- struct completion done;
- ++ bool tx_done;
- ++ bool rx_done;
- + bool wait_for_resp;
- + u32 resp_len;
- + };
- +@@ -102,12 +100,12 @@ struct pcie_state {
- + * NOTE: Structure is shared between Host software and Target firmware!
- + */
- + struct ce_pipe_config {
- +- u32 pipenum;
- +- u32 pipedir;
- +- u32 nentries;
- +- u32 nbytes_max;
- +- u32 flags;
- +- u32 reserved;
- ++ __le32 pipenum;
- ++ __le32 pipedir;
- ++ __le32 nentries;
- ++ __le32 nbytes_max;
- ++ __le32 flags;
- ++ __le32 reserved;
- + };
- +
- + /*
- +@@ -129,17 +127,9 @@ struct ce_pipe_config {
- +
- + /* Establish a mapping between a service/direction and a pipe. */
- + struct service_to_pipe {
- +- u32 service_id;
- +- u32 pipedir;
- +- u32 pipenum;
- +-};
- +-
- +-enum ath10k_pci_features {
- +- ATH10K_PCI_FEATURE_MSI_X = 0,
- +- ATH10K_PCI_FEATURE_SOC_POWER_SAVE = 1,
- +-
- +- /* keep last */
- +- ATH10K_PCI_FEATURE_COUNT
- ++ __le32 service_id;
- ++ __le32 pipedir;
- ++ __le32 pipenum;
- + };
- +
- + /* Per-pipe state. */
- +@@ -162,14 +152,17 @@ struct ath10k_pci_pipe {
- + struct tasklet_struct intr;
- + };
- +
- ++struct ath10k_pci_supp_chip {
- ++ u32 dev_id;
- ++ u32 rev_id;
- ++};
- ++
- + struct ath10k_pci {
- + struct pci_dev *pdev;
- + struct device *dev;
- + struct ath10k *ar;
- + void __iomem *mem;
- +
- +- DECLARE_BITMAP(features, ATH10K_PCI_FEATURE_COUNT);
- +-
- + /*
- + * Number of MSI interrupts granted, 0 --> using legacy PCI line
- + * interrupts.
- +@@ -178,12 +171,6 @@ struct ath10k_pci {
- +
- + struct tasklet_struct intr_tq;
- + struct tasklet_struct msi_fw_err;
- +- struct tasklet_struct early_irq_tasklet;
- +-
- +- int started;
- +-
- +- atomic_t keep_awake_count;
- +- bool verified_awake;
- +
- + struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
- +
- +@@ -197,29 +184,17 @@ struct ath10k_pci {
- +
- + /* Map CE id to ce_state */
- + struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
- ++ struct timer_list rx_post_retry;
- + };
- +
- + static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
- + {
- +- return ar->hif.priv;
- +-}
- +-
- +-static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
- +-{
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +-
- +- return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
- +-}
- +-
- +-static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
- +-{
- +- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +-
- +- iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
- ++ return (struct ath10k_pci *)ar->drv_priv;
- + }
- +
- ++#define ATH10K_PCI_RX_POST_RETRY_MS 50
- + #define ATH_PCI_RESET_WAIT_MAX 10 /* ms */
- +-#define PCIE_WAKE_TIMEOUT 5000 /* 5ms */
- ++#define PCIE_WAKE_TIMEOUT 10000 /* 10ms */
- +
- + #define BAR_NUM 0
- +
- +@@ -241,35 +216,17 @@ static inline void ath10k_pci_reg_write3
- + /* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
- + #define DIAG_ACCESS_CE_TIMEOUT_MS 10
- +
- +-/*
- +- * This API allows the Host to access Target registers directly
- +- * and relatively efficiently over PCIe.
- +- * This allows the Host to avoid extra overhead associated with
- +- * sending a message to firmware and waiting for a response message
- +- * from firmware, as is done on other interconnects.
- +- *
- +- * Yet there is some complexity with direct accesses because the
- +- * Target's power state is not known a priori. The Host must issue
- +- * special PCIe reads/writes in order to explicitly wake the Target
- +- * and to verify that it is awake and will remain awake.
- +- *
- +- * Usage:
- ++/* Target exposes its registers for direct access. However before host can
- ++ * access them it needs to make sure the target is awake (ath10k_pci_wake,
- ++ * ath10k_pci_wake_wait, ath10k_pci_is_awake). Once target is awake it won't go
- ++ * to sleep unless host tells it to (ath10k_pci_sleep).
- + *
- +- * Use ath10k_pci_read32 and ath10k_pci_write32 to access Target space.
- +- * These calls must be bracketed by ath10k_pci_wake and
- +- * ath10k_pci_sleep. A single BEGIN/END pair is adequate for
- +- * multiple READ/WRITE operations.
- ++ * If host tries to access target registers without waking it up it can
- ++ * scribble over host memory.
- + *
- +- * Use ath10k_pci_wake to put the Target in a state in
- +- * which it is legal for the Host to directly access it. This
- +- * may involve waking the Target from a low power state, which
- +- * may take up to 2Ms!
- +- *
- +- * Use ath10k_pci_sleep to tell the Target that as far as
- +- * this code path is concerned, it no longer needs to remain
- +- * directly accessible. BEGIN/END is under a reference counter;
- +- * multiple code paths may issue BEGIN/END on a single targid.
- ++ * If target is asleep waking it up may take up to even 2ms.
- + */
- ++
- + static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
- + u32 value)
- + {
- +@@ -295,25 +252,18 @@ static inline void ath10k_pci_soc_write3
- + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val);
- + }
- +
- +-int ath10k_do_pci_wake(struct ath10k *ar);
- +-void ath10k_do_pci_sleep(struct ath10k *ar);
- +-
- +-static inline int ath10k_pci_wake(struct ath10k *ar)
- ++static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
- + {
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +
- +- if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- +- return ath10k_do_pci_wake(ar);
- +-
- +- return 0;
- ++ return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
- + }
- +
- +-static inline void ath10k_pci_sleep(struct ath10k *ar)
- ++static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
- + {
- + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
- +
- +- if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
- +- ath10k_do_pci_sleep(ar);
- ++ iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
- + }
- +
- + #endif /* _PCI_H_ */
- +--- a/drivers/net/wireless/ath/ath10k/rx_desc.h
- ++++ b/drivers/net/wireless/ath/ath10k/rx_desc.h
- +@@ -839,7 +839,6 @@ struct rx_ppdu_start {
- + * Reserved: HW should fill with 0, FW should ignore.
- + */
- +
- +-
- + #define RX_PPDU_END_FLAGS_PHY_ERR (1 << 0)
- + #define RX_PPDU_END_FLAGS_RX_LOCATION (1 << 1)
- + #define RX_PPDU_END_FLAGS_TXBF_H_INFO (1 << 2)
- +@@ -851,7 +850,7 @@ struct rx_ppdu_start {
- +
- + #define RX_PPDU_END_INFO1_PPDU_DONE (1 << 15)
- +
- +-struct rx_ppdu_end {
- ++struct rx_ppdu_end_common {
- + __le32 evm_p0;
- + __le32 evm_p1;
- + __le32 evm_p2;
- +@@ -874,10 +873,33 @@ struct rx_ppdu_end {
- + u8 phy_err_code;
- + __le16 flags; /* %RX_PPDU_END_FLAGS_ */
- + __le32 info0; /* %RX_PPDU_END_INFO0_ */
- ++} __packed;
- ++
- ++struct rx_ppdu_end_qca988x {
- ++ __le16 bb_length;
- ++ __le16 info1; /* %RX_PPDU_END_INFO1_ */
- ++} __packed;
- ++
- ++#define RX_PPDU_END_RTT_CORRELATION_VALUE_MASK 0x00ffffff
- ++#define RX_PPDU_END_RTT_CORRELATION_VALUE_LSB 0
- ++#define RX_PPDU_END_RTT_UNUSED_MASK 0x7f000000
- ++#define RX_PPDU_END_RTT_UNUSED_LSB 24
- ++#define RX_PPDU_END_RTT_NORMAL_MODE BIT(31)
- ++
- ++struct rx_ppdu_end_qca6174 {
- ++ __le32 rtt; /* %RX_PPDU_END_RTT_ */
- + __le16 bb_length;
- + __le16 info1; /* %RX_PPDU_END_INFO1_ */
- + } __packed;
- +
- ++struct rx_ppdu_end {
- ++ struct rx_ppdu_end_common common;
- ++ union {
- ++ struct rx_ppdu_end_qca988x qca988x;
- ++ struct rx_ppdu_end_qca6174 qca6174;
- ++ } __packed;
- ++} __packed;
- ++
- + /*
- + * evm_p0
- + * EVM for pilot 0. Contain EVM for streams: 0, 1, 2 and 3.
- +--- a/drivers/net/wireless/ath/ath10k/targaddrs.h
- ++++ b/drivers/net/wireless/ath/ath10k/targaddrs.h
- +@@ -18,6 +18,8 @@
- + #ifndef __TARGADDRS_H__
- + #define __TARGADDRS_H__
- +
- ++#include "hw.h"
- ++
- + /*
- + * xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the
- + * host_interest structure. It must match the address of the _host_interest
- +@@ -284,7 +286,6 @@ Fw Mode/SubMode Mask
- + #define HI_OPTION_ALL_FW_SUBMODE_MASK 0xFF00
- + #define HI_OPTION_ALL_FW_SUBMODE_SHIFT 0x8
- +
- +-
- + /* hi_option_flag2 options */
- + #define HI_OPTION_OFFLOAD_AMSDU 0x01
- + #define HI_OPTION_DFS_SUPPORT 0x02 /* Enable DFS support */
- +@@ -446,4 +447,7 @@ Fw Mode/SubMode Mask
- + #define QCA988X_BOARD_DATA_SZ 7168
- + #define QCA988X_BOARD_EXT_DATA_SZ 0
- +
- ++#define QCA6174_BOARD_DATA_SZ 8192
- ++#define QCA6174_BOARD_EXT_DATA_SZ 0
- ++
- + #endif /* __TARGADDRS_H__ */
- +--- a/drivers/net/wireless/ath/ath10k/trace.h
- ++++ b/drivers/net/wireless/ath/ath10k/trace.h
- +@@ -18,6 +18,16 @@
- + #if !defined(_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
- +
- + #include <linux/tracepoint.h>
- ++#include "core.h"
- ++
- ++#if !defined(_TRACE_H_)
- ++static inline u32 ath10k_frm_hdr_len(const void *buf)
- ++{
- ++ const struct ieee80211_hdr *hdr = buf;
- ++
- ++ return ieee80211_hdrlen(hdr->frame_control);
- ++}
- ++#endif
- +
- + #define _TRACE_H_
- +
- +@@ -39,59 +49,79 @@ static inline void trace_ ## name(proto)
- + #define ATH10K_MSG_MAX 200
- +
- + DECLARE_EVENT_CLASS(ath10k_log_event,
- +- TP_PROTO(struct va_format *vaf),
- +- TP_ARGS(vaf),
- ++ TP_PROTO(struct ath10k *ar, struct va_format *vaf),
- ++ TP_ARGS(ar, vaf),
- + TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- + __dynamic_array(char, msg, ATH10K_MSG_MAX)
- + ),
- + TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
- + ATH10K_MSG_MAX,
- + vaf->fmt,
- + *vaf->va) >= ATH10K_MSG_MAX);
- + ),
- +- TP_printk("%s", __get_str(msg))
- ++ TP_printk(
- ++ "%s %s %s",
- ++ __get_str(driver),
- ++ __get_str(device),
- ++ __get_str(msg)
- ++ )
- + );
- +
- + DEFINE_EVENT(ath10k_log_event, ath10k_log_err,
- +- TP_PROTO(struct va_format *vaf),
- +- TP_ARGS(vaf)
- ++ TP_PROTO(struct ath10k *ar, struct va_format *vaf),
- ++ TP_ARGS(ar, vaf)
- + );
- +
- + DEFINE_EVENT(ath10k_log_event, ath10k_log_warn,
- +- TP_PROTO(struct va_format *vaf),
- +- TP_ARGS(vaf)
- ++ TP_PROTO(struct ath10k *ar, struct va_format *vaf),
- ++ TP_ARGS(ar, vaf)
- + );
- +
- + DEFINE_EVENT(ath10k_log_event, ath10k_log_info,
- +- TP_PROTO(struct va_format *vaf),
- +- TP_ARGS(vaf)
- ++ TP_PROTO(struct ath10k *ar, struct va_format *vaf),
- ++ TP_ARGS(ar, vaf)
- + );
- +
- + TRACE_EVENT(ath10k_log_dbg,
- +- TP_PROTO(unsigned int level, struct va_format *vaf),
- +- TP_ARGS(level, vaf),
- ++ TP_PROTO(struct ath10k *ar, unsigned int level, struct va_format *vaf),
- ++ TP_ARGS(ar, level, vaf),
- + TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- + __field(unsigned int, level)
- + __dynamic_array(char, msg, ATH10K_MSG_MAX)
- + ),
- + TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- + __entry->level = level;
- + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
- + ATH10K_MSG_MAX,
- + vaf->fmt,
- + *vaf->va) >= ATH10K_MSG_MAX);
- + ),
- +- TP_printk("%s", __get_str(msg))
- ++ TP_printk(
- ++ "%s %s %s",
- ++ __get_str(driver),
- ++ __get_str(device),
- ++ __get_str(msg)
- ++ )
- + );
- +
- + TRACE_EVENT(ath10k_log_dbg_dump,
- +- TP_PROTO(const char *msg, const char *prefix,
- ++ TP_PROTO(struct ath10k *ar, const char *msg, const char *prefix,
- + const void *buf, size_t buf_len),
- +
- +- TP_ARGS(msg, prefix, buf, buf_len),
- ++ TP_ARGS(ar, msg, prefix, buf, buf_len),
- +
- + TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- + __string(msg, msg)
- + __string(prefix, prefix)
- + __field(size_t, buf_len)
- +@@ -99,6 +129,8 @@ TRACE_EVENT(ath10k_log_dbg_dump,
- + ),
- +
- + TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- + __assign_str(msg, msg);
- + __assign_str(prefix, prefix);
- + __entry->buf_len = buf_len;
- +@@ -106,16 +138,23 @@ TRACE_EVENT(ath10k_log_dbg_dump,
- + ),
- +
- + TP_printk(
- +- "%s/%s\n", __get_str(prefix), __get_str(msg)
- ++ "%s %s %s/%s\n",
- ++ __get_str(driver),
- ++ __get_str(device),
- ++ __get_str(prefix),
- ++ __get_str(msg)
- + )
- + );
- +
- + TRACE_EVENT(ath10k_wmi_cmd,
- +- TP_PROTO(int id, void *buf, size_t buf_len, int ret),
- ++ TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len,
- ++ int ret),
- +
- +- TP_ARGS(id, buf, buf_len, ret),
- ++ TP_ARGS(ar, id, buf, buf_len, ret),
- +
- + TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- + __field(unsigned int, id)
- + __field(size_t, buf_len)
- + __dynamic_array(u8, buf, buf_len)
- +@@ -123,6 +162,8 @@ TRACE_EVENT(ath10k_wmi_cmd,
- + ),
- +
- + TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- + __entry->id = id;
- + __entry->buf_len = buf_len;
- + __entry->ret = ret;
- +@@ -130,7 +171,9 @@ TRACE_EVENT(ath10k_wmi_cmd,
- + ),
- +
- + TP_printk(
- +- "id %d len %zu ret %d",
- ++ "%s %s id %d len %zu ret %d",
- ++ __get_str(driver),
- ++ __get_str(device),
- + __entry->id,
- + __entry->buf_len,
- + __entry->ret
- +@@ -138,71 +181,346 @@ TRACE_EVENT(ath10k_wmi_cmd,
- + );
- +
- + TRACE_EVENT(ath10k_wmi_event,
- +- TP_PROTO(int id, void *buf, size_t buf_len),
- ++ TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len),
- +
- +- TP_ARGS(id, buf, buf_len),
- ++ TP_ARGS(ar, id, buf, buf_len),
- +
- + TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- + __field(unsigned int, id)
- + __field(size_t, buf_len)
- + __dynamic_array(u8, buf, buf_len)
- + ),
- +
- + TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- + __entry->id = id;
- + __entry->buf_len = buf_len;
- + memcpy(__get_dynamic_array(buf), buf, buf_len);
- + ),
- +
- + TP_printk(
- +- "id %d len %zu",
- ++ "%s %s id %d len %zu",
- ++ __get_str(driver),
- ++ __get_str(device),
- + __entry->id,
- + __entry->buf_len
- + )
- + );
- +
- + TRACE_EVENT(ath10k_htt_stats,
- +- TP_PROTO(void *buf, size_t buf_len),
- ++ TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len),
- +
- +- TP_ARGS(buf, buf_len),
- ++ TP_ARGS(ar, buf, buf_len),
- +
- + TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- + __field(size_t, buf_len)
- + __dynamic_array(u8, buf, buf_len)
- + ),
- +
- + TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- + __entry->buf_len = buf_len;
- + memcpy(__get_dynamic_array(buf), buf, buf_len);
- + ),
- +
- + TP_printk(
- +- "len %zu",
- ++ "%s %s len %zu",
- ++ __get_str(driver),
- ++ __get_str(device),
- + __entry->buf_len
- + )
- + );
- +
- + TRACE_EVENT(ath10k_wmi_dbglog,
- +- TP_PROTO(void *buf, size_t buf_len),
- ++ TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len),
- +
- +- TP_ARGS(buf, buf_len),
- ++ TP_ARGS(ar, buf, buf_len),
- +
- + TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- + __field(size_t, buf_len)
- + __dynamic_array(u8, buf, buf_len)
- + ),
- +
- + TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- + __entry->buf_len = buf_len;
- + memcpy(__get_dynamic_array(buf), buf, buf_len);
- + ),
- +
- + TP_printk(
- +- "len %zu",
- ++ "%s %s len %zu",
- ++ __get_str(driver),
- ++ __get_str(device),
- + __entry->buf_len
- + )
- + );
- +
- ++TRACE_EVENT(ath10k_htt_pktlog,
- ++ TP_PROTO(struct ath10k *ar, const void *buf, u16 buf_len),
- ++
- ++ TP_ARGS(ar, buf, buf_len),
- ++
- ++ TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- ++ __field(u16, buf_len)
- ++ __dynamic_array(u8, pktlog, buf_len)
- ++ ),
- ++
- ++ TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- ++ __entry->buf_len = buf_len;
- ++ memcpy(__get_dynamic_array(pktlog), buf, buf_len);
- ++ ),
- ++
- ++ TP_printk(
- ++ "%s %s size %hu",
- ++ __get_str(driver),
- ++ __get_str(device),
- ++ __entry->buf_len
- ++ )
- ++);
- ++
- ++TRACE_EVENT(ath10k_htt_tx,
- ++ TP_PROTO(struct ath10k *ar, u16 msdu_id, u16 msdu_len,
- ++ u8 vdev_id, u8 tid),
- ++
- ++ TP_ARGS(ar, msdu_id, msdu_len, vdev_id, tid),
- ++
- ++ TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- ++ __field(u16, msdu_id)
- ++ __field(u16, msdu_len)
- ++ __field(u8, vdev_id)
- ++ __field(u8, tid)
- ++ ),
- ++
- ++ TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- ++ __entry->msdu_id = msdu_id;
- ++ __entry->msdu_len = msdu_len;
- ++ __entry->vdev_id = vdev_id;
- ++ __entry->tid = tid;
- ++ ),
- ++
- ++ TP_printk(
- ++ "%s %s msdu_id %d msdu_len %d vdev_id %d tid %d",
- ++ __get_str(driver),
- ++ __get_str(device),
- ++ __entry->msdu_id,
- ++ __entry->msdu_len,
- ++ __entry->vdev_id,
- ++ __entry->tid
- ++ )
- ++);
- ++
- ++TRACE_EVENT(ath10k_txrx_tx_unref,
- ++ TP_PROTO(struct ath10k *ar, u16 msdu_id),
- ++
- ++ TP_ARGS(ar, msdu_id),
- ++
- ++ TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- ++ __field(u16, msdu_id)
- ++ ),
- ++
- ++ TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- ++ __entry->msdu_id = msdu_id;
- ++ ),
- ++
- ++ TP_printk(
- ++ "%s %s msdu_id %d",
- ++ __get_str(driver),
- ++ __get_str(device),
- ++ __entry->msdu_id
- ++ )
- ++);
- ++
- ++DECLARE_EVENT_CLASS(ath10k_hdr_event,
- ++ TP_PROTO(struct ath10k *ar, const void *data, size_t len),
- ++
- ++ TP_ARGS(ar, data, len),
- ++
- ++ TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- ++ __field(size_t, len)
- ++ __dynamic_array(u8, data, ath10k_frm_hdr_len(data))
- ++ ),
- ++
- ++ TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- ++ __entry->len = ath10k_frm_hdr_len(data);
- ++ memcpy(__get_dynamic_array(data), data, __entry->len);
- ++ ),
- ++
- ++ TP_printk(
- ++ "%s %s len %zu\n",
- ++ __get_str(driver),
- ++ __get_str(device),
- ++ __entry->len
- ++ )
- ++);
- ++
- ++DECLARE_EVENT_CLASS(ath10k_payload_event,
- ++ TP_PROTO(struct ath10k *ar, const void *data, size_t len),
- ++
- ++ TP_ARGS(ar, data, len),
- ++
- ++ TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- ++ __field(size_t, len)
- ++ __dynamic_array(u8, payload, (len - ath10k_frm_hdr_len(data)))
- ++ ),
- ++
- ++ TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- ++ __entry->len = len - ath10k_frm_hdr_len(data);
- ++ memcpy(__get_dynamic_array(payload),
- ++ data + ath10k_frm_hdr_len(data), __entry->len);
- ++ ),
- ++
- ++ TP_printk(
- ++ "%s %s len %zu\n",
- ++ __get_str(driver),
- ++ __get_str(device),
- ++ __entry->len
- ++ )
- ++);
- ++
- ++DEFINE_EVENT(ath10k_hdr_event, ath10k_tx_hdr,
- ++ TP_PROTO(struct ath10k *ar, const void *data, size_t len),
- ++ TP_ARGS(ar, data, len)
- ++);
- ++
- ++DEFINE_EVENT(ath10k_payload_event, ath10k_tx_payload,
- ++ TP_PROTO(struct ath10k *ar, const void *data, size_t len),
- ++ TP_ARGS(ar, data, len)
- ++);
- ++
- ++DEFINE_EVENT(ath10k_hdr_event, ath10k_rx_hdr,
- ++ TP_PROTO(struct ath10k *ar, const void *data, size_t len),
- ++ TP_ARGS(ar, data, len)
- ++);
- ++
- ++DEFINE_EVENT(ath10k_payload_event, ath10k_rx_payload,
- ++ TP_PROTO(struct ath10k *ar, const void *data, size_t len),
- ++ TP_ARGS(ar, data, len)
- ++);
- ++
- ++TRACE_EVENT(ath10k_htt_rx_desc,
- ++ TP_PROTO(struct ath10k *ar, const void *data, size_t len),
- ++
- ++ TP_ARGS(ar, data, len),
- ++
- ++ TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- ++ __field(u16, len)
- ++ __dynamic_array(u8, rxdesc, len)
- ++ ),
- ++
- ++ TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- ++ __entry->len = len;
- ++ memcpy(__get_dynamic_array(rxdesc), data, len);
- ++ ),
- ++
- ++ TP_printk(
- ++ "%s %s rxdesc len %d",
- ++ __get_str(driver),
- ++ __get_str(device),
- ++ __entry->len
- ++ )
- ++);
- ++
- ++TRACE_EVENT(ath10k_wmi_diag_container,
- ++ TP_PROTO(struct ath10k *ar,
- ++ u8 type,
- ++ u32 timestamp,
- ++ u32 code,
- ++ u16 len,
- ++ const void *data),
- ++
- ++ TP_ARGS(ar, type, timestamp, code, len, data),
- ++
- ++ TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- ++ __field(u8, type)
- ++ __field(u32, timestamp)
- ++ __field(u32, code)
- ++ __field(u16, len)
- ++ __dynamic_array(u8, data, len)
- ++ ),
- ++
- ++ TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- ++ __entry->type = type;
- ++ __entry->timestamp = timestamp;
- ++ __entry->code = code;
- ++ __entry->len = len;
- ++ memcpy(__get_dynamic_array(data), data, len);
- ++ ),
- ++
- ++ TP_printk(
- ++ "%s %s diag container type %hhu timestamp %u code %u len %d",
- ++ __get_str(driver),
- ++ __get_str(device),
- ++ __entry->type,
- ++ __entry->timestamp,
- ++ __entry->code,
- ++ __entry->len
- ++ )
- ++);
- ++
- ++TRACE_EVENT(ath10k_wmi_diag,
- ++ TP_PROTO(struct ath10k *ar, const void *data, size_t len),
- ++
- ++ TP_ARGS(ar, data, len),
- ++
- ++ TP_STRUCT__entry(
- ++ __string(device, dev_name(ar->dev))
- ++ __string(driver, dev_driver_string(ar->dev))
- ++ __field(u16, len)
- ++ __dynamic_array(u8, data, len)
- ++ ),
- ++
- ++ TP_fast_assign(
- ++ __assign_str(device, dev_name(ar->dev));
- ++ __assign_str(driver, dev_driver_string(ar->dev));
- ++ __entry->len = len;
- ++ memcpy(__get_dynamic_array(data), data, len);
- ++ ),
- ++
- ++ TP_printk(
- ++ "%s %s tlv diag len %d",
- ++ __get_str(driver),
- ++ __get_str(device),
- ++ __entry->len
- ++ )
- ++);
- ++
- + #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
- +
- + /* we don't want to use include/trace/events */
- +--- a/drivers/net/wireless/ath/ath10k/txrx.c
- ++++ b/drivers/net/wireless/ath/ath10k/txrx.c
- +@@ -32,14 +32,14 @@ static void ath10k_report_offchan_tx(str
- + * offchan_tx_skb. */
- + spin_lock_bh(&ar->data_lock);
- + if (ar->offchan_tx_skb != skb) {
- +- ath10k_warn("completed old offchannel frame\n");
- ++ ath10k_warn(ar, "completed old offchannel frame\n");
- + goto out;
- + }
- +
- + complete(&ar->offchan_tx_completed);
- + ar->offchan_tx_skb = NULL; /* just for sanity */
- +
- +- ath10k_dbg(ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb);
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb);
- + out:
- + spin_unlock_bh(&ar->data_lock);
- + }
- +@@ -47,23 +47,30 @@ out:
- + void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
- + const struct htt_tx_done *tx_done)
- + {
- +- struct device *dev = htt->ar->dev;
- ++ struct ath10k *ar = htt->ar;
- ++ struct device *dev = ar->dev;
- + struct ieee80211_tx_info *info;
- + struct ath10k_skb_cb *skb_cb;
- + struct sk_buff *msdu;
- +
- + lockdep_assert_held(&htt->tx_lock);
- +
- +- ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
- + tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack);
- +
- + if (tx_done->msdu_id >= htt->max_num_pending_tx) {
- +- ath10k_warn("warning: msdu_id %d too big, ignoring\n",
- ++ ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n",
- ++ tx_done->msdu_id);
- ++ return;
- ++ }
- ++
- ++ msdu = idr_find(&htt->pending_tx, tx_done->msdu_id);
- ++ if (!msdu) {
- ++ ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n",
- + tx_done->msdu_id);
- + return;
- + }
- +
- +- msdu = htt->pending_tx[tx_done->msdu_id];
- + skb_cb = ATH10K_SKB_CB(msdu);
- +
- + dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
- +@@ -77,6 +84,7 @@ void ath10k_txrx_tx_unref(struct ath10k_
- +
- + info = IEEE80211_SKB_CB(msdu);
- + memset(&info->status, 0, sizeof(info->status));
- ++ trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id);
- +
- + if (tx_done->discard) {
- + ieee80211_free_txskb(htt->ar->hw, msdu);
- +@@ -93,7 +101,6 @@ void ath10k_txrx_tx_unref(struct ath10k_
- + /* we do not own the msdu anymore */
- +
- + exit:
- +- htt->pending_tx[tx_done->msdu_id] = NULL;
- + ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
- + __ath10k_htt_tx_dec_pending(htt);
- + if (htt->num_pending_tx == 0)
- +@@ -119,8 +126,7 @@ struct ath10k_peer *ath10k_peer_find(str
- + return NULL;
- + }
- +
- +-static struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar,
- +- int peer_id)
- ++struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id)
- + {
- + struct ath10k_peer *peer;
- +
- +@@ -145,7 +151,8 @@ static int ath10k_wait_for_peer_common(s
- + mapped = !!ath10k_peer_find(ar, vdev_id, addr);
- + spin_unlock_bh(&ar->data_lock);
- +
- +- mapped == expect_mapped;
- ++ (mapped == expect_mapped ||
- ++ test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags));
- + }), 3*HZ);
- +
- + if (ret <= 0)
- +@@ -178,12 +185,12 @@ void ath10k_peer_map_event(struct ath10k
- + goto exit;
- +
- + peer->vdev_id = ev->vdev_id;
- +- memcpy(peer->addr, ev->addr, ETH_ALEN);
- ++ ether_addr_copy(peer->addr, ev->addr);
- + list_add(&peer->list, &ar->peers);
- + wake_up(&ar->peer_mapping_wq);
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
- + ev->vdev_id, ev->addr, ev->peer_id);
- +
- + set_bit(ev->peer_id, peer->peer_ids);
- +@@ -200,12 +207,12 @@ void ath10k_peer_unmap_event(struct ath1
- + spin_lock_bh(&ar->data_lock);
- + peer = ath10k_peer_find_by_id(ar, ev->peer_id);
- + if (!peer) {
- +- ath10k_warn("peer-unmap-event: unknown peer id %d\n",
- ++ ath10k_warn(ar, "peer-unmap-event: unknown peer id %d\n",
- + ev->peer_id);
- + goto exit;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
- + peer->vdev_id, peer->addr, ev->peer_id);
- +
- + clear_bit(ev->peer_id, peer->peer_ids);
- +--- a/drivers/net/wireless/ath/ath10k/txrx.h
- ++++ b/drivers/net/wireless/ath/ath10k/txrx.h
- +@@ -24,6 +24,7 @@ void ath10k_txrx_tx_unref(struct ath10k_
- +
- + struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
- + const u8 *addr);
- ++struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id);
- + int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id,
- + const u8 *addr);
- + int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id,
- +--- a/drivers/net/wireless/ath/ath10k/wmi.c
- ++++ b/drivers/net/wireless/ath/ath10k/wmi.c
- +@@ -22,7 +22,10 @@
- + #include "htc.h"
- + #include "debug.h"
- + #include "wmi.h"
- ++#include "wmi-tlv.h"
- + #include "mac.h"
- ++#include "testmode.h"
- ++#include "wmi-ops.h"
- +
- + /* MAIN WMI cmd track */
- + static struct wmi_cmd_map wmi_cmd_map = {
- +@@ -142,6 +145,7 @@ static struct wmi_cmd_map wmi_cmd_map =
- + .force_fw_hang_cmdid = WMI_FORCE_FW_HANG_CMDID,
- + .gpio_config_cmdid = WMI_GPIO_CONFIG_CMDID,
- + .gpio_output_cmdid = WMI_GPIO_OUTPUT_CMDID,
- ++ .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED,
- + };
- +
- + /* 10.X WMI cmd track */
- +@@ -264,6 +268,129 @@ static struct wmi_cmd_map wmi_10x_cmd_ma
- + .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED,
- + .gpio_config_cmdid = WMI_10X_GPIO_CONFIG_CMDID,
- + .gpio_output_cmdid = WMI_10X_GPIO_OUTPUT_CMDID,
- ++ .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED,
- ++};
- ++
- ++/* 10.2.4 WMI cmd track */
- ++static struct wmi_cmd_map wmi_10_2_4_cmd_map = {
- ++ .init_cmdid = WMI_10_2_INIT_CMDID,
- ++ .start_scan_cmdid = WMI_10_2_START_SCAN_CMDID,
- ++ .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID,
- ++ .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID,
- ++ .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
- ++ .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID,
- ++ .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID,
- ++ .pdev_pktlog_enable_cmdid = WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
- ++ .pdev_pktlog_disable_cmdid = WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
- ++ .pdev_set_wmm_params_cmdid = WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
- ++ .pdev_set_ht_cap_ie_cmdid = WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
- ++ .pdev_set_vht_cap_ie_cmdid = WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
- ++ .pdev_set_quiet_mode_cmdid = WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
- ++ .pdev_green_ap_ps_enable_cmdid = WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
- ++ .pdev_get_tpc_config_cmdid = WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
- ++ .pdev_set_base_macaddr_cmdid = WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
- ++ .vdev_create_cmdid = WMI_10_2_VDEV_CREATE_CMDID,
- ++ .vdev_delete_cmdid = WMI_10_2_VDEV_DELETE_CMDID,
- ++ .vdev_start_request_cmdid = WMI_10_2_VDEV_START_REQUEST_CMDID,
- ++ .vdev_restart_request_cmdid = WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
- ++ .vdev_up_cmdid = WMI_10_2_VDEV_UP_CMDID,
- ++ .vdev_stop_cmdid = WMI_10_2_VDEV_STOP_CMDID,
- ++ .vdev_down_cmdid = WMI_10_2_VDEV_DOWN_CMDID,
- ++ .vdev_set_param_cmdid = WMI_10_2_VDEV_SET_PARAM_CMDID,
- ++ .vdev_install_key_cmdid = WMI_10_2_VDEV_INSTALL_KEY_CMDID,
- ++ .peer_create_cmdid = WMI_10_2_PEER_CREATE_CMDID,
- ++ .peer_delete_cmdid = WMI_10_2_PEER_DELETE_CMDID,
- ++ .peer_flush_tids_cmdid = WMI_10_2_PEER_FLUSH_TIDS_CMDID,
- ++ .peer_set_param_cmdid = WMI_10_2_PEER_SET_PARAM_CMDID,
- ++ .peer_assoc_cmdid = WMI_10_2_PEER_ASSOC_CMDID,
- ++ .peer_add_wds_entry_cmdid = WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
- ++ .peer_remove_wds_entry_cmdid = WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
- ++ .peer_mcast_group_cmdid = WMI_10_2_PEER_MCAST_GROUP_CMDID,
- ++ .bcn_tx_cmdid = WMI_10_2_BCN_TX_CMDID,
- ++ .pdev_send_bcn_cmdid = WMI_10_2_PDEV_SEND_BCN_CMDID,
- ++ .bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .bcn_filter_rx_cmdid = WMI_10_2_BCN_FILTER_RX_CMDID,
- ++ .prb_req_filter_rx_cmdid = WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
- ++ .mgmt_tx_cmdid = WMI_10_2_MGMT_TX_CMDID,
- ++ .prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .addba_clear_resp_cmdid = WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
- ++ .addba_send_cmdid = WMI_10_2_ADDBA_SEND_CMDID,
- ++ .addba_status_cmdid = WMI_10_2_ADDBA_STATUS_CMDID,
- ++ .delba_send_cmdid = WMI_10_2_DELBA_SEND_CMDID,
- ++ .addba_set_resp_cmdid = WMI_10_2_ADDBA_SET_RESP_CMDID,
- ++ .send_singleamsdu_cmdid = WMI_10_2_SEND_SINGLEAMSDU_CMDID,
- ++ .sta_powersave_mode_cmdid = WMI_10_2_STA_POWERSAVE_MODE_CMDID,
- ++ .sta_powersave_param_cmdid = WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
- ++ .sta_mimo_ps_mode_cmdid = WMI_10_2_STA_MIMO_PS_MODE_CMDID,
- ++ .pdev_dfs_enable_cmdid = WMI_10_2_PDEV_DFS_ENABLE_CMDID,
- ++ .pdev_dfs_disable_cmdid = WMI_10_2_PDEV_DFS_DISABLE_CMDID,
- ++ .roam_scan_mode = WMI_10_2_ROAM_SCAN_MODE,
- ++ .roam_scan_rssi_threshold = WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
- ++ .roam_scan_period = WMI_10_2_ROAM_SCAN_PERIOD,
- ++ .roam_scan_rssi_change_threshold =
- ++ WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
- ++ .roam_ap_profile = WMI_10_2_ROAM_AP_PROFILE,
- ++ .ofl_scan_add_ap_profile = WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
- ++ .ofl_scan_remove_ap_profile = WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
- ++ .ofl_scan_period = WMI_10_2_OFL_SCAN_PERIOD,
- ++ .p2p_dev_set_device_info = WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
- ++ .p2p_dev_set_discoverability = WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
- ++ .p2p_go_set_beacon_ie = WMI_10_2_P2P_GO_SET_BEACON_IE,
- ++ .p2p_go_set_probe_resp_ie = WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
- ++ .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .ap_ps_peer_param_cmdid = WMI_10_2_AP_PS_PEER_PARAM_CMDID,
- ++ .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .peer_rate_retry_sched_cmdid = WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
- ++ .wlan_profile_trigger_cmdid = WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
- ++ .wlan_profile_set_hist_intvl_cmdid =
- ++ WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
- ++ .wlan_profile_get_profile_data_cmdid =
- ++ WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
- ++ .wlan_profile_enable_profile_id_cmdid =
- ++ WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
- ++ .wlan_profile_list_profile_id_cmdid =
- ++ WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
- ++ .pdev_suspend_cmdid = WMI_10_2_PDEV_SUSPEND_CMDID,
- ++ .pdev_resume_cmdid = WMI_10_2_PDEV_RESUME_CMDID,
- ++ .add_bcn_filter_cmdid = WMI_10_2_ADD_BCN_FILTER_CMDID,
- ++ .rmv_bcn_filter_cmdid = WMI_10_2_RMV_BCN_FILTER_CMDID,
- ++ .wow_add_wake_pattern_cmdid = WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
- ++ .wow_del_wake_pattern_cmdid = WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
- ++ .wow_enable_disable_wake_event_cmdid =
- ++ WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
- ++ .wow_enable_cmdid = WMI_10_2_WOW_ENABLE_CMDID,
- ++ .wow_hostwakeup_from_sleep_cmdid =
- ++ WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
- ++ .rtt_measreq_cmdid = WMI_10_2_RTT_MEASREQ_CMDID,
- ++ .rtt_tsf_cmdid = WMI_10_2_RTT_TSF_CMDID,
- ++ .vdev_spectral_scan_configure_cmdid =
- ++ WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
- ++ .vdev_spectral_scan_enable_cmdid =
- ++ WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
- ++ .request_stats_cmdid = WMI_10_2_REQUEST_STATS_CMDID,
- ++ .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .gtk_offload_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED,
- ++ .echo_cmdid = WMI_10_2_ECHO_CMDID,
- ++ .pdev_utf_cmdid = WMI_10_2_PDEV_UTF_CMDID,
- ++ .dbglog_cfg_cmdid = WMI_10_2_DBGLOG_CFG_CMDID,
- ++ .pdev_qvit_cmdid = WMI_10_2_PDEV_QVIT_CMDID,
- ++ .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID,
- ++ .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
- ++ .pdev_get_temperature_cmdid = WMI_10_2_PDEV_GET_TEMPERATURE_CMDID,
- + };
- +
- + /* MAIN WMI VDEV param map */
- +@@ -384,6 +511,64 @@ static struct wmi_vdev_param_map wmi_10x
- + WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
- + };
- +
- ++static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = {
- ++ .rts_threshold = WMI_10X_VDEV_PARAM_RTS_THRESHOLD,
- ++ .fragmentation_threshold = WMI_10X_VDEV_PARAM_FRAGMENTATION_THRESHOLD,
- ++ .beacon_interval = WMI_10X_VDEV_PARAM_BEACON_INTERVAL,
- ++ .listen_interval = WMI_10X_VDEV_PARAM_LISTEN_INTERVAL,
- ++ .multicast_rate = WMI_10X_VDEV_PARAM_MULTICAST_RATE,
- ++ .mgmt_tx_rate = WMI_10X_VDEV_PARAM_MGMT_TX_RATE,
- ++ .slot_time = WMI_10X_VDEV_PARAM_SLOT_TIME,
- ++ .preamble = WMI_10X_VDEV_PARAM_PREAMBLE,
- ++ .swba_time = WMI_10X_VDEV_PARAM_SWBA_TIME,
- ++ .wmi_vdev_stats_update_period = WMI_10X_VDEV_STATS_UPDATE_PERIOD,
- ++ .wmi_vdev_pwrsave_ageout_time = WMI_10X_VDEV_PWRSAVE_AGEOUT_TIME,
- ++ .wmi_vdev_host_swba_interval = WMI_10X_VDEV_HOST_SWBA_INTERVAL,
- ++ .dtim_period = WMI_10X_VDEV_PARAM_DTIM_PERIOD,
- ++ .wmi_vdev_oc_scheduler_air_time_limit =
- ++ WMI_10X_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT,
- ++ .wds = WMI_10X_VDEV_PARAM_WDS,
- ++ .atim_window = WMI_10X_VDEV_PARAM_ATIM_WINDOW,
- ++ .bmiss_count_max = WMI_10X_VDEV_PARAM_BMISS_COUNT_MAX,
- ++ .bmiss_first_bcnt = WMI_VDEV_PARAM_UNSUPPORTED,
- ++ .bmiss_final_bcnt = WMI_VDEV_PARAM_UNSUPPORTED,
- ++ .feature_wmm = WMI_10X_VDEV_PARAM_FEATURE_WMM,
- ++ .chwidth = WMI_10X_VDEV_PARAM_CHWIDTH,
- ++ .chextoffset = WMI_10X_VDEV_PARAM_CHEXTOFFSET,
- ++ .disable_htprotection = WMI_10X_VDEV_PARAM_DISABLE_HTPROTECTION,
- ++ .sta_quickkickout = WMI_10X_VDEV_PARAM_STA_QUICKKICKOUT,
- ++ .mgmt_rate = WMI_10X_VDEV_PARAM_MGMT_RATE,
- ++ .protection_mode = WMI_10X_VDEV_PARAM_PROTECTION_MODE,
- ++ .fixed_rate = WMI_10X_VDEV_PARAM_FIXED_RATE,
- ++ .sgi = WMI_10X_VDEV_PARAM_SGI,
- ++ .ldpc = WMI_10X_VDEV_PARAM_LDPC,
- ++ .tx_stbc = WMI_10X_VDEV_PARAM_TX_STBC,
- ++ .rx_stbc = WMI_10X_VDEV_PARAM_RX_STBC,
- ++ .intra_bss_fwd = WMI_10X_VDEV_PARAM_INTRA_BSS_FWD,
- ++ .def_keyid = WMI_10X_VDEV_PARAM_DEF_KEYID,
- ++ .nss = WMI_10X_VDEV_PARAM_NSS,
- ++ .bcast_data_rate = WMI_10X_VDEV_PARAM_BCAST_DATA_RATE,
- ++ .mcast_data_rate = WMI_10X_VDEV_PARAM_MCAST_DATA_RATE,
- ++ .mcast_indicate = WMI_10X_VDEV_PARAM_MCAST_INDICATE,
- ++ .dhcp_indicate = WMI_10X_VDEV_PARAM_DHCP_INDICATE,
- ++ .unknown_dest_indicate = WMI_10X_VDEV_PARAM_UNKNOWN_DEST_INDICATE,
- ++ .ap_keepalive_min_idle_inactive_time_secs =
- ++ WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS,
- ++ .ap_keepalive_max_idle_inactive_time_secs =
- ++ WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS,
- ++ .ap_keepalive_max_unresponsive_time_secs =
- ++ WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS,
- ++ .ap_enable_nawds = WMI_10X_VDEV_PARAM_AP_ENABLE_NAWDS,
- ++ .mcast2ucast_set = WMI_10X_VDEV_PARAM_MCAST2UCAST_SET,
- ++ .enable_rtscts = WMI_10X_VDEV_PARAM_ENABLE_RTSCTS,
- ++ .txbf = WMI_VDEV_PARAM_UNSUPPORTED,
- ++ .packet_powersave = WMI_VDEV_PARAM_UNSUPPORTED,
- ++ .drop_unencry = WMI_VDEV_PARAM_UNSUPPORTED,
- ++ .tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED,
- ++ .ap_detect_out_of_sync_sleeping_sta_time_secs =
- ++ WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
- ++};
- ++
- + static struct wmi_pdev_param_map wmi_pdev_param_map = {
- + .tx_chain_mask = WMI_PDEV_PARAM_TX_CHAIN_MASK,
- + .rx_chain_mask = WMI_PDEV_PARAM_RX_CHAIN_MASK,
- +@@ -433,6 +618,7 @@ static struct wmi_pdev_param_map wmi_pde
- + .fast_channel_reset = WMI_PDEV_PARAM_UNSUPPORTED,
- + .burst_dur = WMI_PDEV_PARAM_UNSUPPORTED,
- + .burst_enable = WMI_PDEV_PARAM_UNSUPPORTED,
- ++ .cal_period = WMI_PDEV_PARAM_UNSUPPORTED,
- + };
- +
- + static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
- +@@ -485,11 +671,221 @@ static struct wmi_pdev_param_map wmi_10x
- + .fast_channel_reset = WMI_10X_PDEV_PARAM_FAST_CHANNEL_RESET,
- + .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR,
- + .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE,
- ++ .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD,
- ++};
- ++
- ++static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = {
- ++ .tx_chain_mask = WMI_10X_PDEV_PARAM_TX_CHAIN_MASK,
- ++ .rx_chain_mask = WMI_10X_PDEV_PARAM_RX_CHAIN_MASK,
- ++ .txpower_limit2g = WMI_10X_PDEV_PARAM_TXPOWER_LIMIT2G,
- ++ .txpower_limit5g = WMI_10X_PDEV_PARAM_TXPOWER_LIMIT5G,
- ++ .txpower_scale = WMI_10X_PDEV_PARAM_TXPOWER_SCALE,
- ++ .beacon_gen_mode = WMI_10X_PDEV_PARAM_BEACON_GEN_MODE,
- ++ .beacon_tx_mode = WMI_10X_PDEV_PARAM_BEACON_TX_MODE,
- ++ .resmgr_offchan_mode = WMI_10X_PDEV_PARAM_RESMGR_OFFCHAN_MODE,
- ++ .protection_mode = WMI_10X_PDEV_PARAM_PROTECTION_MODE,
- ++ .dynamic_bw = WMI_10X_PDEV_PARAM_DYNAMIC_BW,
- ++ .non_agg_sw_retry_th = WMI_10X_PDEV_PARAM_NON_AGG_SW_RETRY_TH,
- ++ .agg_sw_retry_th = WMI_10X_PDEV_PARAM_AGG_SW_RETRY_TH,
- ++ .sta_kickout_th = WMI_10X_PDEV_PARAM_STA_KICKOUT_TH,
- ++ .ac_aggrsize_scaling = WMI_10X_PDEV_PARAM_AC_AGGRSIZE_SCALING,
- ++ .ltr_enable = WMI_10X_PDEV_PARAM_LTR_ENABLE,
- ++ .ltr_ac_latency_be = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BE,
- ++ .ltr_ac_latency_bk = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BK,
- ++ .ltr_ac_latency_vi = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VI,
- ++ .ltr_ac_latency_vo = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VO,
- ++ .ltr_ac_latency_timeout = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT,
- ++ .ltr_sleep_override = WMI_10X_PDEV_PARAM_LTR_SLEEP_OVERRIDE,
- ++ .ltr_rx_override = WMI_10X_PDEV_PARAM_LTR_RX_OVERRIDE,
- ++ .ltr_tx_activity_timeout = WMI_10X_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT,
- ++ .l1ss_enable = WMI_10X_PDEV_PARAM_L1SS_ENABLE,
- ++ .dsleep_enable = WMI_10X_PDEV_PARAM_DSLEEP_ENABLE,
- ++ .pcielp_txbuf_flush = WMI_PDEV_PARAM_UNSUPPORTED,
- ++ .pcielp_txbuf_watermark = WMI_PDEV_PARAM_UNSUPPORTED,
- ++ .pcielp_txbuf_tmo_en = WMI_PDEV_PARAM_UNSUPPORTED,
- ++ .pcielp_txbuf_tmo_value = WMI_PDEV_PARAM_UNSUPPORTED,
- ++ .pdev_stats_update_period = WMI_10X_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD,
- ++ .vdev_stats_update_period = WMI_10X_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD,
- ++ .peer_stats_update_period = WMI_10X_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD,
- ++ .bcnflt_stats_update_period =
- ++ WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
- ++ .pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS,
- ++ .arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE,
- ++ .dcs = WMI_10X_PDEV_PARAM_DCS,
- ++ .ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE,
- ++ .ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD,
- ++ .ani_listen_period = WMI_10X_PDEV_PARAM_ANI_LISTEN_PERIOD,
- ++ .ani_ofdm_level = WMI_10X_PDEV_PARAM_ANI_OFDM_LEVEL,
- ++ .ani_cck_level = WMI_10X_PDEV_PARAM_ANI_CCK_LEVEL,
- ++ .dyntxchain = WMI_10X_PDEV_PARAM_DYNTXCHAIN,
- ++ .proxy_sta = WMI_PDEV_PARAM_UNSUPPORTED,
- ++ .idle_ps_config = WMI_PDEV_PARAM_UNSUPPORTED,
- ++ .power_gating_sleep = WMI_PDEV_PARAM_UNSUPPORTED,
- ++ .fast_channel_reset = WMI_10X_PDEV_PARAM_FAST_CHANNEL_RESET,
- ++ .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR,
- ++ .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE,
- ++ .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD,
- ++};
- ++
- ++/* firmware 10.2 specific mappings */
- ++static struct wmi_cmd_map wmi_10_2_cmd_map = {
- ++ .init_cmdid = WMI_10_2_INIT_CMDID,
- ++ .start_scan_cmdid = WMI_10_2_START_SCAN_CMDID,
- ++ .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID,
- ++ .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID,
- ++ .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
- ++ .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID,
- ++ .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID,
- ++ .pdev_pktlog_enable_cmdid = WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
- ++ .pdev_pktlog_disable_cmdid = WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
- ++ .pdev_set_wmm_params_cmdid = WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
- ++ .pdev_set_ht_cap_ie_cmdid = WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
- ++ .pdev_set_vht_cap_ie_cmdid = WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
- ++ .pdev_set_quiet_mode_cmdid = WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
- ++ .pdev_green_ap_ps_enable_cmdid = WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
- ++ .pdev_get_tpc_config_cmdid = WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
- ++ .pdev_set_base_macaddr_cmdid = WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
- ++ .vdev_create_cmdid = WMI_10_2_VDEV_CREATE_CMDID,
- ++ .vdev_delete_cmdid = WMI_10_2_VDEV_DELETE_CMDID,
- ++ .vdev_start_request_cmdid = WMI_10_2_VDEV_START_REQUEST_CMDID,
- ++ .vdev_restart_request_cmdid = WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
- ++ .vdev_up_cmdid = WMI_10_2_VDEV_UP_CMDID,
- ++ .vdev_stop_cmdid = WMI_10_2_VDEV_STOP_CMDID,
- ++ .vdev_down_cmdid = WMI_10_2_VDEV_DOWN_CMDID,
- ++ .vdev_set_param_cmdid = WMI_10_2_VDEV_SET_PARAM_CMDID,
- ++ .vdev_install_key_cmdid = WMI_10_2_VDEV_INSTALL_KEY_CMDID,
- ++ .peer_create_cmdid = WMI_10_2_PEER_CREATE_CMDID,
- ++ .peer_delete_cmdid = WMI_10_2_PEER_DELETE_CMDID,
- ++ .peer_flush_tids_cmdid = WMI_10_2_PEER_FLUSH_TIDS_CMDID,
- ++ .peer_set_param_cmdid = WMI_10_2_PEER_SET_PARAM_CMDID,
- ++ .peer_assoc_cmdid = WMI_10_2_PEER_ASSOC_CMDID,
- ++ .peer_add_wds_entry_cmdid = WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
- ++ .peer_remove_wds_entry_cmdid = WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
- ++ .peer_mcast_group_cmdid = WMI_10_2_PEER_MCAST_GROUP_CMDID,
- ++ .bcn_tx_cmdid = WMI_10_2_BCN_TX_CMDID,
- ++ .pdev_send_bcn_cmdid = WMI_10_2_PDEV_SEND_BCN_CMDID,
- ++ .bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .bcn_filter_rx_cmdid = WMI_10_2_BCN_FILTER_RX_CMDID,
- ++ .prb_req_filter_rx_cmdid = WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
- ++ .mgmt_tx_cmdid = WMI_10_2_MGMT_TX_CMDID,
- ++ .prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .addba_clear_resp_cmdid = WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
- ++ .addba_send_cmdid = WMI_10_2_ADDBA_SEND_CMDID,
- ++ .addba_status_cmdid = WMI_10_2_ADDBA_STATUS_CMDID,
- ++ .delba_send_cmdid = WMI_10_2_DELBA_SEND_CMDID,
- ++ .addba_set_resp_cmdid = WMI_10_2_ADDBA_SET_RESP_CMDID,
- ++ .send_singleamsdu_cmdid = WMI_10_2_SEND_SINGLEAMSDU_CMDID,
- ++ .sta_powersave_mode_cmdid = WMI_10_2_STA_POWERSAVE_MODE_CMDID,
- ++ .sta_powersave_param_cmdid = WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
- ++ .sta_mimo_ps_mode_cmdid = WMI_10_2_STA_MIMO_PS_MODE_CMDID,
- ++ .pdev_dfs_enable_cmdid = WMI_10_2_PDEV_DFS_ENABLE_CMDID,
- ++ .pdev_dfs_disable_cmdid = WMI_10_2_PDEV_DFS_DISABLE_CMDID,
- ++ .roam_scan_mode = WMI_10_2_ROAM_SCAN_MODE,
- ++ .roam_scan_rssi_threshold = WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
- ++ .roam_scan_period = WMI_10_2_ROAM_SCAN_PERIOD,
- ++ .roam_scan_rssi_change_threshold =
- ++ WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
- ++ .roam_ap_profile = WMI_10_2_ROAM_AP_PROFILE,
- ++ .ofl_scan_add_ap_profile = WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
- ++ .ofl_scan_remove_ap_profile = WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
- ++ .ofl_scan_period = WMI_10_2_OFL_SCAN_PERIOD,
- ++ .p2p_dev_set_device_info = WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
- ++ .p2p_dev_set_discoverability = WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
- ++ .p2p_go_set_beacon_ie = WMI_10_2_P2P_GO_SET_BEACON_IE,
- ++ .p2p_go_set_probe_resp_ie = WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
- ++ .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .ap_ps_peer_param_cmdid = WMI_10_2_AP_PS_PEER_PARAM_CMDID,
- ++ .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .peer_rate_retry_sched_cmdid = WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
- ++ .wlan_profile_trigger_cmdid = WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
- ++ .wlan_profile_set_hist_intvl_cmdid =
- ++ WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
- ++ .wlan_profile_get_profile_data_cmdid =
- ++ WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
- ++ .wlan_profile_enable_profile_id_cmdid =
- ++ WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
- ++ .wlan_profile_list_profile_id_cmdid =
- ++ WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
- ++ .pdev_suspend_cmdid = WMI_10_2_PDEV_SUSPEND_CMDID,
- ++ .pdev_resume_cmdid = WMI_10_2_PDEV_RESUME_CMDID,
- ++ .add_bcn_filter_cmdid = WMI_10_2_ADD_BCN_FILTER_CMDID,
- ++ .rmv_bcn_filter_cmdid = WMI_10_2_RMV_BCN_FILTER_CMDID,
- ++ .wow_add_wake_pattern_cmdid = WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
- ++ .wow_del_wake_pattern_cmdid = WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
- ++ .wow_enable_disable_wake_event_cmdid =
- ++ WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
- ++ .wow_enable_cmdid = WMI_10_2_WOW_ENABLE_CMDID,
- ++ .wow_hostwakeup_from_sleep_cmdid =
- ++ WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
- ++ .rtt_measreq_cmdid = WMI_10_2_RTT_MEASREQ_CMDID,
- ++ .rtt_tsf_cmdid = WMI_10_2_RTT_TSF_CMDID,
- ++ .vdev_spectral_scan_configure_cmdid =
- ++ WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
- ++ .vdev_spectral_scan_enable_cmdid =
- ++ WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
- ++ .request_stats_cmdid = WMI_10_2_REQUEST_STATS_CMDID,
- ++ .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .gtk_offload_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED,
- ++ .echo_cmdid = WMI_10_2_ECHO_CMDID,
- ++ .pdev_utf_cmdid = WMI_10_2_PDEV_UTF_CMDID,
- ++ .dbglog_cfg_cmdid = WMI_10_2_DBGLOG_CFG_CMDID,
- ++ .pdev_qvit_cmdid = WMI_10_2_PDEV_QVIT_CMDID,
- ++ .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED,
- ++ .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID,
- ++ .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
- ++ .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED,
- + };
- +
- ++void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
- ++ const struct wmi_channel_arg *arg)
- ++{
- ++ u32 flags = 0;
- ++
- ++ memset(ch, 0, sizeof(*ch));
- ++
- ++ if (arg->passive)
- ++ flags |= WMI_CHAN_FLAG_PASSIVE;
- ++ if (arg->allow_ibss)
- ++ flags |= WMI_CHAN_FLAG_ADHOC_ALLOWED;
- ++ if (arg->allow_ht)
- ++ flags |= WMI_CHAN_FLAG_ALLOW_HT;
- ++ if (arg->allow_vht)
- ++ flags |= WMI_CHAN_FLAG_ALLOW_VHT;
- ++ if (arg->ht40plus)
- ++ flags |= WMI_CHAN_FLAG_HT40_PLUS;
- ++ if (arg->chan_radar)
- ++ flags |= WMI_CHAN_FLAG_DFS;
- ++
- ++ ch->mhz = __cpu_to_le32(arg->freq);
- ++ ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1);
- ++ ch->band_center_freq2 = 0;
- ++ ch->min_power = arg->min_power;
- ++ ch->max_power = arg->max_power;
- ++ ch->reg_power = arg->max_reg_power;
- ++ ch->antenna_max = arg->max_antenna_gain;
- ++
- ++ /* mode & flags share storage */
- ++ ch->mode = arg->mode;
- ++ ch->flags |= __cpu_to_le32(flags);
- ++}
- ++
- + int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
- + {
- + int ret;
- ++
- + ret = wait_for_completion_timeout(&ar->wmi.service_ready,
- + WMI_SERVICE_READY_TIMEOUT_HZ);
- + return ret;
- +@@ -498,23 +894,24 @@ int ath10k_wmi_wait_for_service_ready(st
- + int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar)
- + {
- + int ret;
- ++
- + ret = wait_for_completion_timeout(&ar->wmi.unified_ready,
- + WMI_UNIFIED_READY_TIMEOUT_HZ);
- + return ret;
- + }
- +
- +-static struct sk_buff *ath10k_wmi_alloc_skb(u32 len)
- ++struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len)
- + {
- + struct sk_buff *skb;
- + u32 round_len = roundup(len, 4);
- +
- +- skb = ath10k_htc_alloc_skb(WMI_SKB_HEADROOM + round_len);
- ++ skb = ath10k_htc_alloc_skb(ar, WMI_SKB_HEADROOM + round_len);
- + if (!skb)
- + return NULL;
- +
- + skb_reserve(skb, WMI_SKB_HEADROOM);
- + if (!IS_ALIGNED((unsigned long)skb->data, 4))
- +- ath10k_warn("Unaligned WMI skb\n");
- ++ ath10k_warn(ar, "Unaligned WMI skb\n");
- +
- + skb_put(skb, round_len);
- + memset(skb->data, 0, round_len);
- +@@ -527,8 +924,8 @@ static void ath10k_wmi_htc_tx_complete(s
- + dev_kfree_skb(skb);
- + }
- +
- +-static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
- +- u32 cmd_id)
- ++int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
- ++ u32 cmd_id)
- + {
- + struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
- + struct wmi_cmd_hdr *cmd_hdr;
- +@@ -545,7 +942,7 @@ static int ath10k_wmi_cmd_send_nowait(st
- +
- + memset(skb_cb, 0, sizeof(*skb_cb));
- + ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb);
- +- trace_ath10k_wmi_cmd(cmd_id, skb->data, skb->len, ret);
- ++ trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len, ret);
- +
- + if (ret)
- + goto err_pull;
- +@@ -559,23 +956,45 @@ err_pull:
- +
- + static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
- + {
- ++ struct ath10k *ar = arvif->ar;
- ++ struct ath10k_skb_cb *cb;
- ++ struct sk_buff *bcn;
- + int ret;
- +
- +- lockdep_assert_held(&arvif->ar->data_lock);
- ++ spin_lock_bh(&ar->data_lock);
- +
- +- if (arvif->beacon == NULL)
- +- return;
- ++ bcn = arvif->beacon;
- +
- +- if (arvif->beacon_sent)
- +- return;
- ++ if (!bcn)
- ++ goto unlock;
- +
- +- ret = ath10k_wmi_beacon_send_ref_nowait(arvif);
- +- if (ret)
- +- return;
- ++ cb = ATH10K_SKB_CB(bcn);
- ++
- ++ switch (arvif->beacon_state) {
- ++ case ATH10K_BEACON_SENDING:
- ++ case ATH10K_BEACON_SENT:
- ++ break;
- ++ case ATH10K_BEACON_SCHEDULED:
- ++ arvif->beacon_state = ATH10K_BEACON_SENDING;
- ++ spin_unlock_bh(&ar->data_lock);
- ++
- ++ ret = ath10k_wmi_beacon_send_ref_nowait(arvif->ar,
- ++ arvif->vdev_id,
- ++ bcn->data, bcn->len,
- ++ cb->paddr,
- ++ cb->bcn.dtim_zero,
- ++ cb->bcn.deliver_cab);
- ++
- ++ spin_lock_bh(&ar->data_lock);
- +
- +- /* We need to retain the arvif->beacon reference for DMA unmapping and
- +- * freeing the skbuff later. */
- +- arvif->beacon_sent = true;
- ++ if (ret == 0)
- ++ arvif->beacon_state = ATH10K_BEACON_SENT;
- ++ else
- ++ arvif->beacon_state = ATH10K_BEACON_SCHEDULED;
- ++ }
- ++
- ++unlock:
- ++ spin_unlock_bh(&ar->data_lock);
- + }
- +
- + static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac,
- +@@ -588,12 +1007,10 @@ static void ath10k_wmi_tx_beacons_iter(v
- +
- + static void ath10k_wmi_tx_beacons_nowait(struct ath10k *ar)
- + {
- +- spin_lock_bh(&ar->data_lock);
- + ieee80211_iterate_active_interfaces_atomic(ar->hw,
- + IEEE80211_IFACE_ITER_NORMAL,
- + ath10k_wmi_tx_beacons_iter,
- + NULL);
- +- spin_unlock_bh(&ar->data_lock);
- + }
- +
- + static void ath10k_wmi_op_ep_tx_credits(struct ath10k *ar)
- +@@ -604,15 +1021,14 @@ static void ath10k_wmi_op_ep_tx_credits(
- + wake_up(&ar->wmi.tx_credits_wq);
- + }
- +
- +-static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,
- +- u32 cmd_id)
- ++int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
- + {
- + int ret = -EOPNOTSUPP;
- +
- + might_sleep();
- +
- + if (cmd_id == WMI_CMD_UNSUPPORTED) {
- +- ath10k_warn("wmi command %d is not supported by firmware\n",
- ++ ath10k_warn(ar, "wmi command %d is not supported by firmware\n",
- + cmd_id);
- + return ret;
- + }
- +@@ -622,6 +1038,10 @@ static int ath10k_wmi_cmd_send(struct at
- + ath10k_wmi_tx_beacons_nowait(ar);
- +
- + ret = ath10k_wmi_cmd_send_nowait(ar, skb, cmd_id);
- ++
- ++ if (ret && test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
- ++ ret = -ESHUTDOWN;
- ++
- + (ret != -EAGAIN);
- + }), 3*HZ);
- +
- +@@ -631,147 +1051,270 @@ static int ath10k_wmi_cmd_send(struct at
- + return ret;
- + }
- +
- +-int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
- + {
- +- int ret = 0;
- + struct wmi_mgmt_tx_cmd *cmd;
- + struct ieee80211_hdr *hdr;
- +- struct sk_buff *wmi_skb;
- +- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- ++ struct sk_buff *skb;
- + int len;
- ++ u32 buf_len = msdu->len;
- + u16 fc;
- +
- +- hdr = (struct ieee80211_hdr *)skb->data;
- ++ hdr = (struct ieee80211_hdr *)msdu->data;
- + fc = le16_to_cpu(hdr->frame_control);
- +
- + if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control)))
- +- return -EINVAL;
- ++ return ERR_PTR(-EINVAL);
- ++
- ++ len = sizeof(cmd->hdr) + msdu->len;
- ++
- ++ if ((ieee80211_is_action(hdr->frame_control) ||
- ++ ieee80211_is_deauth(hdr->frame_control) ||
- ++ ieee80211_is_disassoc(hdr->frame_control)) &&
- ++ ieee80211_has_protected(hdr->frame_control)) {
- ++ len += IEEE80211_CCMP_MIC_LEN;
- ++ buf_len += IEEE80211_CCMP_MIC_LEN;
- ++ }
- +
- +- len = sizeof(cmd->hdr) + skb->len;
- + len = round_up(len, 4);
- +
- +- wmi_skb = ath10k_wmi_alloc_skb(len);
- +- if (!wmi_skb)
- +- return -ENOMEM;
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- +
- +- cmd = (struct wmi_mgmt_tx_cmd *)wmi_skb->data;
- ++ cmd = (struct wmi_mgmt_tx_cmd *)skb->data;
- +
- +- cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(skb)->vdev_id);
- ++ cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(msdu)->vdev_id);
- + cmd->hdr.tx_rate = 0;
- + cmd->hdr.tx_power = 0;
- +- cmd->hdr.buf_len = __cpu_to_le32((u32)(skb->len));
- ++ cmd->hdr.buf_len = __cpu_to_le32(buf_len);
- +
- +- memcpy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr), ETH_ALEN);
- +- memcpy(cmd->buf, skb->data, skb->len);
- ++ ether_addr_copy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr));
- ++ memcpy(cmd->buf, msdu->data, msdu->len);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
- +- wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
- ++ msdu, skb->len, fc & IEEE80211_FCTL_FTYPE,
- + fc & IEEE80211_FCTL_STYPE);
- ++ trace_ath10k_tx_hdr(ar, skb->data, skb->len);
- ++ trace_ath10k_tx_payload(ar, skb->data, skb->len);
- +
- +- /* Send the management frame buffer to the target */
- +- ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid);
- +- if (ret)
- +- return ret;
- +-
- +- /* TODO: report tx status to mac80211 - temporary just ACK */
- +- info->flags |= IEEE80211_TX_STAT_ACK;
- +- ieee80211_tx_status_irqsafe(ar->hw, skb);
- +-
- +- return ret;
- ++ return skb;
- + }
- +
- +-static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
- ++static void ath10k_wmi_event_scan_started(struct ath10k *ar)
- + {
- +- struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data;
- +- enum wmi_scan_event_type event_type;
- +- enum wmi_scan_completion_reason reason;
- +- u32 freq;
- +- u32 req_id;
- +- u32 scan_id;
- +- u32 vdev_id;
- +-
- +- event_type = __le32_to_cpu(event->event_type);
- +- reason = __le32_to_cpu(event->reason);
- +- freq = __le32_to_cpu(event->channel_freq);
- +- req_id = __le32_to_cpu(event->scan_req_id);
- +- scan_id = __le32_to_cpu(event->scan_id);
- +- vdev_id = __le32_to_cpu(event->vdev_id);
- +-
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENTID\n");
- +- ath10k_dbg(ATH10K_DBG_WMI,
- +- "scan event type %d reason %d freq %d req_id %d "
- +- "scan_id %d vdev_id %d\n",
- +- event_type, reason, freq, req_id, scan_id, vdev_id);
- ++ lockdep_assert_held(&ar->data_lock);
- +
- +- spin_lock_bh(&ar->data_lock);
- ++ switch (ar->scan.state) {
- ++ case ATH10K_SCAN_IDLE:
- ++ case ATH10K_SCAN_RUNNING:
- ++ case ATH10K_SCAN_ABORTING:
- ++ ath10k_warn(ar, "received scan started event in an invalid scan state: %s (%d)\n",
- ++ ath10k_scan_state_str(ar->scan.state),
- ++ ar->scan.state);
- ++ break;
- ++ case ATH10K_SCAN_STARTING:
- ++ ar->scan.state = ATH10K_SCAN_RUNNING;
- +
- +- switch (event_type) {
- +- case WMI_SCAN_EVENT_STARTED:
- +- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_STARTED\n");
- +- if (ar->scan.in_progress && ar->scan.is_roc)
- ++ if (ar->scan.is_roc)
- + ieee80211_ready_on_channel(ar->hw);
- +
- + complete(&ar->scan.started);
- + break;
- +- case WMI_SCAN_EVENT_COMPLETED:
- +- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_COMPLETED\n");
- +- switch (reason) {
- +- case WMI_SCAN_REASON_COMPLETED:
- +- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_COMPLETED\n");
- +- break;
- +- case WMI_SCAN_REASON_CANCELLED:
- +- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_CANCELED\n");
- +- break;
- +- case WMI_SCAN_REASON_PREEMPTED:
- +- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_PREEMPTED\n");
- +- break;
- +- case WMI_SCAN_REASON_TIMEDOUT:
- +- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_TIMEDOUT\n");
- +- break;
- +- default:
- +- break;
- +- }
- +-
- +- ar->scan_channel = NULL;
- +- if (!ar->scan.in_progress) {
- +- ath10k_warn("no scan requested, ignoring\n");
- +- break;
- +- }
- +-
- +- if (ar->scan.is_roc) {
- +- ath10k_offchan_tx_purge(ar);
- ++ }
- ++}
- +
- +- if (!ar->scan.aborting)
- +- ieee80211_remain_on_channel_expired(ar->hw);
- +- } else {
- +- ieee80211_scan_completed(ar->hw, ar->scan.aborting);
- +- }
- ++static void ath10k_wmi_event_scan_start_failed(struct ath10k *ar)
- ++{
- ++ lockdep_assert_held(&ar->data_lock);
- +
- +- del_timer(&ar->scan.timeout);
- +- complete_all(&ar->scan.completed);
- +- ar->scan.in_progress = false;
- ++ switch (ar->scan.state) {
- ++ case ATH10K_SCAN_IDLE:
- ++ case ATH10K_SCAN_RUNNING:
- ++ case ATH10K_SCAN_ABORTING:
- ++ ath10k_warn(ar, "received scan start failed event in an invalid scan state: %s (%d)\n",
- ++ ath10k_scan_state_str(ar->scan.state),
- ++ ar->scan.state);
- + break;
- +- case WMI_SCAN_EVENT_BSS_CHANNEL:
- +- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_BSS_CHANNEL\n");
- +- ar->scan_channel = NULL;
- ++ case ATH10K_SCAN_STARTING:
- ++ complete(&ar->scan.started);
- ++ __ath10k_scan_finish(ar);
- + break;
- +- case WMI_SCAN_EVENT_FOREIGN_CHANNEL:
- +- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_FOREIGN_CHANNEL\n");
- ++ }
- ++}
- ++
- ++static void ath10k_wmi_event_scan_completed(struct ath10k *ar)
- ++{
- ++ lockdep_assert_held(&ar->data_lock);
- ++
- ++ switch (ar->scan.state) {
- ++ case ATH10K_SCAN_IDLE:
- ++ case ATH10K_SCAN_STARTING:
- ++ /* One suspected reason scan can be completed while starting is
- ++ * if firmware fails to deliver all scan events to the host,
- ++ * e.g. when transport pipe is full. This has been observed
- ++ * with spectral scan phyerr events starving wmi transport
- ++ * pipe. In such case the "scan completed" event should be (and
- ++ * is) ignored by the host as it may be just firmware's scan
- ++ * state machine recovering.
- ++ */
- ++ ath10k_warn(ar, "received scan completed event in an invalid scan state: %s (%d)\n",
- ++ ath10k_scan_state_str(ar->scan.state),
- ++ ar->scan.state);
- ++ break;
- ++ case ATH10K_SCAN_RUNNING:
- ++ case ATH10K_SCAN_ABORTING:
- ++ __ath10k_scan_finish(ar);
- ++ break;
- ++ }
- ++}
- ++
- ++static void ath10k_wmi_event_scan_bss_chan(struct ath10k *ar)
- ++{
- ++ lockdep_assert_held(&ar->data_lock);
- ++
- ++ switch (ar->scan.state) {
- ++ case ATH10K_SCAN_IDLE:
- ++ case ATH10K_SCAN_STARTING:
- ++ ath10k_warn(ar, "received scan bss chan event in an invalid scan state: %s (%d)\n",
- ++ ath10k_scan_state_str(ar->scan.state),
- ++ ar->scan.state);
- ++ break;
- ++ case ATH10K_SCAN_RUNNING:
- ++ case ATH10K_SCAN_ABORTING:
- ++ ar->scan_channel = NULL;
- ++ break;
- ++ }
- ++}
- ++
- ++static void ath10k_wmi_event_scan_foreign_chan(struct ath10k *ar, u32 freq)
- ++{
- ++ lockdep_assert_held(&ar->data_lock);
- ++
- ++ switch (ar->scan.state) {
- ++ case ATH10K_SCAN_IDLE:
- ++ case ATH10K_SCAN_STARTING:
- ++ ath10k_warn(ar, "received scan foreign chan event in an invalid scan state: %s (%d)\n",
- ++ ath10k_scan_state_str(ar->scan.state),
- ++ ar->scan.state);
- ++ break;
- ++ case ATH10K_SCAN_RUNNING:
- ++ case ATH10K_SCAN_ABORTING:
- + ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
- +- if (ar->scan.in_progress && ar->scan.is_roc &&
- +- ar->scan.roc_freq == freq) {
- ++
- ++ if (ar->scan.is_roc && ar->scan.roc_freq == freq)
- + complete(&ar->scan.on_channel);
- +- }
- + break;
- ++ }
- ++}
- ++
- ++static const char *
- ++ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type,
- ++ enum wmi_scan_completion_reason reason)
- ++{
- ++ switch (type) {
- ++ case WMI_SCAN_EVENT_STARTED:
- ++ return "started";
- ++ case WMI_SCAN_EVENT_COMPLETED:
- ++ switch (reason) {
- ++ case WMI_SCAN_REASON_COMPLETED:
- ++ return "completed";
- ++ case WMI_SCAN_REASON_CANCELLED:
- ++ return "completed [cancelled]";
- ++ case WMI_SCAN_REASON_PREEMPTED:
- ++ return "completed [preempted]";
- ++ case WMI_SCAN_REASON_TIMEDOUT:
- ++ return "completed [timedout]";
- ++ case WMI_SCAN_REASON_MAX:
- ++ break;
- ++ }
- ++ return "completed [unknown]";
- ++ case WMI_SCAN_EVENT_BSS_CHANNEL:
- ++ return "bss channel";
- ++ case WMI_SCAN_EVENT_FOREIGN_CHANNEL:
- ++ return "foreign channel";
- + case WMI_SCAN_EVENT_DEQUEUED:
- +- ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_DEQUEUED\n");
- +- break;
- ++ return "dequeued";
- + case WMI_SCAN_EVENT_PREEMPTED:
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_PREEMPTED\n");
- ++ return "preempted";
- ++ case WMI_SCAN_EVENT_START_FAILED:
- ++ return "start failed";
- ++ default:
- ++ return "unknown";
- ++ }
- ++}
- ++
- ++static int ath10k_wmi_op_pull_scan_ev(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_scan_ev_arg *arg)
- ++{
- ++ struct wmi_scan_event *ev = (void *)skb->data;
- ++
- ++ if (skb->len < sizeof(*ev))
- ++ return -EPROTO;
- ++
- ++ skb_pull(skb, sizeof(*ev));
- ++ arg->event_type = ev->event_type;
- ++ arg->reason = ev->reason;
- ++ arg->channel_freq = ev->channel_freq;
- ++ arg->scan_req_id = ev->scan_req_id;
- ++ arg->scan_id = ev->scan_id;
- ++ arg->vdev_id = ev->vdev_id;
- ++
- ++ return 0;
- ++}
- ++
- ++int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
- ++{
- ++ struct wmi_scan_ev_arg arg = {};
- ++ enum wmi_scan_event_type event_type;
- ++ enum wmi_scan_completion_reason reason;
- ++ u32 freq;
- ++ u32 req_id;
- ++ u32 scan_id;
- ++ u32 vdev_id;
- ++ int ret;
- ++
- ++ ret = ath10k_wmi_pull_scan(ar, skb, &arg);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to parse scan event: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ event_type = __le32_to_cpu(arg.event_type);
- ++ reason = __le32_to_cpu(arg.reason);
- ++ freq = __le32_to_cpu(arg.channel_freq);
- ++ req_id = __le32_to_cpu(arg.scan_req_id);
- ++ scan_id = __le32_to_cpu(arg.scan_id);
- ++ vdev_id = __le32_to_cpu(arg.vdev_id);
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "scan event %s type %d reason %d freq %d req_id %d scan_id %d vdev_id %d state %s (%d)\n",
- ++ ath10k_wmi_event_scan_type_str(event_type, reason),
- ++ event_type, reason, freq, req_id, scan_id, vdev_id,
- ++ ath10k_scan_state_str(ar->scan.state), ar->scan.state);
- ++
- ++ switch (event_type) {
- ++ case WMI_SCAN_EVENT_STARTED:
- ++ ath10k_wmi_event_scan_started(ar);
- ++ break;
- ++ case WMI_SCAN_EVENT_COMPLETED:
- ++ ath10k_wmi_event_scan_completed(ar);
- ++ break;
- ++ case WMI_SCAN_EVENT_BSS_CHANNEL:
- ++ ath10k_wmi_event_scan_bss_chan(ar);
- ++ break;
- ++ case WMI_SCAN_EVENT_FOREIGN_CHANNEL:
- ++ ath10k_wmi_event_scan_foreign_chan(ar, freq);
- + break;
- + case WMI_SCAN_EVENT_START_FAILED:
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_START_FAILED\n");
- ++ ath10k_warn(ar, "received scan start failure event\n");
- ++ ath10k_wmi_event_scan_start_failed(ar);
- + break;
- ++ case WMI_SCAN_EVENT_DEQUEUED:
- ++ case WMI_SCAN_EVENT_PREEMPTED:
- + default:
- + break;
- + }
- +@@ -865,13 +1408,86 @@ static inline u8 get_rate_idx(u32 rate,
- + return rate_idx;
- + }
- +
- +-static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
- ++/* If keys are configured, HW decrypts all frames
- ++ * with protected bit set. Mark such frames as decrypted.
- ++ */
- ++static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct ieee80211_rx_status *status)
- ++{
- ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- ++ unsigned int hdrlen;
- ++ bool peer_key;
- ++ u8 *addr, keyidx;
- ++
- ++ if (!ieee80211_is_auth(hdr->frame_control) ||
- ++ !ieee80211_has_protected(hdr->frame_control))
- ++ return;
- ++
- ++ hdrlen = ieee80211_hdrlen(hdr->frame_control);
- ++ if (skb->len < (hdrlen + IEEE80211_WEP_IV_LEN))
- ++ return;
- ++
- ++ keyidx = skb->data[hdrlen + (IEEE80211_WEP_IV_LEN - 1)] >> WEP_KEYID_SHIFT;
- ++ addr = ieee80211_get_SA(hdr);
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++ peer_key = ath10k_mac_is_peer_wep_key_set(ar, addr, keyidx);
- ++ spin_unlock_bh(&ar->data_lock);
- ++
- ++ if (peer_key) {
- ++ ath10k_dbg(ar, ATH10K_DBG_MAC,
- ++ "mac wep key present for peer %pM\n", addr);
- ++ status->flag |= RX_FLAG_DECRYPTED;
- ++ }
- ++}
- ++
- ++static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_mgmt_rx_ev_arg *arg)
- + {
- + struct wmi_mgmt_rx_event_v1 *ev_v1;
- + struct wmi_mgmt_rx_event_v2 *ev_v2;
- + struct wmi_mgmt_rx_hdr_v1 *ev_hdr;
- ++ size_t pull_len;
- ++ u32 msdu_len;
- ++
- ++ if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) {
- ++ ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data;
- ++ ev_hdr = &ev_v2->hdr.v1;
- ++ pull_len = sizeof(*ev_v2);
- ++ } else {
- ++ ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data;
- ++ ev_hdr = &ev_v1->hdr;
- ++ pull_len = sizeof(*ev_v1);
- ++ }
- ++
- ++ if (skb->len < pull_len)
- ++ return -EPROTO;
- ++
- ++ skb_pull(skb, pull_len);
- ++ arg->channel = ev_hdr->channel;
- ++ arg->buf_len = ev_hdr->buf_len;
- ++ arg->status = ev_hdr->status;
- ++ arg->snr = ev_hdr->snr;
- ++ arg->phy_mode = ev_hdr->phy_mode;
- ++ arg->rate = ev_hdr->rate;
- ++
- ++ msdu_len = __le32_to_cpu(arg->buf_len);
- ++ if (skb->len < msdu_len)
- ++ return -EPROTO;
- ++
- ++ /* the WMI buffer might've ended up being padded to 4 bytes due to HTC
- ++ * trailer with credit update. Trim the excess garbage.
- ++ */
- ++ skb_trim(skb, msdu_len);
- ++
- ++ return 0;
- ++}
- ++
- ++int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
- ++{
- ++ struct wmi_mgmt_rx_ev_arg arg = {};
- + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
- +- struct ieee80211_channel *ch;
- + struct ieee80211_hdr *hdr;
- + u32 rx_status;
- + u32 channel;
- +@@ -880,28 +1496,24 @@ static int ath10k_wmi_event_mgmt_rx(stru
- + u32 rate;
- + u32 buf_len;
- + u16 fc;
- +- int pull_len;
- ++ int ret;
- +
- +- if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) {
- +- ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data;
- +- ev_hdr = &ev_v2->hdr.v1;
- +- pull_len = sizeof(*ev_v2);
- +- } else {
- +- ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data;
- +- ev_hdr = &ev_v1->hdr;
- +- pull_len = sizeof(*ev_v1);
- ++ ret = ath10k_wmi_pull_mgmt_rx(ar, skb, &arg);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to parse mgmt rx event: %d\n", ret);
- ++ return ret;
- + }
- +
- +- channel = __le32_to_cpu(ev_hdr->channel);
- +- buf_len = __le32_to_cpu(ev_hdr->buf_len);
- +- rx_status = __le32_to_cpu(ev_hdr->status);
- +- snr = __le32_to_cpu(ev_hdr->snr);
- +- phy_mode = __le32_to_cpu(ev_hdr->phy_mode);
- +- rate = __le32_to_cpu(ev_hdr->rate);
- ++ channel = __le32_to_cpu(arg.channel);
- ++ buf_len = __le32_to_cpu(arg.buf_len);
- ++ rx_status = __le32_to_cpu(arg.status);
- ++ snr = __le32_to_cpu(arg.snr);
- ++ phy_mode = __le32_to_cpu(arg.phy_mode);
- ++ rate = __le32_to_cpu(arg.rate);
- +
- + memset(status, 0, sizeof(*status));
- +
- +- ath10k_dbg(ATH10K_DBG_MGMT,
- ++ ath10k_dbg(ar, ATH10K_DBG_MGMT,
- + "event mgmt rx status %08x\n", rx_status);
- +
- + if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) {
- +@@ -919,66 +1531,70 @@ static int ath10k_wmi_event_mgmt_rx(stru
- + return 0;
- + }
- +
- +- if (rx_status & WMI_RX_STATUS_ERR_CRC)
- +- status->flag |= RX_FLAG_FAILED_FCS_CRC;
- ++ if (rx_status & WMI_RX_STATUS_ERR_CRC) {
- ++ dev_kfree_skb(skb);
- ++ return 0;
- ++ }
- ++
- + if (rx_status & WMI_RX_STATUS_ERR_MIC)
- + status->flag |= RX_FLAG_MMIC_ERROR;
- +
- +- /* HW can Rx CCK rates on 5GHz. In that case phy_mode is set to
- ++ /* Hardware can Rx CCK rates on 5GHz. In that case phy_mode is set to
- + * MODE_11B. This means phy_mode is not a reliable source for the band
- +- * of mgmt rx. */
- +-
- +- ch = ar->scan_channel;
- +- if (!ch)
- +- ch = ar->rx_channel;
- +-
- +- if (ch) {
- +- status->band = ch->band;
- +-
- +- if (phy_mode == MODE_11B &&
- +- status->band == IEEE80211_BAND_5GHZ)
- +- ath10k_dbg(ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
- ++ * of mgmt rx.
- ++ */
- ++ if (channel >= 1 && channel <= 14) {
- ++ status->band = IEEE80211_BAND_2GHZ;
- ++ } else if (channel >= 36 && channel <= 165) {
- ++ status->band = IEEE80211_BAND_5GHZ;
- + } else {
- +- ath10k_warn("using (unreliable) phy_mode to extract band for mgmt rx\n");
- +- status->band = phy_mode_to_band(phy_mode);
- ++ /* Shouldn't happen unless list of advertised channels to
- ++ * mac80211 has been changed.
- ++ */
- ++ WARN_ON_ONCE(1);
- ++ dev_kfree_skb(skb);
- ++ return 0;
- + }
- +
- ++ if (phy_mode == MODE_11B && status->band == IEEE80211_BAND_5GHZ)
- ++ ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
- ++
- + status->freq = ieee80211_channel_to_frequency(channel, status->band);
- + status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR;
- + status->rate_idx = get_rate_idx(rate, status->band);
- +
- +- skb_pull(skb, pull_len);
- +-
- + hdr = (struct ieee80211_hdr *)skb->data;
- + fc = le16_to_cpu(hdr->frame_control);
- +
- ++ ath10k_wmi_handle_wep_reauth(ar, skb, status);
- ++
- + /* FW delivers WEP Shared Auth frame with Protected Bit set and
- + * encrypted payload. However in case of PMF it delivers decrypted
- + * frames with Protected Bit set. */
- + if (ieee80211_has_protected(hdr->frame_control) &&
- + !ieee80211_is_auth(hdr->frame_control)) {
- +- status->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED |
- +- RX_FLAG_MMIC_STRIPPED;
- +- hdr->frame_control = __cpu_to_le16(fc &
- ++ status->flag |= RX_FLAG_DECRYPTED;
- ++
- ++ if (!ieee80211_is_action(hdr->frame_control) &&
- ++ !ieee80211_is_deauth(hdr->frame_control) &&
- ++ !ieee80211_is_disassoc(hdr->frame_control)) {
- ++ status->flag |= RX_FLAG_IV_STRIPPED |
- ++ RX_FLAG_MMIC_STRIPPED;
- ++ hdr->frame_control = __cpu_to_le16(fc &
- + ~IEEE80211_FCTL_PROTECTED);
- ++ }
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_MGMT,
- ++ ath10k_dbg(ar, ATH10K_DBG_MGMT,
- + "event mgmt rx skb %p len %d ftype %02x stype %02x\n",
- + skb, skb->len,
- + fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE);
- +
- +- ath10k_dbg(ATH10K_DBG_MGMT,
- ++ ath10k_dbg(ar, ATH10K_DBG_MGMT,
- + "event mgmt rx freq %d band %d snr %d, rate_idx %d\n",
- + status->freq, status->band, status->signal,
- + status->rate_idx);
- +
- +- /*
- +- * packets from HTC come aligned to 4byte boundaries
- +- * because they can originally come in along with a trailer
- +- */
- +- skb_trim(skb, buf_len);
- +-
- + ieee80211_rx(ar->hw, skb);
- + return 0;
- + }
- +@@ -1002,37 +1618,65 @@ exit:
- + return idx;
- + }
- +
- +-static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
- ++static int ath10k_wmi_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_ch_info_ev_arg *arg)
- ++{
- ++ struct wmi_chan_info_event *ev = (void *)skb->data;
- ++
- ++ if (skb->len < sizeof(*ev))
- ++ return -EPROTO;
- ++
- ++ skb_pull(skb, sizeof(*ev));
- ++ arg->err_code = ev->err_code;
- ++ arg->freq = ev->freq;
- ++ arg->cmd_flags = ev->cmd_flags;
- ++ arg->noise_floor = ev->noise_floor;
- ++ arg->rx_clear_count = ev->rx_clear_count;
- ++ arg->cycle_count = ev->cycle_count;
- ++
- ++ return 0;
- ++}
- ++
- ++void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- struct wmi_chan_info_event *ev;
- ++ struct wmi_ch_info_ev_arg arg = {};
- + struct survey_info *survey;
- + u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count;
- +- int idx;
- ++ int idx, ret;
- +
- +- ev = (struct wmi_chan_info_event *)skb->data;
- ++ ret = ath10k_wmi_pull_ch_info(ar, skb, &arg);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to parse chan info event: %d\n", ret);
- ++ return;
- ++ }
- +
- +- err_code = __le32_to_cpu(ev->err_code);
- +- freq = __le32_to_cpu(ev->freq);
- +- cmd_flags = __le32_to_cpu(ev->cmd_flags);
- +- noise_floor = __le32_to_cpu(ev->noise_floor);
- +- rx_clear_count = __le32_to_cpu(ev->rx_clear_count);
- +- cycle_count = __le32_to_cpu(ev->cycle_count);
- ++ err_code = __le32_to_cpu(arg.err_code);
- ++ freq = __le32_to_cpu(arg.freq);
- ++ cmd_flags = __le32_to_cpu(arg.cmd_flags);
- ++ noise_floor = __le32_to_cpu(arg.noise_floor);
- ++ rx_clear_count = __le32_to_cpu(arg.rx_clear_count);
- ++ cycle_count = __le32_to_cpu(arg.cycle_count);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n",
- + err_code, freq, cmd_flags, noise_floor, rx_clear_count,
- + cycle_count);
- +
- + spin_lock_bh(&ar->data_lock);
- +
- +- if (!ar->scan.in_progress) {
- +- ath10k_warn("chan info event without a scan request?\n");
- ++ switch (ar->scan.state) {
- ++ case ATH10K_SCAN_IDLE:
- ++ case ATH10K_SCAN_STARTING:
- ++ ath10k_warn(ar, "received chan info event without a scan request, ignoring\n");
- + goto exit;
- ++ case ATH10K_SCAN_RUNNING:
- ++ case ATH10K_SCAN_ABORTING:
- ++ break;
- + }
- +
- + idx = freq_to_idx(ar, freq);
- + if (idx >= ARRAY_SIZE(ar->survey)) {
- +- ath10k_warn("chan info: invalid frequency %d (idx %d out of bounds)\n",
- ++ ath10k_warn(ar, "chan info: invalid frequency %d (idx %d out of bounds)\n",
- + freq, idx);
- + goto exit;
- + }
- +@@ -1061,191 +1705,579 @@ exit:
- + spin_unlock_bh(&ar->data_lock);
- + }
- +
- +-static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
- ++void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
- + }
- +
- +-static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
- ++int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
- + skb->len);
- +
- +- trace_ath10k_wmi_dbglog(skb->data, skb->len);
- ++ trace_ath10k_wmi_dbglog(ar, skb->data, skb->len);
- +
- + return 0;
- + }
- +
- +-static void ath10k_wmi_event_update_stats(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src,
- ++ struct ath10k_fw_stats_pdev *dst)
- + {
- +- struct wmi_stats_event *ev = (struct wmi_stats_event *)skb->data;
- +-
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
- +-
- +- ath10k_debug_read_target_stats(ar, ev);
- +-}
- +-
- +-static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++ dst->ch_noise_floor = __le32_to_cpu(src->chan_nf);
- ++ dst->tx_frame_count = __le32_to_cpu(src->tx_frame_count);
- ++ dst->rx_frame_count = __le32_to_cpu(src->rx_frame_count);
- ++ dst->rx_clear_count = __le32_to_cpu(src->rx_clear_count);
- ++ dst->cycle_count = __le32_to_cpu(src->cycle_count);
- ++ dst->phy_err_count = __le32_to_cpu(src->phy_err_count);
- ++ dst->chan_tx_power = __le32_to_cpu(src->chan_tx_pwr);
- ++}
- ++
- ++void ath10k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src,
- ++ struct ath10k_fw_stats_pdev *dst)
- ++{
- ++ dst->comp_queued = __le32_to_cpu(src->comp_queued);
- ++ dst->comp_delivered = __le32_to_cpu(src->comp_delivered);
- ++ dst->msdu_enqued = __le32_to_cpu(src->msdu_enqued);
- ++ dst->mpdu_enqued = __le32_to_cpu(src->mpdu_enqued);
- ++ dst->wmm_drop = __le32_to_cpu(src->wmm_drop);
- ++ dst->local_enqued = __le32_to_cpu(src->local_enqued);
- ++ dst->local_freed = __le32_to_cpu(src->local_freed);
- ++ dst->hw_queued = __le32_to_cpu(src->hw_queued);
- ++ dst->hw_reaped = __le32_to_cpu(src->hw_reaped);
- ++ dst->underrun = __le32_to_cpu(src->underrun);
- ++ dst->tx_abort = __le32_to_cpu(src->tx_abort);
- ++ dst->mpdus_requed = __le32_to_cpu(src->mpdus_requed);
- ++ dst->tx_ko = __le32_to_cpu(src->tx_ko);
- ++ dst->data_rc = __le32_to_cpu(src->data_rc);
- ++ dst->self_triggers = __le32_to_cpu(src->self_triggers);
- ++ dst->sw_retry_failure = __le32_to_cpu(src->sw_retry_failure);
- ++ dst->illgl_rate_phy_err = __le32_to_cpu(src->illgl_rate_phy_err);
- ++ dst->pdev_cont_xretry = __le32_to_cpu(src->pdev_cont_xretry);
- ++ dst->pdev_tx_timeout = __le32_to_cpu(src->pdev_tx_timeout);
- ++ dst->pdev_resets = __le32_to_cpu(src->pdev_resets);
- ++ dst->phy_underrun = __le32_to_cpu(src->phy_underrun);
- ++ dst->txop_ovf = __le32_to_cpu(src->txop_ovf);
- ++}
- ++
- ++void ath10k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src,
- ++ struct ath10k_fw_stats_pdev *dst)
- ++{
- ++ dst->mid_ppdu_route_change = __le32_to_cpu(src->mid_ppdu_route_change);
- ++ dst->status_rcvd = __le32_to_cpu(src->status_rcvd);
- ++ dst->r0_frags = __le32_to_cpu(src->r0_frags);
- ++ dst->r1_frags = __le32_to_cpu(src->r1_frags);
- ++ dst->r2_frags = __le32_to_cpu(src->r2_frags);
- ++ dst->r3_frags = __le32_to_cpu(src->r3_frags);
- ++ dst->htt_msdus = __le32_to_cpu(src->htt_msdus);
- ++ dst->htt_mpdus = __le32_to_cpu(src->htt_mpdus);
- ++ dst->loc_msdus = __le32_to_cpu(src->loc_msdus);
- ++ dst->loc_mpdus = __le32_to_cpu(src->loc_mpdus);
- ++ dst->oversize_amsdu = __le32_to_cpu(src->oversize_amsdu);
- ++ dst->phy_errs = __le32_to_cpu(src->phy_errs);
- ++ dst->phy_err_drop = __le32_to_cpu(src->phy_err_drop);
- ++ dst->mpdu_errs = __le32_to_cpu(src->mpdu_errs);
- ++}
- ++
- ++void ath10k_wmi_pull_pdev_stats_extra(const struct wmi_pdev_stats_extra *src,
- ++ struct ath10k_fw_stats_pdev *dst)
- ++{
- ++ dst->ack_rx_bad = __le32_to_cpu(src->ack_rx_bad);
- ++ dst->rts_bad = __le32_to_cpu(src->rts_bad);
- ++ dst->rts_good = __le32_to_cpu(src->rts_good);
- ++ dst->fcs_bad = __le32_to_cpu(src->fcs_bad);
- ++ dst->no_beacons = __le32_to_cpu(src->no_beacons);
- ++ dst->mib_int_count = __le32_to_cpu(src->mib_int_count);
- ++}
- ++
- ++void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src,
- ++ struct ath10k_fw_stats_peer *dst)
- ++{
- ++ ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr);
- ++ dst->peer_rssi = __le32_to_cpu(src->peer_rssi);
- ++ dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate);
- ++}
- ++
- ++static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct ath10k_fw_stats *stats)
- + {
- +- struct wmi_vdev_start_response_event *ev;
- ++ const struct wmi_stats_event *ev = (void *)skb->data;
- ++ u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
- ++ int i;
- +
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
- ++ if (!skb_pull(skb, sizeof(*ev)))
- ++ return -EPROTO;
- +
- +- ev = (struct wmi_vdev_start_response_event *)skb->data;
- ++ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
- ++ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
- ++ num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
- ++
- ++ for (i = 0; i < num_pdev_stats; i++) {
- ++ const struct wmi_pdev_stats *src;
- ++ struct ath10k_fw_stats_pdev *dst;
- ++
- ++ src = (void *)skb->data;
- ++ if (!skb_pull(skb, sizeof(*src)))
- ++ return -EPROTO;
- +
- +- if (WARN_ON(__le32_to_cpu(ev->status)))
- +- return;
- ++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
- ++ if (!dst)
- ++ continue;
- +
- +- complete(&ar->vdev_setup_done);
- +-}
- ++ ath10k_wmi_pull_pdev_stats_base(&src->base, dst);
- ++ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst);
- ++ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst);
- +
- +-static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
- +- struct sk_buff *skb)
- +-{
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n");
- +- complete(&ar->vdev_setup_done);
- +-}
- ++ list_add_tail(&dst->list, &stats->pdevs);
- ++ }
- +
- +-static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
- +- struct sk_buff *skb)
- +-{
- +- struct wmi_peer_sta_kickout_event *ev;
- +- struct ieee80211_sta *sta;
- ++ /* fw doesn't implement vdev stats */
- +
- +- ev = (struct wmi_peer_sta_kickout_event *)skb->data;
- ++ for (i = 0; i < num_peer_stats; i++) {
- ++ const struct wmi_peer_stats *src;
- ++ struct ath10k_fw_stats_peer *dst;
- +
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
- +- ev->peer_macaddr.addr);
- ++ src = (void *)skb->data;
- ++ if (!skb_pull(skb, sizeof(*src)))
- ++ return -EPROTO;
- +
- +- rcu_read_lock();
- ++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
- ++ if (!dst)
- ++ continue;
- +
- +- sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL);
- +- if (!sta) {
- +- ath10k_warn("Spurious quick kickout for STA %pM\n",
- +- ev->peer_macaddr.addr);
- +- goto exit;
- ++ ath10k_wmi_pull_peer_stats(src, dst);
- ++ list_add_tail(&dst->list, &stats->peers);
- + }
- +
- +- ieee80211_report_low_ack(sta, 10);
- +-
- +-exit:
- +- rcu_read_unlock();
- ++ return 0;
- + }
- +
- +-/*
- +- * FIXME
- +- *
- +- * We don't report to mac80211 sleep state of connected
- +- * stations. Due to this mac80211 can't fill in TIM IE
- +- * correctly.
- +- *
- +- * I know of no way of getting nullfunc frames that contain
- +- * sleep transition from connected stations - these do not
- +- * seem to be sent from the target to the host. There also
- +- * doesn't seem to be a dedicated event for that. So the
- +- * only way left to do this would be to read tim_bitmap
- +- * during SWBA.
- +- *
- +- * We could probably try using tim_bitmap from SWBA to tell
- +- * mac80211 which stations are asleep and which are not. The
- +- * problem here is calling mac80211 functions so many times
- +- * could take too long and make us miss the time to submit
- +- * the beacon to the target.
- +- *
- +- * So as a workaround we try to extend the TIM IE if there
- +- * is unicast buffered for stations with aid > 7 and fill it
- +- * in ourselves.
- +- */
- +-static void ath10k_wmi_update_tim(struct ath10k *ar,
- +- struct ath10k_vif *arvif,
- +- struct sk_buff *bcn,
- +- struct wmi_bcn_info *bcn_info)
- ++static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct ath10k_fw_stats *stats)
- + {
- +- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data;
- +- struct ieee80211_tim_ie *tim;
- +- u8 *ies, *ie;
- +- u8 ie_len, pvm_len;
- ++ const struct wmi_stats_event *ev = (void *)skb->data;
- ++ u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
- ++ int i;
- +
- +- /* if next SWBA has no tim_changed the tim_bitmap is garbage.
- +- * we must copy the bitmap upon change and reuse it later */
- +- if (__le32_to_cpu(bcn_info->tim_info.tim_changed)) {
- +- int i;
- ++ if (!skb_pull(skb, sizeof(*ev)))
- ++ return -EPROTO;
- +
- +- BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) !=
- +- sizeof(bcn_info->tim_info.tim_bitmap));
- ++ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
- ++ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
- ++ num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
- ++
- ++ for (i = 0; i < num_pdev_stats; i++) {
- ++ const struct wmi_10x_pdev_stats *src;
- ++ struct ath10k_fw_stats_pdev *dst;
- ++
- ++ src = (void *)skb->data;
- ++ if (!skb_pull(skb, sizeof(*src)))
- ++ return -EPROTO;
- +
- +- for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) {
- +- __le32 t = bcn_info->tim_info.tim_bitmap[i / 4];
- +- u32 v = __le32_to_cpu(t);
- +- arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF;
- +- }
- ++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
- ++ if (!dst)
- ++ continue;
- +
- +- /* FW reports either length 0 or 16
- +- * so we calculate this on our own */
- +- arvif->u.ap.tim_len = 0;
- +- for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++)
- +- if (arvif->u.ap.tim_bitmap[i])
- +- arvif->u.ap.tim_len = i;
- ++ ath10k_wmi_pull_pdev_stats_base(&src->base, dst);
- ++ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst);
- ++ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst);
- ++ ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst);
- +
- +- arvif->u.ap.tim_len++;
- ++ list_add_tail(&dst->list, &stats->pdevs);
- + }
- +
- +- ies = bcn->data;
- +- ies += ieee80211_hdrlen(hdr->frame_control);
- +- ies += 12; /* fixed parameters */
- ++ /* fw doesn't implement vdev stats */
- +
- +- ie = (u8 *)cfg80211_find_ie(WLAN_EID_TIM, ies,
- +- (u8 *)skb_tail_pointer(bcn) - ies);
- +- if (!ie) {
- +- if (arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
- +- ath10k_warn("no tim ie found;\n");
- +- return;
- +- }
- ++ for (i = 0; i < num_peer_stats; i++) {
- ++ const struct wmi_10x_peer_stats *src;
- ++ struct ath10k_fw_stats_peer *dst;
- +
- +- tim = (void *)ie + 2;
- +- ie_len = ie[1];
- +- pvm_len = ie_len - 3; /* exclude dtim count, dtim period, bmap ctl */
- ++ src = (void *)skb->data;
- ++ if (!skb_pull(skb, sizeof(*src)))
- ++ return -EPROTO;
- +
- +- if (pvm_len < arvif->u.ap.tim_len) {
- +- int expand_size = sizeof(arvif->u.ap.tim_bitmap) - pvm_len;
- +- int move_size = skb_tail_pointer(bcn) - (ie + 2 + ie_len);
- +- void *next_ie = ie + 2 + ie_len;
- ++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
- ++ if (!dst)
- ++ continue;
- +
- +- if (skb_put(bcn, expand_size)) {
- +- memmove(next_ie + expand_size, next_ie, move_size);
- ++ ath10k_wmi_pull_peer_stats(&src->old, dst);
- +
- +- ie[1] += expand_size;
- +- ie_len += expand_size;
- +- pvm_len += expand_size;
- +- } else {
- +- ath10k_warn("tim expansion failed\n");
- +- }
- +- }
- ++ dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate);
- +
- +- if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) {
- +- ath10k_warn("tim pvm length is too great (%d)\n", pvm_len);
- +- return;
- ++ list_add_tail(&dst->list, &stats->peers);
- + }
- +
- +- tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast);
- +- memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len);
- ++ return 0;
- ++}
- +
- +- if (tim->dtim_count == 0) {
- +- ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true;
- ++static int ath10k_wmi_10_2_op_pull_fw_stats(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct ath10k_fw_stats *stats)
- ++{
- ++ const struct wmi_10_2_stats_event *ev = (void *)skb->data;
- ++ u32 num_pdev_stats;
- ++ u32 num_pdev_ext_stats;
- ++ u32 num_vdev_stats;
- ++ u32 num_peer_stats;
- ++ int i;
- +
- +- if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1)
- +- ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
- +- }
- ++ if (!skb_pull(skb, sizeof(*ev)))
- ++ return -EPROTO;
- +
- +- ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
- +- tim->dtim_count, tim->dtim_period,
- +- tim->bitmap_ctrl, pvm_len);
- ++ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
- ++ num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats);
- ++ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
- ++ num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
- ++
- ++ for (i = 0; i < num_pdev_stats; i++) {
- ++ const struct wmi_10_2_pdev_stats *src;
- ++ struct ath10k_fw_stats_pdev *dst;
- ++
- ++ src = (void *)skb->data;
- ++ if (!skb_pull(skb, sizeof(*src)))
- ++ return -EPROTO;
- ++
- ++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
- ++ if (!dst)
- ++ continue;
- ++
- ++ ath10k_wmi_pull_pdev_stats_base(&src->base, dst);
- ++ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst);
- ++ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst);
- ++ ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst);
- ++ /* FIXME: expose 10.2 specific values */
- ++
- ++ list_add_tail(&dst->list, &stats->pdevs);
- ++ }
- ++
- ++ for (i = 0; i < num_pdev_ext_stats; i++) {
- ++ const struct wmi_10_2_pdev_ext_stats *src;
- ++
- ++ src = (void *)skb->data;
- ++ if (!skb_pull(skb, sizeof(*src)))
- ++ return -EPROTO;
- ++
- ++ /* FIXME: expose values to userspace
- ++ *
- ++ * Note: Even though this loop seems to do nothing it is
- ++ * required to parse following sub-structures properly.
- ++ */
- ++ }
- ++
- ++ /* fw doesn't implement vdev stats */
- ++
- ++ for (i = 0; i < num_peer_stats; i++) {
- ++ const struct wmi_10_2_peer_stats *src;
- ++ struct ath10k_fw_stats_peer *dst;
- ++
- ++ src = (void *)skb->data;
- ++ if (!skb_pull(skb, sizeof(*src)))
- ++ return -EPROTO;
- ++
- ++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
- ++ if (!dst)
- ++ continue;
- ++
- ++ ath10k_wmi_pull_peer_stats(&src->old, dst);
- ++
- ++ dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate);
- ++ /* FIXME: expose 10.2 specific values */
- ++
- ++ list_add_tail(&dst->list, &stats->peers);
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct ath10k_fw_stats *stats)
- ++{
- ++ const struct wmi_10_2_stats_event *ev = (void *)skb->data;
- ++ u32 num_pdev_stats;
- ++ u32 num_pdev_ext_stats;
- ++ u32 num_vdev_stats;
- ++ u32 num_peer_stats;
- ++ int i;
- ++
- ++ if (!skb_pull(skb, sizeof(*ev)))
- ++ return -EPROTO;
- ++
- ++ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
- ++ num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats);
- ++ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
- ++ num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
- ++
- ++ for (i = 0; i < num_pdev_stats; i++) {
- ++ const struct wmi_10_2_pdev_stats *src;
- ++ struct ath10k_fw_stats_pdev *dst;
- ++
- ++ src = (void *)skb->data;
- ++ if (!skb_pull(skb, sizeof(*src)))
- ++ return -EPROTO;
- ++
- ++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
- ++ if (!dst)
- ++ continue;
- ++
- ++ ath10k_wmi_pull_pdev_stats_base(&src->base, dst);
- ++ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst);
- ++ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst);
- ++ ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst);
- ++ /* FIXME: expose 10.2 specific values */
- ++
- ++ list_add_tail(&dst->list, &stats->pdevs);
- ++ }
- ++
- ++ for (i = 0; i < num_pdev_ext_stats; i++) {
- ++ const struct wmi_10_2_pdev_ext_stats *src;
- ++
- ++ src = (void *)skb->data;
- ++ if (!skb_pull(skb, sizeof(*src)))
- ++ return -EPROTO;
- ++
- ++ /* FIXME: expose values to userspace
- ++ *
- ++ * Note: Even though this loop seems to do nothing it is
- ++ * required to parse following sub-structures properly.
- ++ */
- ++ }
- ++
- ++ /* fw doesn't implement vdev stats */
- ++
- ++ for (i = 0; i < num_peer_stats; i++) {
- ++ const struct wmi_10_2_4_peer_stats *src;
- ++ struct ath10k_fw_stats_peer *dst;
- ++
- ++ src = (void *)skb->data;
- ++ if (!skb_pull(skb, sizeof(*src)))
- ++ return -EPROTO;
- ++
- ++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
- ++ if (!dst)
- ++ continue;
- ++
- ++ ath10k_wmi_pull_peer_stats(&src->common.old, dst);
- ++
- ++ dst->peer_rx_rate = __le32_to_cpu(src->common.peer_rx_rate);
- ++ /* FIXME: expose 10.2 specific values */
- ++
- ++ list_add_tail(&dst->list, &stats->peers);
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- ++void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb)
- ++{
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
- ++ ath10k_debug_fw_stats_process(ar, skb);
- ++}
- ++
- ++static int
- ++ath10k_wmi_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_vdev_start_ev_arg *arg)
- ++{
- ++ struct wmi_vdev_start_response_event *ev = (void *)skb->data;
- ++
- ++ if (skb->len < sizeof(*ev))
- ++ return -EPROTO;
- ++
- ++ skb_pull(skb, sizeof(*ev));
- ++ arg->vdev_id = ev->vdev_id;
- ++ arg->req_id = ev->req_id;
- ++ arg->resp_type = ev->resp_type;
- ++ arg->status = ev->status;
- ++
- ++ return 0;
- ++}
- ++
- ++void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb)
- ++{
- ++ struct wmi_vdev_start_ev_arg arg = {};
- ++ int ret;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
- ++
- ++ ret = ath10k_wmi_pull_vdev_start(ar, skb, &arg);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to parse vdev start event: %d\n", ret);
- ++ return;
- ++ }
- ++
- ++ if (WARN_ON(__le32_to_cpu(arg.status)))
- ++ return;
- ++
- ++ complete(&ar->vdev_setup_done);
- ++}
- ++
- ++void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb)
- ++{
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n");
- ++ complete(&ar->vdev_setup_done);
- ++}
- ++
- ++static int
- ++ath10k_wmi_op_pull_peer_kick_ev(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_peer_kick_ev_arg *arg)
- ++{
- ++ struct wmi_peer_sta_kickout_event *ev = (void *)skb->data;
- ++
- ++ if (skb->len < sizeof(*ev))
- ++ return -EPROTO;
- ++
- ++ skb_pull(skb, sizeof(*ev));
- ++ arg->mac_addr = ev->peer_macaddr.addr;
- ++
- ++ return 0;
- ++}
- ++
- ++void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb)
- ++{
- ++ struct wmi_peer_kick_ev_arg arg = {};
- ++ struct ieee80211_sta *sta;
- ++ int ret;
- ++
- ++ ret = ath10k_wmi_pull_peer_kick(ar, skb, &arg);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to parse peer kickout event: %d\n",
- ++ ret);
- ++ return;
- ++ }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
- ++ arg.mac_addr);
- ++
- ++ rcu_read_lock();
- ++
- ++ sta = ieee80211_find_sta_by_ifaddr(ar->hw, arg.mac_addr, NULL);
- ++ if (!sta) {
- ++ ath10k_warn(ar, "Spurious quick kickout for STA %pM\n",
- ++ arg.mac_addr);
- ++ goto exit;
- ++ }
- ++
- ++ ieee80211_report_low_ack(sta, 10);
- ++
- ++exit:
- ++ rcu_read_unlock();
- ++}
- ++
- ++/*
- ++ * FIXME
- ++ *
- ++ * We don't report to mac80211 sleep state of connected
- ++ * stations. Due to this mac80211 can't fill in TIM IE
- ++ * correctly.
- ++ *
- ++ * I know of no way of getting nullfunc frames that contain
- ++ * sleep transition from connected stations - these do not
- ++ * seem to be sent from the target to the host. There also
- ++ * doesn't seem to be a dedicated event for that. So the
- ++ * only way left to do this would be to read tim_bitmap
- ++ * during SWBA.
- ++ *
- ++ * We could probably try using tim_bitmap from SWBA to tell
- ++ * mac80211 which stations are asleep and which are not. The
- ++ * problem here is calling mac80211 functions so many times
- ++ * could take too long and make us miss the time to submit
- ++ * the beacon to the target.
- ++ *
- ++ * So as a workaround we try to extend the TIM IE if there
- ++ * is unicast buffered for stations with aid > 7 and fill it
- ++ * in ourselves.
- ++ */
- ++static void ath10k_wmi_update_tim(struct ath10k *ar,
- ++ struct ath10k_vif *arvif,
- ++ struct sk_buff *bcn,
- ++ const struct wmi_tim_info *tim_info)
- ++{
- ++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data;
- ++ struct ieee80211_tim_ie *tim;
- ++ u8 *ies, *ie;
- ++ u8 ie_len, pvm_len;
- ++ __le32 t;
- ++ u32 v;
- ++
- ++ /* if next SWBA has no tim_changed the tim_bitmap is garbage.
- ++ * we must copy the bitmap upon change and reuse it later */
- ++ if (__le32_to_cpu(tim_info->tim_changed)) {
- ++ int i;
- ++
- ++ BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) !=
- ++ sizeof(tim_info->tim_bitmap));
- ++
- ++ for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) {
- ++ t = tim_info->tim_bitmap[i / 4];
- ++ v = __le32_to_cpu(t);
- ++ arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF;
- ++ }
- ++
- ++ /* FW reports either length 0 or 16
- ++ * so we calculate this on our own */
- ++ arvif->u.ap.tim_len = 0;
- ++ for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++)
- ++ if (arvif->u.ap.tim_bitmap[i])
- ++ arvif->u.ap.tim_len = i;
- ++
- ++ arvif->u.ap.tim_len++;
- ++ }
- ++
- ++ ies = bcn->data;
- ++ ies += ieee80211_hdrlen(hdr->frame_control);
- ++ ies += 12; /* fixed parameters */
- ++
- ++ ie = (u8 *)cfg80211_find_ie(WLAN_EID_TIM, ies,
- ++ (u8 *)skb_tail_pointer(bcn) - ies);
- ++ if (!ie) {
- ++ if (arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
- ++ ath10k_warn(ar, "no tim ie found;\n");
- ++ return;
- ++ }
- ++
- ++ tim = (void *)ie + 2;
- ++ ie_len = ie[1];
- ++ pvm_len = ie_len - 3; /* exclude dtim count, dtim period, bmap ctl */
- ++
- ++ if (pvm_len < arvif->u.ap.tim_len) {
- ++ int expand_size = sizeof(arvif->u.ap.tim_bitmap) - pvm_len;
- ++ int move_size = skb_tail_pointer(bcn) - (ie + 2 + ie_len);
- ++ void *next_ie = ie + 2 + ie_len;
- ++
- ++ if (skb_put(bcn, expand_size)) {
- ++ memmove(next_ie + expand_size, next_ie, move_size);
- ++
- ++ ie[1] += expand_size;
- ++ ie_len += expand_size;
- ++ pvm_len += expand_size;
- ++ } else {
- ++ ath10k_warn(ar, "tim expansion failed\n");
- ++ }
- ++ }
- ++
- ++ if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) {
- ++ ath10k_warn(ar, "tim pvm length is too great (%d)\n", pvm_len);
- ++ return;
- ++ }
- ++
- ++ tim->bitmap_ctrl = !!__le32_to_cpu(tim_info->tim_mcast);
- ++ memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len);
- ++
- ++ if (tim->dtim_count == 0) {
- ++ ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true;
- ++
- ++ if (__le32_to_cpu(tim_info->tim_mcast) == 1)
- ++ ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
- ++ }
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
- ++ tim->dtim_count, tim->dtim_period,
- ++ tim->bitmap_ctrl, pvm_len);
- + }
- +
- + static void ath10k_p2p_fill_noa_ie(u8 *data, u32 len,
- +- struct wmi_p2p_noa_info *noa)
- ++ const struct wmi_p2p_noa_info *noa)
- + {
- + struct ieee80211_p2p_noa_attr *noa_attr;
- + u8 ctwindow_oppps = noa->ctwindow_oppps;
- +@@ -1287,14 +2319,13 @@ static void ath10k_p2p_fill_noa_ie(u8 *d
- + *noa_attr_len = __cpu_to_le16(attr_len);
- + }
- +
- +-static u32 ath10k_p2p_calc_noa_ie_len(struct wmi_p2p_noa_info *noa)
- ++static u32 ath10k_p2p_calc_noa_ie_len(const struct wmi_p2p_noa_info *noa)
- + {
- + u32 len = 0;
- + u8 noa_descriptors = noa->num_descriptors;
- + u8 opp_ps_info = noa->ctwindow_oppps;
- + bool opps_enabled = !!(opp_ps_info & WMI_P2P_OPPPS_ENABLE_BIT);
- +
- +-
- + if (!noa_descriptors && !opps_enabled)
- + return len;
- +
- +@@ -1308,16 +2339,15 @@ static u32 ath10k_p2p_calc_noa_ie_len(st
- +
- + static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif,
- + struct sk_buff *bcn,
- +- struct wmi_bcn_info *bcn_info)
- ++ const struct wmi_p2p_noa_info *noa)
- + {
- +- struct wmi_p2p_noa_info *noa = &bcn_info->p2p_noa_info;
- + u8 *new_data, *old_data = arvif->u.ap.noa_data;
- + u32 new_len;
- +
- + if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
- + return;
- +
- +- ath10k_dbg(ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
- ++ ath10k_dbg(ar, ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
- + if (noa->changed & WMI_P2P_NOA_CHANGED_BIT) {
- + new_len = ath10k_p2p_calc_noa_ie_len(noa);
- + if (!new_len)
- +@@ -1351,22 +2381,59 @@ cleanup:
- + kfree(old_data);
- + }
- +
- ++static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_swba_ev_arg *arg)
- ++{
- ++ struct wmi_host_swba_event *ev = (void *)skb->data;
- ++ u32 map;
- ++ size_t i;
- ++
- ++ if (skb->len < sizeof(*ev))
- ++ return -EPROTO;
- ++
- ++ skb_pull(skb, sizeof(*ev));
- ++ arg->vdev_map = ev->vdev_map;
- ++
- ++ for (i = 0, map = __le32_to_cpu(ev->vdev_map); map; map >>= 1) {
- ++ if (!(map & BIT(0)))
- ++ continue;
- ++
- ++ /* If this happens there were some changes in firmware and
- ++ * ath10k should update the max size of tim_info array.
- ++ */
- ++ if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info)))
- ++ break;
- ++
- ++ arg->tim_info[i] = &ev->bcn_info[i].tim_info;
- ++ arg->noa_info[i] = &ev->bcn_info[i].p2p_noa_info;
- ++ i++;
- ++ }
- ++
- ++ return 0;
- ++}
- +
- +-static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
- ++void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- struct wmi_host_swba_event *ev;
- ++ struct wmi_swba_ev_arg arg = {};
- + u32 map;
- + int i = -1;
- +- struct wmi_bcn_info *bcn_info;
- ++ const struct wmi_tim_info *tim_info;
- ++ const struct wmi_p2p_noa_info *noa_info;
- + struct ath10k_vif *arvif;
- + struct sk_buff *bcn;
- ++ dma_addr_t paddr;
- + int ret, vdev_id = 0;
- +
- +- ev = (struct wmi_host_swba_event *)skb->data;
- +- map = __le32_to_cpu(ev->vdev_map);
- ++ ret = ath10k_wmi_pull_swba(ar, skb, &arg);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to parse swba event: %d\n", ret);
- ++ return;
- ++ }
- ++
- ++ map = __le32_to_cpu(arg.vdev_map);
- +
- +- ath10k_dbg(ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
- +- ev->vdev_map);
- ++ ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
- ++ map);
- +
- + for (; map; map >>= 1, vdev_id++) {
- + if (!(map & 0x1))
- +@@ -1375,27 +2442,29 @@ static void ath10k_wmi_event_host_swba(s
- + i++;
- +
- + if (i >= WMI_MAX_AP_VDEV) {
- +- ath10k_warn("swba has corrupted vdev map\n");
- ++ ath10k_warn(ar, "swba has corrupted vdev map\n");
- + break;
- + }
- +
- +- bcn_info = &ev->bcn_info[i];
- ++ tim_info = arg.tim_info[i];
- ++ noa_info = arg.noa_info[i];
- +
- +- ath10k_dbg(ATH10K_DBG_MGMT,
- ++ ath10k_dbg(ar, ATH10K_DBG_MGMT,
- + "mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n",
- + i,
- +- __le32_to_cpu(bcn_info->tim_info.tim_len),
- +- __le32_to_cpu(bcn_info->tim_info.tim_mcast),
- +- __le32_to_cpu(bcn_info->tim_info.tim_changed),
- +- __le32_to_cpu(bcn_info->tim_info.tim_num_ps_pending),
- +- __le32_to_cpu(bcn_info->tim_info.tim_bitmap[3]),
- +- __le32_to_cpu(bcn_info->tim_info.tim_bitmap[2]),
- +- __le32_to_cpu(bcn_info->tim_info.tim_bitmap[1]),
- +- __le32_to_cpu(bcn_info->tim_info.tim_bitmap[0]));
- ++ __le32_to_cpu(tim_info->tim_len),
- ++ __le32_to_cpu(tim_info->tim_mcast),
- ++ __le32_to_cpu(tim_info->tim_changed),
- ++ __le32_to_cpu(tim_info->tim_num_ps_pending),
- ++ __le32_to_cpu(tim_info->tim_bitmap[3]),
- ++ __le32_to_cpu(tim_info->tim_bitmap[2]),
- ++ __le32_to_cpu(tim_info->tim_bitmap[1]),
- ++ __le32_to_cpu(tim_info->tim_bitmap[0]));
- +
- + arvif = ath10k_get_arvif(ar, vdev_id);
- + if (arvif == NULL) {
- +- ath10k_warn("no vif for vdev_id %d found\n", vdev_id);
- ++ ath10k_warn(ar, "no vif for vdev_id %d found\n",
- ++ vdev_id);
- + continue;
- + }
- +
- +@@ -1412,57 +2481,77 @@ static void ath10k_wmi_event_host_swba(s
- +
- + bcn = ieee80211_beacon_get(ar->hw, arvif->vif);
- + if (!bcn) {
- +- ath10k_warn("could not get mac80211 beacon\n");
- ++ ath10k_warn(ar, "could not get mac80211 beacon\n");
- + continue;
- + }
- +
- +- ath10k_tx_h_seq_no(bcn);
- +- ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info);
- +- ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info);
- ++ ath10k_tx_h_seq_no(arvif->vif, bcn);
- ++ ath10k_wmi_update_tim(ar, arvif, bcn, tim_info);
- ++ ath10k_wmi_update_noa(ar, arvif, bcn, noa_info);
- +
- + spin_lock_bh(&ar->data_lock);
- +
- + if (arvif->beacon) {
- +- if (!arvif->beacon_sent)
- +- ath10k_warn("SWBA overrun on vdev %d\n",
- ++ switch (arvif->beacon_state) {
- ++ case ATH10K_BEACON_SENT:
- ++ break;
- ++ case ATH10K_BEACON_SCHEDULED:
- ++ ath10k_warn(ar, "SWBA overrun on vdev %d, skipped old beacon\n",
- + arvif->vdev_id);
- ++ break;
- ++ case ATH10K_BEACON_SENDING:
- ++ ath10k_warn(ar, "SWBA overrun on vdev %d, skipped new beacon\n",
- ++ arvif->vdev_id);
- ++ dev_kfree_skb(bcn);
- ++ goto skip;
- ++ }
- +
- +- dma_unmap_single(arvif->ar->dev,
- +- ATH10K_SKB_CB(arvif->beacon)->paddr,
- +- arvif->beacon->len, DMA_TO_DEVICE);
- +- dev_kfree_skb_any(arvif->beacon);
- +- arvif->beacon = NULL;
- ++ ath10k_mac_vif_beacon_free(arvif);
- + }
- +
- +- ATH10K_SKB_CB(bcn)->paddr = dma_map_single(arvif->ar->dev,
- +- bcn->data, bcn->len,
- +- DMA_TO_DEVICE);
- +- ret = dma_mapping_error(arvif->ar->dev,
- +- ATH10K_SKB_CB(bcn)->paddr);
- +- if (ret) {
- +- ath10k_warn("failed to map beacon: %d\n", ret);
- +- dev_kfree_skb_any(bcn);
- +- goto skip;
- ++ if (!arvif->beacon_buf) {
- ++ paddr = dma_map_single(arvif->ar->dev, bcn->data,
- ++ bcn->len, DMA_TO_DEVICE);
- ++ ret = dma_mapping_error(arvif->ar->dev, paddr);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to map beacon: %d\n",
- ++ ret);
- ++ dev_kfree_skb_any(bcn);
- ++ goto skip;
- ++ }
- ++
- ++ ATH10K_SKB_CB(bcn)->paddr = paddr;
- ++ } else {
- ++ if (bcn->len > IEEE80211_MAX_FRAME_LEN) {
- ++ ath10k_warn(ar, "trimming beacon %d -> %d bytes!\n",
- ++ bcn->len, IEEE80211_MAX_FRAME_LEN);
- ++ skb_trim(bcn, IEEE80211_MAX_FRAME_LEN);
- ++ }
- ++ memcpy(arvif->beacon_buf, bcn->data, bcn->len);
- ++ ATH10K_SKB_CB(bcn)->paddr = arvif->beacon_paddr;
- + }
- +
- + arvif->beacon = bcn;
- +- arvif->beacon_sent = false;
- ++ arvif->beacon_state = ATH10K_BEACON_SCHEDULED;
- ++
- ++ trace_ath10k_tx_hdr(ar, bcn->data, bcn->len);
- ++ trace_ath10k_tx_payload(ar, bcn->data, bcn->len);
- +
- +- ath10k_wmi_tx_beacon_nowait(arvif);
- + skip:
- + spin_unlock_bh(&ar->data_lock);
- + }
- ++
- ++ ath10k_wmi_tx_beacons_nowait(ar);
- + }
- +
- +-static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
- + }
- +
- + static void ath10k_dfs_radar_report(struct ath10k *ar,
- +- struct wmi_single_phyerr_rx_event *event,
- +- struct phyerr_radar_report *rr,
- ++ const struct wmi_phyerr *phyerr,
- ++ const struct phyerr_radar_report *rr,
- + u64 tsf)
- + {
- + u32 reg0, reg1, tsf32l;
- +@@ -1473,20 +2562,20 @@ static void ath10k_dfs_radar_report(stru
- + reg0 = __le32_to_cpu(rr->reg0);
- + reg1 = __le32_to_cpu(rr->reg1);
- +
- +- ath10k_dbg(ATH10K_DBG_REGULATORY,
- ++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
- + "wmi phyerr radar report chirp %d max_width %d agc_total_gain %d pulse_delta_diff %d\n",
- + MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP),
- + MS(reg0, RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH),
- + MS(reg0, RADAR_REPORT_REG0_AGC_TOTAL_GAIN),
- + MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_DIFF));
- +- ath10k_dbg(ATH10K_DBG_REGULATORY,
- ++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
- + "wmi phyerr radar report pulse_delta_pean %d pulse_sidx %d fft_valid %d agc_mb_gain %d subchan_mask %d\n",
- + MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_PEAK),
- + MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX),
- + MS(reg1, RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID),
- + MS(reg1, RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN),
- + MS(reg1, RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK));
- +- ath10k_dbg(ATH10K_DBG_REGULATORY,
- ++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
- + "wmi phyerr radar report pulse_tsf_offset 0x%X pulse_dur: %d\n",
- + MS(reg1, RADAR_REPORT_REG1_PULSE_TSF_OFFSET),
- + MS(reg1, RADAR_REPORT_REG1_PULSE_DUR));
- +@@ -1495,12 +2584,12 @@ static void ath10k_dfs_radar_report(stru
- + return;
- +
- + /* report event to DFS pattern detector */
- +- tsf32l = __le32_to_cpu(event->hdr.tsf_timestamp);
- ++ tsf32l = __le32_to_cpu(phyerr->tsf_timestamp);
- + tsf64 = tsf & (~0xFFFFFFFFULL);
- + tsf64 |= tsf32l;
- +
- + width = MS(reg1, RADAR_REPORT_REG1_PULSE_DUR);
- +- rssi = event->hdr.rssi_combined;
- ++ rssi = phyerr->rssi_combined;
- +
- + /* hardware store this as 8 bit signed value,
- + * set to zero if negative number
- +@@ -1513,25 +2602,25 @@ static void ath10k_dfs_radar_report(stru
- + pe.width = width;
- + pe.rssi = rssi;
- +
- +- ath10k_dbg(ATH10K_DBG_REGULATORY,
- ++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
- + "dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n",
- + pe.freq, pe.width, pe.rssi, pe.ts);
- +
- + ATH10K_DFS_STAT_INC(ar, pulses_detected);
- +
- + if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) {
- +- ath10k_dbg(ATH10K_DBG_REGULATORY,
- ++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
- + "dfs no pulse pattern detected, yet\n");
- + return;
- + }
- +
- +- ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n");
- + ATH10K_DFS_STAT_INC(ar, radar_detected);
- +
- + /* Control radar events reporting in debugfs file
- + dfs_block_radar_events */
- + if (ar->dfs_block_radar_events) {
- +- ath10k_info("DFS Radar detected, but ignored as requested\n");
- ++ ath10k_info(ar, "DFS Radar detected, but ignored as requested\n");
- + return;
- + }
- +
- +@@ -1539,8 +2628,8 @@ static void ath10k_dfs_radar_report(stru
- + }
- +
- + static int ath10k_dfs_fft_report(struct ath10k *ar,
- +- struct wmi_single_phyerr_rx_event *event,
- +- struct phyerr_fft_report *fftr,
- ++ const struct wmi_phyerr *phyerr,
- ++ const struct phyerr_fft_report *fftr,
- + u64 tsf)
- + {
- + u32 reg0, reg1;
- +@@ -1548,15 +2637,15 @@ static int ath10k_dfs_fft_report(struct
- +
- + reg0 = __le32_to_cpu(fftr->reg0);
- + reg1 = __le32_to_cpu(fftr->reg1);
- +- rssi = event->hdr.rssi_combined;
- ++ rssi = phyerr->rssi_combined;
- +
- +- ath10k_dbg(ATH10K_DBG_REGULATORY,
- ++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
- + "wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n",
- + MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB),
- + MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB),
- + MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX),
- + MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX));
- +- ath10k_dbg(ATH10K_DBG_REGULATORY,
- ++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
- + "wmi phyerr fft report rel_pwr_db %d avgpwr_db %d peak_mag %d num_store_bin %d\n",
- + MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB),
- + MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB),
- +@@ -1568,7 +2657,7 @@ static int ath10k_dfs_fft_report(struct
- + /* false event detection */
- + if (rssi == DFS_RSSI_POSSIBLY_FALSE &&
- + peak_mag < 2 * DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE) {
- +- ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs false pulse detected\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs false pulse detected\n");
- + ATH10K_DFS_STAT_INC(ar, pulses_discarded);
- + return -EINVAL;
- + }
- +@@ -1576,21 +2665,21 @@ static int ath10k_dfs_fft_report(struct
- + return 0;
- + }
- +
- +-static void ath10k_wmi_event_dfs(struct ath10k *ar,
- +- struct wmi_single_phyerr_rx_event *event,
- +- u64 tsf)
- ++void ath10k_wmi_event_dfs(struct ath10k *ar,
- ++ const struct wmi_phyerr *phyerr,
- ++ u64 tsf)
- + {
- + int buf_len, tlv_len, res, i = 0;
- +- struct phyerr_tlv *tlv;
- +- struct phyerr_radar_report *rr;
- +- struct phyerr_fft_report *fftr;
- +- u8 *tlv_buf;
- ++ const struct phyerr_tlv *tlv;
- ++ const struct phyerr_radar_report *rr;
- ++ const struct phyerr_fft_report *fftr;
- ++ const u8 *tlv_buf;
- +
- +- buf_len = __le32_to_cpu(event->hdr.buf_len);
- +- ath10k_dbg(ATH10K_DBG_REGULATORY,
- ++ buf_len = __le32_to_cpu(phyerr->buf_len);
- ++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
- + "wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n",
- +- event->hdr.phy_err_code, event->hdr.rssi_combined,
- +- __le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len);
- ++ phyerr->phy_err_code, phyerr->rssi_combined,
- ++ __le32_to_cpu(phyerr->tsf_timestamp), tsf, buf_len);
- +
- + /* Skip event if DFS disabled */
- + if (!config_enabled(CPTCFG_ATH10K_DFS_CERTIFIED))
- +@@ -1600,36 +2689,38 @@ static void ath10k_wmi_event_dfs(struct
- +
- + while (i < buf_len) {
- + if (i + sizeof(*tlv) > buf_len) {
- +- ath10k_warn("too short buf for tlv header (%d)\n", i);
- ++ ath10k_warn(ar, "too short buf for tlv header (%d)\n",
- ++ i);
- + return;
- + }
- +
- +- tlv = (struct phyerr_tlv *)&event->bufp[i];
- ++ tlv = (struct phyerr_tlv *)&phyerr->buf[i];
- + tlv_len = __le16_to_cpu(tlv->len);
- +- tlv_buf = &event->bufp[i + sizeof(*tlv)];
- +- ath10k_dbg(ATH10K_DBG_REGULATORY,
- ++ tlv_buf = &phyerr->buf[i + sizeof(*tlv)];
- ++ ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
- + "wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n",
- + tlv_len, tlv->tag, tlv->sig);
- +
- + switch (tlv->tag) {
- + case PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY:
- + if (i + sizeof(*tlv) + sizeof(*rr) > buf_len) {
- +- ath10k_warn("too short radar pulse summary (%d)\n",
- ++ ath10k_warn(ar, "too short radar pulse summary (%d)\n",
- + i);
- + return;
- + }
- +
- + rr = (struct phyerr_radar_report *)tlv_buf;
- +- ath10k_dfs_radar_report(ar, event, rr, tsf);
- ++ ath10k_dfs_radar_report(ar, phyerr, rr, tsf);
- + break;
- + case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
- + if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) {
- +- ath10k_warn("too short fft report (%d)\n", i);
- ++ ath10k_warn(ar, "too short fft report (%d)\n",
- ++ i);
- + return;
- + }
- +
- + fftr = (struct phyerr_fft_report *)tlv_buf;
- +- res = ath10k_dfs_fft_report(ar, event, fftr, tsf);
- ++ res = ath10k_dfs_fft_report(ar, phyerr, fftr, tsf);
- + if (res)
- + return;
- + break;
- +@@ -1639,58 +2730,122 @@ static void ath10k_wmi_event_dfs(struct
- + }
- + }
- +
- +-static void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
- +- struct wmi_single_phyerr_rx_event *event,
- +- u64 tsf)
- +-{
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi event spectral scan\n");
- +-}
- +-
- +-static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
- ++void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
- ++ const struct wmi_phyerr *phyerr,
- ++ u64 tsf)
- + {
- +- struct wmi_comb_phyerr_rx_event *comb_event;
- +- struct wmi_single_phyerr_rx_event *event;
- +- u32 count, i, buf_len, phy_err_code;
- +- u64 tsf;
- +- int left_len = skb->len;
- +-
- +- ATH10K_DFS_STAT_INC(ar, phy_errors);
- +-
- +- /* Check if combined event available */
- +- if (left_len < sizeof(*comb_event)) {
- +- ath10k_warn("wmi phyerr combined event wrong len\n");
- +- return;
- +- }
- +-
- +- left_len -= sizeof(*comb_event);
- ++ int buf_len, tlv_len, res, i = 0;
- ++ struct phyerr_tlv *tlv;
- ++ const void *tlv_buf;
- ++ const struct phyerr_fft_report *fftr;
- ++ size_t fftr_len;
- +
- +- /* Check number of included events */
- +- comb_event = (struct wmi_comb_phyerr_rx_event *)skb->data;
- +- count = __le32_to_cpu(comb_event->hdr.num_phyerr_events);
- ++ buf_len = __le32_to_cpu(phyerr->buf_len);
- +
- +- tsf = __le32_to_cpu(comb_event->hdr.tsf_u32);
- +- tsf <<= 32;
- +- tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32);
- ++ while (i < buf_len) {
- ++ if (i + sizeof(*tlv) > buf_len) {
- ++ ath10k_warn(ar, "failed to parse phyerr tlv header at byte %d\n",
- ++ i);
- ++ return;
- ++ }
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- +- "wmi event phyerr count %d tsf64 0x%llX\n",
- +- count, tsf);
- ++ tlv = (struct phyerr_tlv *)&phyerr->buf[i];
- ++ tlv_len = __le16_to_cpu(tlv->len);
- ++ tlv_buf = &phyerr->buf[i + sizeof(*tlv)];
- +
- +- event = (struct wmi_single_phyerr_rx_event *)comb_event->bufp;
- +- for (i = 0; i < count; i++) {
- +- /* Check if we can read event header */
- +- if (left_len < sizeof(*event)) {
- +- ath10k_warn("single event (%d) wrong head len\n", i);
- ++ if (i + sizeof(*tlv) + tlv_len > buf_len) {
- ++ ath10k_warn(ar, "failed to parse phyerr tlv payload at byte %d\n",
- ++ i);
- + return;
- + }
- +
- +- left_len -= sizeof(*event);
- +-
- +- buf_len = __le32_to_cpu(event->hdr.buf_len);
- +- phy_err_code = event->hdr.phy_err_code;
- ++ switch (tlv->tag) {
- ++ case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
- ++ if (sizeof(*fftr) > tlv_len) {
- ++ ath10k_warn(ar, "failed to parse fft report at byte %d\n",
- ++ i);
- ++ return;
- ++ }
- ++
- ++ fftr_len = tlv_len - sizeof(*fftr);
- ++ fftr = tlv_buf;
- ++ res = ath10k_spectral_process_fft(ar, phyerr,
- ++ fftr, fftr_len,
- ++ tsf);
- ++ if (res < 0) {
- ++ ath10k_warn(ar, "failed to process fft report: %d\n",
- ++ res);
- ++ return;
- ++ }
- ++ break;
- ++ }
- ++
- ++ i += sizeof(*tlv) + tlv_len;
- ++ }
- ++}
- ++
- ++static int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_phyerr_ev_arg *arg)
- ++{
- ++ struct wmi_phyerr_event *ev = (void *)skb->data;
- ++
- ++ if (skb->len < sizeof(*ev))
- ++ return -EPROTO;
- ++
- ++ arg->num_phyerrs = ev->num_phyerrs;
- ++ arg->tsf_l32 = ev->tsf_l32;
- ++ arg->tsf_u32 = ev->tsf_u32;
- ++ arg->buf_len = __cpu_to_le32(skb->len - sizeof(*ev));
- ++ arg->phyerrs = ev->phyerrs;
- ++
- ++ return 0;
- ++}
- ++
- ++void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
- ++{
- ++ struct wmi_phyerr_ev_arg arg = {};
- ++ const struct wmi_phyerr *phyerr;
- ++ u32 count, i, buf_len, phy_err_code;
- ++ u64 tsf;
- ++ int left_len, ret;
- ++
- ++ ATH10K_DFS_STAT_INC(ar, phy_errors);
- ++
- ++ ret = ath10k_wmi_pull_phyerr(ar, skb, &arg);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to parse phyerr event: %d\n", ret);
- ++ return;
- ++ }
- ++
- ++ left_len = __le32_to_cpu(arg.buf_len);
- ++
- ++ /* Check number of included events */
- ++ count = __le32_to_cpu(arg.num_phyerrs);
- ++
- ++ tsf = __le32_to_cpu(arg.tsf_u32);
- ++ tsf <<= 32;
- ++ tsf |= __le32_to_cpu(arg.tsf_l32);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi event phyerr count %d tsf64 0x%llX\n",
- ++ count, tsf);
- ++
- ++ phyerr = arg.phyerrs;
- ++ for (i = 0; i < count; i++) {
- ++ /* Check if we can read event header */
- ++ if (left_len < sizeof(*phyerr)) {
- ++ ath10k_warn(ar, "single event (%d) wrong head len\n",
- ++ i);
- ++ return;
- ++ }
- ++
- ++ left_len -= sizeof(*phyerr);
- ++
- ++ buf_len = __le32_to_cpu(phyerr->buf_len);
- ++ phy_err_code = phyerr->phy_err_code;
- +
- + if (left_len < buf_len) {
- +- ath10k_warn("single event (%d) wrong buf len\n", i);
- ++ ath10k_warn(ar, "single event (%d) wrong buf len\n", i);
- + return;
- + }
- +
- +@@ -1698,36 +2853,34 @@ static void ath10k_wmi_event_phyerr(stru
- +
- + switch (phy_err_code) {
- + case PHY_ERROR_RADAR:
- +- ath10k_wmi_event_dfs(ar, event, tsf);
- ++ ath10k_wmi_event_dfs(ar, phyerr, tsf);
- + break;
- + case PHY_ERROR_SPECTRAL_SCAN:
- +- ath10k_wmi_event_spectral_scan(ar, event, tsf);
- ++ ath10k_wmi_event_spectral_scan(ar, phyerr, tsf);
- + break;
- + case PHY_ERROR_FALSE_RADAR_EXT:
- +- ath10k_wmi_event_dfs(ar, event, tsf);
- +- ath10k_wmi_event_spectral_scan(ar, event, tsf);
- ++ ath10k_wmi_event_dfs(ar, phyerr, tsf);
- ++ ath10k_wmi_event_spectral_scan(ar, phyerr, tsf);
- + break;
- + default:
- + break;
- + }
- +
- +- event += sizeof(*event) + buf_len;
- ++ phyerr = (void *)phyerr + sizeof(*phyerr) + buf_len;
- + }
- + }
- +
- +-static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
- ++void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_profile_match(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n");
- + }
- +
- +-static void ath10k_wmi_event_debug_print(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb)
- + {
- + char buf[101], c;
- + int i;
- +@@ -1748,7 +2901,7 @@ static void ath10k_wmi_event_debug_print
- + }
- +
- + if (i == sizeof(buf) - 1)
- +- ath10k_warn("wmi debug print truncated: %d\n", skb->len);
- ++ ath10k_warn(ar, "wmi debug print truncated: %d\n", skb->len);
- +
- + /* for some reason the debug prints end with \n, remove that */
- + if (skb->data[i - 1] == '\n')
- +@@ -1757,112 +2910,99 @@ static void ath10k_wmi_event_debug_print
- + /* the last byte is always reserved for the null character */
- + buf[i] = '\0';
- +
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf);
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI_PRINT, "wmi print '%s'\n", buf);
- + }
- +
- +-static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
- ++void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar,
- ++void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar,
- + struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar,
- ++void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar,
- + struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_rtt_error_report(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_dcs_interference(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_delba_complete(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_delba_complete(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_addba_complete(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_addba_complete(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
- ++void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
- + struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n");
- + }
- +
- +-static void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
- + }
- +
- + static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
- +- u32 num_units, u32 unit_len)
- ++ u32 num_units, u32 unit_len)
- + {
- + dma_addr_t paddr;
- + u32 pool_size;
- +@@ -1878,7 +3018,7 @@ static int ath10k_wmi_alloc_host_mem(str
- + &paddr,
- + GFP_ATOMIC);
- + if (!ar->wmi.mem_chunks[idx].vaddr) {
- +- ath10k_warn("failed to allocate memory chunk\n");
- ++ ath10k_warn(ar, "failed to allocate memory chunk\n");
- + return -ENOMEM;
- + }
- +
- +@@ -1892,45 +3032,124 @@ static int ath10k_wmi_alloc_host_mem(str
- + return 0;
- + }
- +
- +-static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
- +- struct sk_buff *skb)
- ++static int
- ++ath10k_wmi_main_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_svc_rdy_ev_arg *arg)
- ++{
- ++ struct wmi_service_ready_event *ev;
- ++ size_t i, n;
- ++
- ++ if (skb->len < sizeof(*ev))
- ++ return -EPROTO;
- ++
- ++ ev = (void *)skb->data;
- ++ skb_pull(skb, sizeof(*ev));
- ++ arg->min_tx_power = ev->hw_min_tx_power;
- ++ arg->max_tx_power = ev->hw_max_tx_power;
- ++ arg->ht_cap = ev->ht_cap_info;
- ++ arg->vht_cap = ev->vht_cap_info;
- ++ arg->sw_ver0 = ev->sw_version;
- ++ arg->sw_ver1 = ev->sw_version_1;
- ++ arg->phy_capab = ev->phy_capability;
- ++ arg->num_rf_chains = ev->num_rf_chains;
- ++ arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
- ++ arg->num_mem_reqs = ev->num_mem_reqs;
- ++ arg->service_map = ev->wmi_service_bitmap;
- ++ arg->service_map_len = sizeof(ev->wmi_service_bitmap);
- ++
- ++ n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs),
- ++ ARRAY_SIZE(arg->mem_reqs));
- ++ for (i = 0; i < n; i++)
- ++ arg->mem_reqs[i] = &ev->mem_reqs[i];
- ++
- ++ if (skb->len <
- ++ __le32_to_cpu(arg->num_mem_reqs) * sizeof(arg->mem_reqs[0]))
- ++ return -EPROTO;
- ++
- ++ return 0;
- ++}
- ++
- ++static int
- ++ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_svc_rdy_ev_arg *arg)
- ++{
- ++ struct wmi_10x_service_ready_event *ev;
- ++ int i, n;
- ++
- ++ if (skb->len < sizeof(*ev))
- ++ return -EPROTO;
- ++
- ++ ev = (void *)skb->data;
- ++ skb_pull(skb, sizeof(*ev));
- ++ arg->min_tx_power = ev->hw_min_tx_power;
- ++ arg->max_tx_power = ev->hw_max_tx_power;
- ++ arg->ht_cap = ev->ht_cap_info;
- ++ arg->vht_cap = ev->vht_cap_info;
- ++ arg->sw_ver0 = ev->sw_version;
- ++ arg->phy_capab = ev->phy_capability;
- ++ arg->num_rf_chains = ev->num_rf_chains;
- ++ arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
- ++ arg->num_mem_reqs = ev->num_mem_reqs;
- ++ arg->service_map = ev->wmi_service_bitmap;
- ++ arg->service_map_len = sizeof(ev->wmi_service_bitmap);
- ++
- ++ n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs),
- ++ ARRAY_SIZE(arg->mem_reqs));
- ++ for (i = 0; i < n; i++)
- ++ arg->mem_reqs[i] = &ev->mem_reqs[i];
- ++
- ++ if (skb->len <
- ++ __le32_to_cpu(arg->num_mem_reqs) * sizeof(arg->mem_reqs[0]))
- ++ return -EPROTO;
- ++
- ++ return 0;
- ++}
- ++
- ++void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- struct wmi_service_ready_event *ev = (void *)skb->data;
- ++ struct wmi_svc_rdy_ev_arg arg = {};
- ++ u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
- ++ int ret;
- +
- +- if (skb->len < sizeof(*ev)) {
- +- ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
- +- skb->len, sizeof(*ev));
- ++ ret = ath10k_wmi_pull_svc_rdy(ar, skb, &arg);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to parse service ready: %d\n", ret);
- + return;
- + }
- +
- +- ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power);
- +- ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power);
- +- ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info);
- +- ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info);
- ++ memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map));
- ++ ath10k_wmi_map_svc(ar, arg.service_map, ar->wmi.svc_map,
- ++ arg.service_map_len);
- ++
- ++ ar->hw_min_tx_power = __le32_to_cpu(arg.min_tx_power);
- ++ ar->hw_max_tx_power = __le32_to_cpu(arg.max_tx_power);
- ++ ar->ht_cap_info = __le32_to_cpu(arg.ht_cap);
- ++ ar->vht_cap_info = __le32_to_cpu(arg.vht_cap);
- + ar->fw_version_major =
- +- (__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24;
- +- ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff);
- ++ (__le32_to_cpu(arg.sw_ver0) & 0xff000000) >> 24;
- ++ ar->fw_version_minor = (__le32_to_cpu(arg.sw_ver0) & 0x00ffffff);
- + ar->fw_version_release =
- +- (__le32_to_cpu(ev->sw_version_1) & 0xffff0000) >> 16;
- +- ar->fw_version_build = (__le32_to_cpu(ev->sw_version_1) & 0x0000ffff);
- +- ar->phy_capability = __le32_to_cpu(ev->phy_capability);
- +- ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
- ++ (__le32_to_cpu(arg.sw_ver1) & 0xffff0000) >> 16;
- ++ ar->fw_version_build = (__le32_to_cpu(arg.sw_ver1) & 0x0000ffff);
- ++ ar->phy_capability = __le32_to_cpu(arg.phy_capab);
- ++ ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains);
- ++ ar->ath_common.regulatory.current_rd = __le32_to_cpu(arg.eeprom_rd);
- ++
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
- ++ arg.service_map, arg.service_map_len);
- +
- + /* only manually set fw features when not using FW IE format */
- + if (ar->fw_api == 1 && ar->fw_version_build > 636)
- + set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features);
- +
- + if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
- +- ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
- ++ ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
- + ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
- + ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
- + }
- +
- +- ar->ath_common.regulatory.current_rd =
- +- __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
- +-
- +- ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap,
- +- sizeof(ev->wmi_service_bitmap));
- ++ ar->supp_tx_chainmask = (1 << ar->num_rf_chains) - 1;
- ++ ar->supp_rx_chainmask = (1 << ar->num_rf_chains) - 1;
- +
- + if (strlen(ar->hw->wiphy->fw_version) == 0) {
- + snprintf(ar->hw->wiphy->fw_version,
- +@@ -1942,90 +3161,18 @@ static void ath10k_wmi_service_ready_eve
- + ar->fw_version_build);
- + }
- +
- +- /* FIXME: it probably should be better to support this */
- +- if (__le32_to_cpu(ev->num_mem_reqs) > 0) {
- +- ath10k_warn("target requested %d memory chunks; ignoring\n",
- +- __le32_to_cpu(ev->num_mem_reqs));
- +- }
- +-
- +- ath10k_dbg(ATH10K_DBG_WMI,
- +- "wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
- +- __le32_to_cpu(ev->sw_version),
- +- __le32_to_cpu(ev->sw_version_1),
- +- __le32_to_cpu(ev->abi_version),
- +- __le32_to_cpu(ev->phy_capability),
- +- __le32_to_cpu(ev->ht_cap_info),
- +- __le32_to_cpu(ev->vht_cap_info),
- +- __le32_to_cpu(ev->vht_supp_mcs),
- +- __le32_to_cpu(ev->sys_cap_info),
- +- __le32_to_cpu(ev->num_mem_reqs),
- +- __le32_to_cpu(ev->num_rf_chains));
- +-
- +- complete(&ar->wmi.service_ready);
- +-}
- +-
- +-static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
- +- struct sk_buff *skb)
- +-{
- +- u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
- +- int ret;
- +- struct wmi_service_ready_event_10x *ev = (void *)skb->data;
- +-
- +- if (skb->len < sizeof(*ev)) {
- +- ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
- +- skb->len, sizeof(*ev));
- +- return;
- +- }
- +-
- +- ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power);
- +- ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power);
- +- ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info);
- +- ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info);
- +- ar->fw_version_major =
- +- (__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24;
- +- ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff);
- +- ar->phy_capability = __le32_to_cpu(ev->phy_capability);
- +- ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
- +-
- +- if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
- +- ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
- +- ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
- +- ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
- +- }
- +-
- +- ar->ath_common.regulatory.current_rd =
- +- __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
- +-
- +- ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap,
- +- sizeof(ev->wmi_service_bitmap));
- +-
- +- if (strlen(ar->hw->wiphy->fw_version) == 0) {
- +- snprintf(ar->hw->wiphy->fw_version,
- +- sizeof(ar->hw->wiphy->fw_version),
- +- "%u.%u",
- +- ar->fw_version_major,
- +- ar->fw_version_minor);
- +- }
- +-
- +- num_mem_reqs = __le32_to_cpu(ev->num_mem_reqs);
- +-
- +- if (num_mem_reqs > ATH10K_MAX_MEM_REQS) {
- +- ath10k_warn("requested memory chunks number (%d) exceeds the limit\n",
- ++ num_mem_reqs = __le32_to_cpu(arg.num_mem_reqs);
- ++ if (num_mem_reqs > WMI_MAX_MEM_REQS) {
- ++ ath10k_warn(ar, "requested memory chunks number (%d) exceeds the limit\n",
- + num_mem_reqs);
- + return;
- + }
- +
- +- if (!num_mem_reqs)
- +- goto exit;
- +-
- +- ath10k_dbg(ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n",
- +- num_mem_reqs);
- +-
- + for (i = 0; i < num_mem_reqs; ++i) {
- +- req_id = __le32_to_cpu(ev->mem_reqs[i].req_id);
- +- num_units = __le32_to_cpu(ev->mem_reqs[i].num_units);
- +- unit_size = __le32_to_cpu(ev->mem_reqs[i].unit_size);
- +- num_unit_info = __le32_to_cpu(ev->mem_reqs[i].num_unit_info);
- ++ req_id = __le32_to_cpu(arg.mem_reqs[i]->req_id);
- ++ num_units = __le32_to_cpu(arg.mem_reqs[i]->num_units);
- ++ unit_size = __le32_to_cpu(arg.mem_reqs[i]->unit_size);
- ++ num_unit_info = __le32_to_cpu(arg.mem_reqs[i]->num_unit_info);
- +
- + if (num_unit_info & NUM_UNITS_IS_NUM_PEERS)
- + /* number of units to allocate is number of
- +@@ -2036,10 +3183,10 @@ static void ath10k_wmi_10x_service_ready
- + else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS)
- + num_units = TARGET_10X_NUM_VDEVS + 1;
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n",
- + req_id,
- +- __le32_to_cpu(ev->mem_reqs[i].num_units),
- ++ __le32_to_cpu(arg.mem_reqs[i]->num_units),
- + num_unit_info,
- + unit_size,
- + num_units);
- +@@ -2050,47 +3197,79 @@ static void ath10k_wmi_10x_service_ready
- + return;
- + }
- +
- +-exit:
- +- ath10k_dbg(ATH10K_DBG_WMI,
- +- "wmi event service ready sw_ver 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
- +- __le32_to_cpu(ev->sw_version),
- +- __le32_to_cpu(ev->abi_version),
- +- __le32_to_cpu(ev->phy_capability),
- +- __le32_to_cpu(ev->ht_cap_info),
- +- __le32_to_cpu(ev->vht_cap_info),
- +- __le32_to_cpu(ev->vht_supp_mcs),
- +- __le32_to_cpu(ev->sys_cap_info),
- +- __le32_to_cpu(ev->num_mem_reqs),
- +- __le32_to_cpu(ev->num_rf_chains));
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x fw_build 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n",
- ++ __le32_to_cpu(arg.min_tx_power),
- ++ __le32_to_cpu(arg.max_tx_power),
- ++ __le32_to_cpu(arg.ht_cap),
- ++ __le32_to_cpu(arg.vht_cap),
- ++ __le32_to_cpu(arg.sw_ver0),
- ++ __le32_to_cpu(arg.sw_ver1),
- ++ __le32_to_cpu(arg.fw_build),
- ++ __le32_to_cpu(arg.phy_capab),
- ++ __le32_to_cpu(arg.num_rf_chains),
- ++ __le32_to_cpu(arg.eeprom_rd),
- ++ __le32_to_cpu(arg.num_mem_reqs));
- +
- + complete(&ar->wmi.service_ready);
- + }
- +
- +-static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb)
- ++static int ath10k_wmi_op_pull_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_rdy_ev_arg *arg)
- + {
- +- struct wmi_ready_event *ev = (struct wmi_ready_event *)skb->data;
- ++ struct wmi_ready_event *ev = (void *)skb->data;
- +
- +- if (WARN_ON(skb->len < sizeof(*ev)))
- +- return -EINVAL;
- ++ if (skb->len < sizeof(*ev))
- ++ return -EPROTO;
- ++
- ++ skb_pull(skb, sizeof(*ev));
- ++ arg->sw_version = ev->sw_version;
- ++ arg->abi_version = ev->abi_version;
- ++ arg->status = ev->status;
- ++ arg->mac_addr = ev->mac_addr.addr;
- ++
- ++ return 0;
- ++}
- ++
- ++int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
- ++{
- ++ struct wmi_rdy_ev_arg arg = {};
- ++ int ret;
- +
- +- memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN);
- ++ ret = ath10k_wmi_pull_rdy(ar, skb, &arg);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to parse ready event: %d\n", ret);
- ++ return ret;
- ++ }
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- +- "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n",
- +- __le32_to_cpu(ev->sw_version),
- +- __le32_to_cpu(ev->abi_version),
- +- ev->mac_addr.addr,
- +- __le32_to_cpu(ev->status), skb->len, sizeof(*ev));
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n",
- ++ __le32_to_cpu(arg.sw_version),
- ++ __le32_to_cpu(arg.abi_version),
- ++ arg.mac_addr,
- ++ __le32_to_cpu(arg.status));
- +
- ++ ether_addr_copy(ar->mac_addr, arg.mac_addr);
- + complete(&ar->wmi.unified_ready);
- + return 0;
- + }
- +
- +-static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb)
- ++static int ath10k_wmi_event_temperature(struct ath10k *ar, struct sk_buff *skb)
- ++{
- ++ const struct wmi_pdev_temperature_event *ev;
- ++
- ++ ev = (struct wmi_pdev_temperature_event *)skb->data;
- ++ if (WARN_ON(skb->len < sizeof(*ev)))
- ++ return -EPROTO;
- ++
- ++ ath10k_thermal_event_temperature(ar, __le32_to_cpu(ev->temperature));
- ++ return 0;
- ++}
- ++
- ++static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
- + {
- + struct wmi_cmd_hdr *cmd_hdr;
- + enum wmi_event_id id;
- +- u16 len;
- +
- + cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
- + id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
- +@@ -2098,9 +3277,7 @@ static void ath10k_wmi_main_process_rx(s
- + if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
- + return;
- +
- +- len = skb->len;
- +-
- +- trace_ath10k_wmi_event(id, skb->data, skb->len);
- ++ trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
- +
- + switch (id) {
- + case WMI_MGMT_RX_EVENTID:
- +@@ -2192,24 +3369,24 @@ static void ath10k_wmi_main_process_rx(s
- + ath10k_wmi_event_vdev_install_key_complete(ar, skb);
- + break;
- + case WMI_SERVICE_READY_EVENTID:
- +- ath10k_wmi_service_ready_event_rx(ar, skb);
- ++ ath10k_wmi_event_service_ready(ar, skb);
- + break;
- + case WMI_READY_EVENTID:
- +- ath10k_wmi_ready_event_rx(ar, skb);
- ++ ath10k_wmi_event_ready(ar, skb);
- + break;
- + default:
- +- ath10k_warn("Unknown eventid: %d\n", id);
- ++ ath10k_warn(ar, "Unknown eventid: %d\n", id);
- + break;
- + }
- +
- + dev_kfree_skb(skb);
- + }
- +
- +-static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
- ++static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
- + {
- + struct wmi_cmd_hdr *cmd_hdr;
- + enum wmi_10x_event_id id;
- +- u16 len;
- ++ bool consumed;
- +
- + cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
- + id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
- +@@ -2217,9 +3394,19 @@ static void ath10k_wmi_10x_process_rx(st
- + if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
- + return;
- +
- +- len = skb->len;
- ++ trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
- ++
- ++ consumed = ath10k_tm_event_wmi(ar, id, skb);
- +
- +- trace_ath10k_wmi_event(id, skb->data, skb->len);
- ++ /* Ready event must be handled normally also in UTF mode so that we
- ++ * know the UTF firmware has booted, others we are just bypass WMI
- ++ * events to testmode.
- ++ */
- ++ if (consumed && id != WMI_10X_READY_EVENTID) {
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi testmode consumed 0x%x\n", id);
- ++ goto out;
- ++ }
- +
- + switch (id) {
- + case WMI_10X_MGMT_RX_EVENTID:
- +@@ -2302,64 +3489,153 @@ static void ath10k_wmi_10x_process_rx(st
- + ath10k_wmi_event_vdev_resume_req(ar, skb);
- + break;
- + case WMI_10X_SERVICE_READY_EVENTID:
- +- ath10k_wmi_10x_service_ready_event_rx(ar, skb);
- ++ ath10k_wmi_event_service_ready(ar, skb);
- + break;
- + case WMI_10X_READY_EVENTID:
- +- ath10k_wmi_ready_event_rx(ar, skb);
- ++ ath10k_wmi_event_ready(ar, skb);
- ++ break;
- ++ case WMI_10X_PDEV_UTF_EVENTID:
- ++ /* ignore utf events */
- + break;
- + default:
- +- ath10k_warn("Unknown eventid: %d\n", id);
- ++ ath10k_warn(ar, "Unknown eventid: %d\n", id);
- + break;
- + }
- +
- ++out:
- + dev_kfree_skb(skb);
- + }
- +
- +-
- +-static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)
- ++static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- +- ath10k_wmi_10x_process_rx(ar, skb);
- +- else
- +- ath10k_wmi_main_process_rx(ar, skb);
- +-}
- ++ struct wmi_cmd_hdr *cmd_hdr;
- ++ enum wmi_10_2_event_id id;
- +
- +-/* WMI Initialization functions */
- +-int ath10k_wmi_attach(struct ath10k *ar)
- +-{
- +- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- +- ar->wmi.cmd = &wmi_10x_cmd_map;
- +- ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
- +- ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
- +- } else {
- +- ar->wmi.cmd = &wmi_cmd_map;
- +- ar->wmi.vdev_param = &wmi_vdev_param_map;
- +- ar->wmi.pdev_param = &wmi_pdev_param_map;
- +- }
- ++ cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
- ++ id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
- +
- +- init_completion(&ar->wmi.service_ready);
- +- init_completion(&ar->wmi.unified_ready);
- +- init_waitqueue_head(&ar->wmi.tx_credits_wq);
- ++ if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
- ++ return;
- +
- +- return 0;
- ++ trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
- ++
- ++ switch (id) {
- ++ case WMI_10_2_MGMT_RX_EVENTID:
- ++ ath10k_wmi_event_mgmt_rx(ar, skb);
- ++ /* mgmt_rx() owns the skb now! */
- ++ return;
- ++ case WMI_10_2_SCAN_EVENTID:
- ++ ath10k_wmi_event_scan(ar, skb);
- ++ break;
- ++ case WMI_10_2_CHAN_INFO_EVENTID:
- ++ ath10k_wmi_event_chan_info(ar, skb);
- ++ break;
- ++ case WMI_10_2_ECHO_EVENTID:
- ++ ath10k_wmi_event_echo(ar, skb);
- ++ break;
- ++ case WMI_10_2_DEBUG_MESG_EVENTID:
- ++ ath10k_wmi_event_debug_mesg(ar, skb);
- ++ break;
- ++ case WMI_10_2_UPDATE_STATS_EVENTID:
- ++ ath10k_wmi_event_update_stats(ar, skb);
- ++ break;
- ++ case WMI_10_2_VDEV_START_RESP_EVENTID:
- ++ ath10k_wmi_event_vdev_start_resp(ar, skb);
- ++ break;
- ++ case WMI_10_2_VDEV_STOPPED_EVENTID:
- ++ ath10k_wmi_event_vdev_stopped(ar, skb);
- ++ break;
- ++ case WMI_10_2_PEER_STA_KICKOUT_EVENTID:
- ++ ath10k_wmi_event_peer_sta_kickout(ar, skb);
- ++ break;
- ++ case WMI_10_2_HOST_SWBA_EVENTID:
- ++ ath10k_wmi_event_host_swba(ar, skb);
- ++ break;
- ++ case WMI_10_2_TBTTOFFSET_UPDATE_EVENTID:
- ++ ath10k_wmi_event_tbttoffset_update(ar, skb);
- ++ break;
- ++ case WMI_10_2_PHYERR_EVENTID:
- ++ ath10k_wmi_event_phyerr(ar, skb);
- ++ break;
- ++ case WMI_10_2_ROAM_EVENTID:
- ++ ath10k_wmi_event_roam(ar, skb);
- ++ break;
- ++ case WMI_10_2_PROFILE_MATCH:
- ++ ath10k_wmi_event_profile_match(ar, skb);
- ++ break;
- ++ case WMI_10_2_DEBUG_PRINT_EVENTID:
- ++ ath10k_wmi_event_debug_print(ar, skb);
- ++ break;
- ++ case WMI_10_2_PDEV_QVIT_EVENTID:
- ++ ath10k_wmi_event_pdev_qvit(ar, skb);
- ++ break;
- ++ case WMI_10_2_WLAN_PROFILE_DATA_EVENTID:
- ++ ath10k_wmi_event_wlan_profile_data(ar, skb);
- ++ break;
- ++ case WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID:
- ++ ath10k_wmi_event_rtt_measurement_report(ar, skb);
- ++ break;
- ++ case WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID:
- ++ ath10k_wmi_event_tsf_measurement_report(ar, skb);
- ++ break;
- ++ case WMI_10_2_RTT_ERROR_REPORT_EVENTID:
- ++ ath10k_wmi_event_rtt_error_report(ar, skb);
- ++ break;
- ++ case WMI_10_2_WOW_WAKEUP_HOST_EVENTID:
- ++ ath10k_wmi_event_wow_wakeup_host(ar, skb);
- ++ break;
- ++ case WMI_10_2_DCS_INTERFERENCE_EVENTID:
- ++ ath10k_wmi_event_dcs_interference(ar, skb);
- ++ break;
- ++ case WMI_10_2_PDEV_TPC_CONFIG_EVENTID:
- ++ ath10k_wmi_event_pdev_tpc_config(ar, skb);
- ++ break;
- ++ case WMI_10_2_INST_RSSI_STATS_EVENTID:
- ++ ath10k_wmi_event_inst_rssi_stats(ar, skb);
- ++ break;
- ++ case WMI_10_2_VDEV_STANDBY_REQ_EVENTID:
- ++ ath10k_wmi_event_vdev_standby_req(ar, skb);
- ++ break;
- ++ case WMI_10_2_VDEV_RESUME_REQ_EVENTID:
- ++ ath10k_wmi_event_vdev_resume_req(ar, skb);
- ++ break;
- ++ case WMI_10_2_SERVICE_READY_EVENTID:
- ++ ath10k_wmi_event_service_ready(ar, skb);
- ++ break;
- ++ case WMI_10_2_READY_EVENTID:
- ++ ath10k_wmi_event_ready(ar, skb);
- ++ break;
- ++ case WMI_10_2_PDEV_TEMPERATURE_EVENTID:
- ++ ath10k_wmi_event_temperature(ar, skb);
- ++ break;
- ++ case WMI_10_2_RTT_KEEPALIVE_EVENTID:
- ++ case WMI_10_2_GPIO_INPUT_EVENTID:
- ++ case WMI_10_2_PEER_RATECODE_LIST_EVENTID:
- ++ case WMI_10_2_GENERIC_BUFFER_EVENTID:
- ++ case WMI_10_2_MCAST_BUF_RELEASE_EVENTID:
- ++ case WMI_10_2_MCAST_LIST_AGEOUT_EVENTID:
- ++ case WMI_10_2_WDS_PEER_EVENTID:
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "received event id %d not implemented\n", id);
- ++ break;
- ++ default:
- ++ ath10k_warn(ar, "Unknown eventid: %d\n", id);
- ++ break;
- ++ }
- ++
- ++ dev_kfree_skb(skb);
- + }
- +
- +-void ath10k_wmi_detach(struct ath10k *ar)
- ++static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)
- + {
- +- int i;
- +-
- +- /* free the host memory chunks requested by firmware */
- +- for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
- +- dma_free_coherent(ar->dev,
- +- ar->wmi.mem_chunks[i].len,
- +- ar->wmi.mem_chunks[i].vaddr,
- +- ar->wmi.mem_chunks[i].paddr);
- +- }
- ++ int ret;
- +
- +- ar->wmi.num_mem_chunks = 0;
- ++ ret = ath10k_wmi_rx(ar, skb);
- ++ if (ret)
- ++ ath10k_warn(ar, "failed to process wmi rx: %d\n", ret);
- + }
- +
- +-int ath10k_wmi_connect_htc_service(struct ath10k *ar)
- ++int ath10k_wmi_connect(struct ath10k *ar)
- + {
- + int status;
- + struct ath10k_htc_svc_conn_req conn_req;
- +@@ -2378,7 +3654,7 @@ int ath10k_wmi_connect_htc_service(struc
- +
- + status = ath10k_htc_connect_service(&ar->htc, &conn_req, &conn_resp);
- + if (status) {
- +- ath10k_warn("failed to connect to WMI CONTROL service status: %d\n",
- ++ ath10k_warn(ar, "failed to connect to WMI CONTROL service status: %d\n",
- + status);
- + return status;
- + }
- +@@ -2387,16 +3663,17 @@ int ath10k_wmi_connect_htc_service(struc
- + return 0;
- + }
- +
- +-static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd,
- +- u16 rd2g, u16 rd5g, u16 ctl2g,
- +- u16 ctl5g)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_pdev_set_rd(struct ath10k *ar, u16 rd, u16 rd2g, u16 rd5g,
- ++ u16 ctl2g, u16 ctl5g,
- ++ enum wmi_dfs_region dfs_reg)
- + {
- + struct wmi_pdev_set_regdomain_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_pdev_set_regdomain_cmd *)skb->data;
- + cmd->reg_domain = __cpu_to_le32(rd);
- +@@ -2405,25 +3682,23 @@ static int ath10k_wmi_main_pdev_set_regd
- + cmd->conformance_test_limit_2G = __cpu_to_le32(ctl2g);
- + cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x\n",
- + rd, rd2g, rd5g, ctl2g, ctl5g);
- +-
- +- return ath10k_wmi_cmd_send(ar, skb,
- +- ar->wmi.cmd->pdev_set_regdomain_cmdid);
- ++ return skb;
- + }
- +
- +-static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd,
- +- u16 rd2g, u16 rd5g,
- +- u16 ctl2g, u16 ctl5g,
- +- enum wmi_dfs_region dfs_reg)
- ++static struct sk_buff *
- ++ath10k_wmi_10x_op_gen_pdev_set_rd(struct ath10k *ar, u16 rd, u16 rd2g, u16
- ++ rd5g, u16 ctl2g, u16 ctl5g,
- ++ enum wmi_dfs_region dfs_reg)
- + {
- + struct wmi_pdev_set_regdomain_cmd_10x *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_pdev_set_regdomain_cmd_10x *)skb->data;
- + cmd->reg_domain = __cpu_to_le32(rd);
- +@@ -2433,121 +3708,96 @@ static int ath10k_wmi_10x_pdev_set_regdo
- + cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g);
- + cmd->dfs_domain = __cpu_to_le32(dfs_reg);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n",
- + rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg);
- +-
- +- return ath10k_wmi_cmd_send(ar, skb,
- +- ar->wmi.cmd->pdev_set_regdomain_cmdid);
- +-}
- +-
- +-int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
- +- u16 rd5g, u16 ctl2g, u16 ctl5g,
- +- enum wmi_dfs_region dfs_reg)
- +-{
- +- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- +- return ath10k_wmi_10x_pdev_set_regdomain(ar, rd, rd2g, rd5g,
- +- ctl2g, ctl5g, dfs_reg);
- +- else
- +- return ath10k_wmi_main_pdev_set_regdomain(ar, rd, rd2g, rd5g,
- +- ctl2g, ctl5g);
- +-}
- +-
- +-int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
- +- const struct wmi_channel_arg *arg)
- +-{
- +- struct wmi_set_channel_cmd *cmd;
- +- struct sk_buff *skb;
- +- u32 ch_flags = 0;
- +-
- +- if (arg->passive)
- +- return -EINVAL;
- +-
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- +- if (!skb)
- +- return -ENOMEM;
- +-
- +- if (arg->chan_radar)
- +- ch_flags |= WMI_CHAN_FLAG_DFS;
- +-
- +- cmd = (struct wmi_set_channel_cmd *)skb->data;
- +- cmd->chan.mhz = __cpu_to_le32(arg->freq);
- +- cmd->chan.band_center_freq1 = __cpu_to_le32(arg->freq);
- +- cmd->chan.mode = arg->mode;
- +- cmd->chan.flags |= __cpu_to_le32(ch_flags);
- +- cmd->chan.min_power = arg->min_power;
- +- cmd->chan.max_power = arg->max_power;
- +- cmd->chan.reg_power = arg->max_reg_power;
- +- cmd->chan.reg_classid = arg->reg_class_id;
- +- cmd->chan.antenna_max = arg->max_antenna_gain;
- +-
- +- ath10k_dbg(ATH10K_DBG_WMI,
- +- "wmi set channel mode %d freq %d\n",
- +- arg->mode, arg->freq);
- +-
- +- return ath10k_wmi_cmd_send(ar, skb,
- +- ar->wmi.cmd->pdev_set_channel_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_pdev_suspend(struct ath10k *ar, u32 suspend_opt)
- + {
- + struct wmi_pdev_suspend_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_pdev_suspend_cmd *)skb->data;
- + cmd->suspend_opt = __cpu_to_le32(suspend_opt);
- +
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_pdev_resume_target(struct ath10k *ar)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_pdev_resume(struct ath10k *ar)
- + {
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(0);
- +- if (skb == NULL)
- +- return -ENOMEM;
- ++ skb = ath10k_wmi_alloc_skb(ar, 0);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- +
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_resume_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
- + {
- + struct wmi_pdev_set_param_cmd *cmd;
- + struct sk_buff *skb;
- +
- + if (id == WMI_PDEV_PARAM_UNSUPPORTED) {
- +- ath10k_warn("pdev param %d not supported by firmware\n", id);
- +- return -EOPNOTSUPP;
- ++ ath10k_warn(ar, "pdev param %d not supported by firmware\n",
- ++ id);
- ++ return ERR_PTR(-EOPNOTSUPP);
- + }
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_pdev_set_param_cmd *)skb->data;
- + cmd->param_id = __cpu_to_le32(id);
- + cmd->param_value = __cpu_to_le32(value);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n",
- + id, value);
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);
- ++ return skb;
- + }
- +
- +-static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
- ++void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
- ++ struct wmi_host_mem_chunks *chunks)
- + {
- +- struct wmi_init_cmd *cmd;
- +- struct sk_buff *buf;
- +- struct wmi_resource_config config = {};
- +- u32 len, val;
- ++ struct host_memory_chunk *chunk;
- + int i;
- +
- +- config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS);
- +- config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS);
- ++ chunks->count = __cpu_to_le32(ar->wmi.num_mem_chunks);
- ++
- ++ for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
- ++ chunk = &chunks->items[i];
- ++ chunk->ptr = __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
- ++ chunk->size = __cpu_to_le32(ar->wmi.mem_chunks[i].len);
- ++ chunk->req_id = __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi chunk %d len %d requested, addr 0x%llx\n",
- ++ i,
- ++ ar->wmi.mem_chunks[i].len,
- ++ (unsigned long long)ar->wmi.mem_chunks[i].paddr);
- ++ }
- ++}
- ++
- ++static struct sk_buff *ath10k_wmi_op_gen_init(struct ath10k *ar)
- ++{
- ++ struct wmi_init_cmd *cmd;
- ++ struct sk_buff *buf;
- ++ struct wmi_resource_config config = {};
- ++ u32 len, val;
- ++
- ++ config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS);
- ++ config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS);
- + config.num_offload_peers = __cpu_to_le32(TARGET_NUM_OFFLOAD_PEERS);
- +
- + config.num_offload_reorder_bufs =
- +@@ -2600,50 +3850,25 @@ static int ath10k_wmi_main_cmd_init(stru
- + len = sizeof(*cmd) +
- + (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
- +
- +- buf = ath10k_wmi_alloc_skb(len);
- ++ buf = ath10k_wmi_alloc_skb(ar, len);
- + if (!buf)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_init_cmd *)buf->data;
- +
- +- if (ar->wmi.num_mem_chunks == 0) {
- +- cmd->num_host_mem_chunks = 0;
- +- goto out;
- +- }
- +-
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
- +- ar->wmi.num_mem_chunks);
- +-
- +- cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
- +-
- +- for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
- +- cmd->host_mem_chunks[i].ptr =
- +- __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
- +- cmd->host_mem_chunks[i].size =
- +- __cpu_to_le32(ar->wmi.mem_chunks[i].len);
- +- cmd->host_mem_chunks[i].req_id =
- +- __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
- +-
- +- ath10k_dbg(ATH10K_DBG_WMI,
- +- "wmi chunk %d len %d requested, addr 0x%llx\n",
- +- i,
- +- ar->wmi.mem_chunks[i].len,
- +- (unsigned long long)ar->wmi.mem_chunks[i].paddr);
- +- }
- +-out:
- + memcpy(&cmd->resource_config, &config, sizeof(config));
- ++ ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi init\n");
- +- return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n");
- ++ return buf;
- + }
- +
- +-static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
- ++static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
- + {
- + struct wmi_init_cmd_10x *cmd;
- + struct sk_buff *buf;
- + struct wmi_resource_config_10x config = {};
- + u32 len, val;
- +- int i;
- +
- + config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
- + config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
- +@@ -2691,101 +3916,132 @@ static int ath10k_wmi_10x_cmd_init(struc
- + len = sizeof(*cmd) +
- + (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
- +
- +- buf = ath10k_wmi_alloc_skb(len);
- ++ buf = ath10k_wmi_alloc_skb(ar, len);
- + if (!buf)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_init_cmd_10x *)buf->data;
- +
- +- if (ar->wmi.num_mem_chunks == 0) {
- +- cmd->num_host_mem_chunks = 0;
- +- goto out;
- +- }
- ++ memcpy(&cmd->resource_config, &config, sizeof(config));
- ++ ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
- +- ar->wmi.num_mem_chunks);
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n");
- ++ return buf;
- ++}
- +
- +- cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
- ++static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
- ++{
- ++ struct wmi_init_cmd_10_2 *cmd;
- ++ struct sk_buff *buf;
- ++ struct wmi_resource_config_10x config = {};
- ++ u32 len, val, features;
- +
- +- for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
- +- cmd->host_mem_chunks[i].ptr =
- +- __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
- +- cmd->host_mem_chunks[i].size =
- +- __cpu_to_le32(ar->wmi.mem_chunks[i].len);
- +- cmd->host_mem_chunks[i].req_id =
- +- __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
- ++ config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
- ++ config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
- ++ config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
- ++ config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
- ++ config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT);
- ++ config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK);
- ++ config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK);
- ++ config.rx_timeout_pri_vo = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
- ++ config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
- ++ config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
- ++ config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI);
- ++ config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- +- "wmi chunk %d len %d requested, addr 0x%llx\n",
- +- i,
- +- ar->wmi.mem_chunks[i].len,
- +- (unsigned long long)ar->wmi.mem_chunks[i].paddr);
- +- }
- +-out:
- +- memcpy(&cmd->resource_config, &config, sizeof(config));
- ++ config.scan_max_pending_reqs =
- ++ __cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS);
- ++
- ++ config.bmiss_offload_max_vdev =
- ++ __cpu_to_le32(TARGET_10X_BMISS_OFFLOAD_MAX_VDEV);
- ++
- ++ config.roam_offload_max_vdev =
- ++ __cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_VDEV);
- ++
- ++ config.roam_offload_max_ap_profiles =
- ++ __cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES);
- ++
- ++ config.num_mcast_groups = __cpu_to_le32(TARGET_10X_NUM_MCAST_GROUPS);
- ++ config.num_mcast_table_elems =
- ++ __cpu_to_le32(TARGET_10X_NUM_MCAST_TABLE_ELEMS);
- ++
- ++ config.mcast2ucast_mode = __cpu_to_le32(TARGET_10X_MCAST2UCAST_MODE);
- ++ config.tx_dbg_log_size = __cpu_to_le32(TARGET_10X_TX_DBG_LOG_SIZE);
- ++ config.num_wds_entries = __cpu_to_le32(TARGET_10X_NUM_WDS_ENTRIES);
- ++ config.dma_burst_size = __cpu_to_le32(TARGET_10_2_DMA_BURST_SIZE);
- ++ config.mac_aggr_delim = __cpu_to_le32(TARGET_10X_MAC_AGGR_DELIM);
- ++
- ++ val = TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK;
- ++ config.rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(val);
- ++
- ++ config.vow_config = __cpu_to_le32(TARGET_10X_VOW_CONFIG);
- ++
- ++ config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC);
- ++ config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi init 10x\n");
- +- return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
- ++ len = sizeof(*cmd) +
- ++ (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
- ++
- ++ buf = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!buf)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ cmd = (struct wmi_init_cmd_10_2 *)buf->data;
- ++
- ++ features = WMI_10_2_RX_BATCH_MODE;
- ++ cmd->resource_config.feature_mask = __cpu_to_le32(features);
- ++
- ++ memcpy(&cmd->resource_config.common, &config, sizeof(config));
- ++ ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n");
- ++ return buf;
- + }
- +
- +-int ath10k_wmi_cmd_init(struct ath10k *ar)
- ++int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg)
- + {
- +- int ret;
- ++ if (arg->ie_len && !arg->ie)
- ++ return -EINVAL;
- ++ if (arg->n_channels && !arg->channels)
- ++ return -EINVAL;
- ++ if (arg->n_ssids && !arg->ssids)
- ++ return -EINVAL;
- ++ if (arg->n_bssids && !arg->bssids)
- ++ return -EINVAL;
- +
- +- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- +- ret = ath10k_wmi_10x_cmd_init(ar);
- +- else
- +- ret = ath10k_wmi_main_cmd_init(ar);
- ++ if (arg->ie_len > WLAN_SCAN_PARAMS_MAX_IE_LEN)
- ++ return -EINVAL;
- ++ if (arg->n_channels > ARRAY_SIZE(arg->channels))
- ++ return -EINVAL;
- ++ if (arg->n_ssids > WLAN_SCAN_PARAMS_MAX_SSID)
- ++ return -EINVAL;
- ++ if (arg->n_bssids > WLAN_SCAN_PARAMS_MAX_BSSID)
- ++ return -EINVAL;
- +
- +- return ret;
- ++ return 0;
- + }
- +
- +-static int ath10k_wmi_start_scan_calc_len(struct ath10k *ar,
- +- const struct wmi_start_scan_arg *arg)
- ++static size_t
- ++ath10k_wmi_start_scan_tlvs_len(const struct wmi_start_scan_arg *arg)
- + {
- +- int len;
- +-
- +- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- +- len = sizeof(struct wmi_start_scan_cmd_10x);
- +- else
- +- len = sizeof(struct wmi_start_scan_cmd);
- ++ int len = 0;
- +
- + if (arg->ie_len) {
- +- if (!arg->ie)
- +- return -EINVAL;
- +- if (arg->ie_len > WLAN_SCAN_PARAMS_MAX_IE_LEN)
- +- return -EINVAL;
- +-
- + len += sizeof(struct wmi_ie_data);
- + len += roundup(arg->ie_len, 4);
- + }
- +
- + if (arg->n_channels) {
- +- if (!arg->channels)
- +- return -EINVAL;
- +- if (arg->n_channels > ARRAY_SIZE(arg->channels))
- +- return -EINVAL;
- +-
- + len += sizeof(struct wmi_chan_list);
- + len += sizeof(__le32) * arg->n_channels;
- + }
- +
- + if (arg->n_ssids) {
- +- if (!arg->ssids)
- +- return -EINVAL;
- +- if (arg->n_ssids > WLAN_SCAN_PARAMS_MAX_SSID)
- +- return -EINVAL;
- +-
- + len += sizeof(struct wmi_ssid_list);
- + len += sizeof(struct wmi_ssid) * arg->n_ssids;
- + }
- +
- + if (arg->n_bssids) {
- +- if (!arg->bssids)
- +- return -EINVAL;
- +- if (arg->n_bssids > WLAN_SCAN_PARAMS_MAX_BSSID)
- +- return -EINVAL;
- +-
- + len += sizeof(struct wmi_bssid_list);
- + len += sizeof(struct wmi_mac_addr) * arg->n_bssids;
- + }
- +@@ -2793,28 +4049,11 @@ static int ath10k_wmi_start_scan_calc_le
- + return len;
- + }
- +
- +-int ath10k_wmi_start_scan(struct ath10k *ar,
- +- const struct wmi_start_scan_arg *arg)
- ++void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn,
- ++ const struct wmi_start_scan_arg *arg)
- + {
- +- struct wmi_start_scan_cmd *cmd;
- +- struct sk_buff *skb;
- +- struct wmi_ie_data *ie;
- +- struct wmi_chan_list *channels;
- +- struct wmi_ssid_list *ssids;
- +- struct wmi_bssid_list *bssids;
- + u32 scan_id;
- + u32 scan_req_id;
- +- int off;
- +- int len = 0;
- +- int i;
- +-
- +- len = ath10k_wmi_start_scan_calc_len(ar, arg);
- +- if (len < 0)
- +- return len; /* len contains error code here */
- +-
- +- skb = ath10k_wmi_alloc_skb(len);
- +- if (!skb)
- +- return -ENOMEM;
- +
- + scan_id = WMI_HOST_SCAN_REQ_ID_PREFIX;
- + scan_id |= arg->scan_id;
- +@@ -2822,48 +4061,49 @@ int ath10k_wmi_start_scan(struct ath10k
- + scan_req_id = WMI_HOST_SCAN_REQUESTOR_ID_PREFIX;
- + scan_req_id |= arg->scan_req_id;
- +
- +- cmd = (struct wmi_start_scan_cmd *)skb->data;
- +- cmd->scan_id = __cpu_to_le32(scan_id);
- +- cmd->scan_req_id = __cpu_to_le32(scan_req_id);
- +- cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
- +- cmd->scan_priority = __cpu_to_le32(arg->scan_priority);
- +- cmd->notify_scan_events = __cpu_to_le32(arg->notify_scan_events);
- +- cmd->dwell_time_active = __cpu_to_le32(arg->dwell_time_active);
- +- cmd->dwell_time_passive = __cpu_to_le32(arg->dwell_time_passive);
- +- cmd->min_rest_time = __cpu_to_le32(arg->min_rest_time);
- +- cmd->max_rest_time = __cpu_to_le32(arg->max_rest_time);
- +- cmd->repeat_probe_time = __cpu_to_le32(arg->repeat_probe_time);
- +- cmd->probe_spacing_time = __cpu_to_le32(arg->probe_spacing_time);
- +- cmd->idle_time = __cpu_to_le32(arg->idle_time);
- +- cmd->max_scan_time = __cpu_to_le32(arg->max_scan_time);
- +- cmd->probe_delay = __cpu_to_le32(arg->probe_delay);
- +- cmd->scan_ctrl_flags = __cpu_to_le32(arg->scan_ctrl_flags);
- +-
- +- /* TLV list starts after fields included in the struct */
- +- /* There's just one filed that differes the two start_scan
- +- * structures - burst_duration, which we are not using btw,
- +- no point to make the split here, just shift the buffer to fit with
- +- given FW */
- +- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- +- off = sizeof(struct wmi_start_scan_cmd_10x);
- +- else
- +- off = sizeof(struct wmi_start_scan_cmd);
- ++ cmn->scan_id = __cpu_to_le32(scan_id);
- ++ cmn->scan_req_id = __cpu_to_le32(scan_req_id);
- ++ cmn->vdev_id = __cpu_to_le32(arg->vdev_id);
- ++ cmn->scan_priority = __cpu_to_le32(arg->scan_priority);
- ++ cmn->notify_scan_events = __cpu_to_le32(arg->notify_scan_events);
- ++ cmn->dwell_time_active = __cpu_to_le32(arg->dwell_time_active);
- ++ cmn->dwell_time_passive = __cpu_to_le32(arg->dwell_time_passive);
- ++ cmn->min_rest_time = __cpu_to_le32(arg->min_rest_time);
- ++ cmn->max_rest_time = __cpu_to_le32(arg->max_rest_time);
- ++ cmn->repeat_probe_time = __cpu_to_le32(arg->repeat_probe_time);
- ++ cmn->probe_spacing_time = __cpu_to_le32(arg->probe_spacing_time);
- ++ cmn->idle_time = __cpu_to_le32(arg->idle_time);
- ++ cmn->max_scan_time = __cpu_to_le32(arg->max_scan_time);
- ++ cmn->probe_delay = __cpu_to_le32(arg->probe_delay);
- ++ cmn->scan_ctrl_flags = __cpu_to_le32(arg->scan_ctrl_flags);
- ++}
- ++
- ++static void
- ++ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs,
- ++ const struct wmi_start_scan_arg *arg)
- ++{
- ++ struct wmi_ie_data *ie;
- ++ struct wmi_chan_list *channels;
- ++ struct wmi_ssid_list *ssids;
- ++ struct wmi_bssid_list *bssids;
- ++ void *ptr = tlvs->tlvs;
- ++ int i;
- +
- + if (arg->n_channels) {
- +- channels = (void *)skb->data + off;
- ++ channels = ptr;
- + channels->tag = __cpu_to_le32(WMI_CHAN_LIST_TAG);
- + channels->num_chan = __cpu_to_le32(arg->n_channels);
- +
- + for (i = 0; i < arg->n_channels; i++)
- +- channels->channel_list[i] =
- +- __cpu_to_le32(arg->channels[i]);
- ++ channels->channel_list[i].freq =
- ++ __cpu_to_le16(arg->channels[i]);
- +
- +- off += sizeof(*channels);
- +- off += sizeof(__le32) * arg->n_channels;
- ++ ptr += sizeof(*channels);
- ++ ptr += sizeof(__le32) * arg->n_channels;
- + }
- +
- + if (arg->n_ssids) {
- +- ssids = (void *)skb->data + off;
- ++ ssids = ptr;
- + ssids->tag = __cpu_to_le32(WMI_SSID_LIST_TAG);
- + ssids->num_ssids = __cpu_to_le32(arg->n_ssids);
- +
- +@@ -2875,12 +4115,12 @@ int ath10k_wmi_start_scan(struct ath10k
- + arg->ssids[i].len);
- + }
- +
- +- off += sizeof(*ssids);
- +- off += sizeof(struct wmi_ssid) * arg->n_ssids;
- ++ ptr += sizeof(*ssids);
- ++ ptr += sizeof(struct wmi_ssid) * arg->n_ssids;
- + }
- +
- + if (arg->n_bssids) {
- +- bssids = (void *)skb->data + off;
- ++ bssids = ptr;
- + bssids->tag = __cpu_to_le32(WMI_BSSID_LIST_TAG);
- + bssids->num_bssid = __cpu_to_le32(arg->n_bssids);
- +
- +@@ -2889,27 +4129,75 @@ int ath10k_wmi_start_scan(struct ath10k
- + arg->bssids[i].bssid,
- + ETH_ALEN);
- +
- +- off += sizeof(*bssids);
- +- off += sizeof(struct wmi_mac_addr) * arg->n_bssids;
- ++ ptr += sizeof(*bssids);
- ++ ptr += sizeof(struct wmi_mac_addr) * arg->n_bssids;
- + }
- +
- + if (arg->ie_len) {
- +- ie = (void *)skb->data + off;
- ++ ie = ptr;
- + ie->tag = __cpu_to_le32(WMI_IE_TAG);
- + ie->ie_len = __cpu_to_le32(arg->ie_len);
- + memcpy(ie->ie_data, arg->ie, arg->ie_len);
- +
- +- off += sizeof(*ie);
- +- off += roundup(arg->ie_len, 4);
- ++ ptr += sizeof(*ie);
- ++ ptr += roundup(arg->ie_len, 4);
- + }
- ++}
- +
- +- if (off != skb->len) {
- +- dev_kfree_skb(skb);
- +- return -EINVAL;
- +- }
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_start_scan(struct ath10k *ar,
- ++ const struct wmi_start_scan_arg *arg)
- ++{
- ++ struct wmi_start_scan_cmd *cmd;
- ++ struct sk_buff *skb;
- ++ size_t len;
- ++ int ret;
- ++
- ++ ret = ath10k_wmi_start_scan_verify(arg);
- ++ if (ret)
- ++ return ERR_PTR(ret);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi start scan\n");
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid);
- ++ len = sizeof(*cmd) + ath10k_wmi_start_scan_tlvs_len(arg);
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ cmd = (struct wmi_start_scan_cmd *)skb->data;
- ++
- ++ ath10k_wmi_put_start_scan_common(&cmd->common, arg);
- ++ ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
- ++
- ++ cmd->burst_duration_ms = __cpu_to_le32(0);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_10x_op_gen_start_scan(struct ath10k *ar,
- ++ const struct wmi_start_scan_arg *arg)
- ++{
- ++ struct wmi_10x_start_scan_cmd *cmd;
- ++ struct sk_buff *skb;
- ++ size_t len;
- ++ int ret;
- ++
- ++ ret = ath10k_wmi_start_scan_verify(arg);
- ++ if (ret)
- ++ return ERR_PTR(ret);
- ++
- ++ len = sizeof(*cmd) + ath10k_wmi_start_scan_tlvs_len(arg);
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ cmd = (struct wmi_10x_start_scan_cmd *)skb->data;
- ++
- ++ ath10k_wmi_put_start_scan_common(&cmd->common, arg);
- ++ ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi 10x start scan\n");
- ++ return skb;
- + }
- +
- + void ath10k_wmi_start_scan_init(struct ath10k *ar,
- +@@ -2938,7 +4226,9 @@ void ath10k_wmi_start_scan_init(struct a
- + arg->bssids[0].bssid = "\xFF\xFF\xFF\xFF\xFF\xFF";
- + }
- +
- +-int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_stop_scan(struct ath10k *ar,
- ++ const struct wmi_stop_scan_arg *arg)
- + {
- + struct wmi_stop_scan_cmd *cmd;
- + struct sk_buff *skb;
- +@@ -2946,13 +4236,13 @@ int ath10k_wmi_stop_scan(struct ath10k *
- + u32 req_id;
- +
- + if (arg->req_id > 0xFFF)
- +- return -EINVAL;
- ++ return ERR_PTR(-EINVAL);
- + if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF)
- +- return -EINVAL;
- ++ return ERR_PTR(-EINVAL);
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + scan_id = arg->u.scan_id;
- + scan_id |= WMI_HOST_SCAN_REQ_ID_PREFIX;
- +@@ -2966,92 +4256,85 @@ int ath10k_wmi_stop_scan(struct ath10k *
- + cmd->scan_id = __cpu_to_le32(scan_id);
- + cmd->scan_req_id = __cpu_to_le32(req_id);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi stop scan reqid %d req_type %d vdev/scan_id %d\n",
- + arg->req_id, arg->req_type, arg->u.scan_id);
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
- +- enum wmi_vdev_type type,
- +- enum wmi_vdev_subtype subtype,
- +- const u8 macaddr[ETH_ALEN])
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_vdev_create(struct ath10k *ar, u32 vdev_id,
- ++ enum wmi_vdev_type type,
- ++ enum wmi_vdev_subtype subtype,
- ++ const u8 macaddr[ETH_ALEN])
- + {
- + struct wmi_vdev_create_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_vdev_create_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(vdev_id);
- + cmd->vdev_type = __cpu_to_le32(type);
- + cmd->vdev_subtype = __cpu_to_le32(subtype);
- +- memcpy(cmd->vdev_macaddr.addr, macaddr, ETH_ALEN);
- ++ ether_addr_copy(cmd->vdev_macaddr.addr, macaddr);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "WMI vdev create: id %d type %d subtype %d macaddr %pM\n",
- + vdev_id, type, subtype, macaddr);
- +-
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_create_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_vdev_delete(struct ath10k *ar, u32 vdev_id)
- + {
- + struct wmi_vdev_delete_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_vdev_delete_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(vdev_id);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "WMI vdev delete id %d\n", vdev_id);
- +-
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid);
- ++ return skb;
- + }
- +
- +-static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,
- +- const struct wmi_vdev_start_request_arg *arg,
- +- u32 cmd_id)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_vdev_start(struct ath10k *ar,
- ++ const struct wmi_vdev_start_request_arg *arg,
- ++ bool restart)
- + {
- + struct wmi_vdev_start_request_cmd *cmd;
- + struct sk_buff *skb;
- + const char *cmdname;
- + u32 flags = 0;
- +- u32 ch_flags = 0;
- +
- +- if (cmd_id != ar->wmi.cmd->vdev_start_request_cmdid &&
- +- cmd_id != ar->wmi.cmd->vdev_restart_request_cmdid)
- +- return -EINVAL;
- + if (WARN_ON(arg->ssid && arg->ssid_len == 0))
- +- return -EINVAL;
- ++ return ERR_PTR(-EINVAL);
- + if (WARN_ON(arg->hidden_ssid && !arg->ssid))
- +- return -EINVAL;
- ++ return ERR_PTR(-EINVAL);
- + if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))
- +- return -EINVAL;
- ++ return ERR_PTR(-EINVAL);
- +
- +- if (cmd_id == ar->wmi.cmd->vdev_start_request_cmdid)
- +- cmdname = "start";
- +- else if (cmd_id == ar->wmi.cmd->vdev_restart_request_cmdid)
- ++ if (restart)
- + cmdname = "restart";
- + else
- +- return -EINVAL; /* should not happen, we already check cmd_id */
- ++ cmdname = "start";
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + if (arg->hidden_ssid)
- + flags |= WMI_VDEV_START_HIDDEN_SSID;
- + if (arg->pmf_enabled)
- + flags |= WMI_VDEV_START_PMF_ENABLED;
- +- if (arg->channel.chan_radar)
- +- ch_flags |= WMI_CHAN_FLAG_DFS;
- +
- + cmd = (struct wmi_vdev_start_request_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
- +@@ -3067,143 +4350,118 @@ static int ath10k_wmi_vdev_start_restart
- + memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len);
- + }
- +
- +- cmd->chan.mhz = __cpu_to_le32(arg->channel.freq);
- ++ ath10k_wmi_put_wmi_channel(&cmd->chan, &arg->channel);
- +
- +- cmd->chan.band_center_freq1 =
- +- __cpu_to_le32(arg->channel.band_center_freq1);
- +-
- +- cmd->chan.mode = arg->channel.mode;
- +- cmd->chan.flags |= __cpu_to_le32(ch_flags);
- +- cmd->chan.min_power = arg->channel.min_power;
- +- cmd->chan.max_power = arg->channel.max_power;
- +- cmd->chan.reg_power = arg->channel.max_reg_power;
- +- cmd->chan.reg_classid = arg->channel.reg_class_id;
- +- cmd->chan.antenna_max = arg->channel.max_antenna_gain;
- +-
- +- ath10k_dbg(ATH10K_DBG_WMI,
- +- "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, "
- +- "ch_flags: 0x%0X, max_power: %d\n", cmdname, arg->vdev_id,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, ch_flags: 0x%0X, max_power: %d\n",
- ++ cmdname, arg->vdev_id,
- + flags, arg->channel.freq, arg->channel.mode,
- + cmd->chan.flags, arg->channel.max_power);
- +
- +- return ath10k_wmi_cmd_send(ar, skb, cmd_id);
- +-}
- +-
- +-int ath10k_wmi_vdev_start(struct ath10k *ar,
- +- const struct wmi_vdev_start_request_arg *arg)
- +-{
- +- u32 cmd_id = ar->wmi.cmd->vdev_start_request_cmdid;
- +-
- +- return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id);
- +-}
- +-
- +-int ath10k_wmi_vdev_restart(struct ath10k *ar,
- +- const struct wmi_vdev_start_request_arg *arg)
- +-{
- +- u32 cmd_id = ar->wmi.cmd->vdev_restart_request_cmdid;
- +-
- +- return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_vdev_stop(struct ath10k *ar, u32 vdev_id)
- + {
- + struct wmi_vdev_stop_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_vdev_stop_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(vdev_id);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id);
- +-
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid);
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid,
- ++ const u8 *bssid)
- + {
- + struct wmi_vdev_up_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_vdev_up_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(vdev_id);
- + cmd->vdev_assoc_id = __cpu_to_le32(aid);
- +- memcpy(&cmd->vdev_bssid.addr, bssid, ETH_ALEN);
- ++ ether_addr_copy(cmd->vdev_bssid.addr, bssid);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi mgmt vdev up id 0x%x assoc id %d bssid %pM\n",
- + vdev_id, aid, bssid);
- +-
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_up_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_vdev_down(struct ath10k *ar, u32 vdev_id)
- + {
- + struct wmi_vdev_down_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_vdev_down_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(vdev_id);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi mgmt vdev down id 0x%x\n", vdev_id);
- +-
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
- +- u32 param_id, u32 param_value)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_vdev_set_param(struct ath10k *ar, u32 vdev_id,
- ++ u32 param_id, u32 param_value)
- + {
- + struct wmi_vdev_set_param_cmd *cmd;
- + struct sk_buff *skb;
- +
- + if (param_id == WMI_VDEV_PARAM_UNSUPPORTED) {
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "vdev param %d not supported by firmware\n",
- + param_id);
- +- return -EOPNOTSUPP;
- ++ return ERR_PTR(-EOPNOTSUPP);
- + }
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_vdev_set_param_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(vdev_id);
- + cmd->param_id = __cpu_to_le32(param_id);
- + cmd->param_value = __cpu_to_le32(param_value);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi vdev id 0x%x set param %d value %d\n",
- + vdev_id, param_id, param_value);
- +-
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_set_param_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_vdev_install_key(struct ath10k *ar,
- +- const struct wmi_vdev_install_key_arg *arg)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_vdev_install_key(struct ath10k *ar,
- ++ const struct wmi_vdev_install_key_arg *arg)
- + {
- + struct wmi_vdev_install_key_cmd *cmd;
- + struct sk_buff *skb;
- +
- + if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL)
- +- return -EINVAL;
- ++ return ERR_PTR(-EINVAL);
- + if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL)
- +- return -EINVAL;
- ++ return ERR_PTR(-EINVAL);
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->key_len);
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + arg->key_len);
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_vdev_install_key_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
- +@@ -3215,176 +4473,232 @@ int ath10k_wmi_vdev_install_key(struct a
- + cmd->key_rxmic_len = __cpu_to_le32(arg->key_rxmic_len);
- +
- + if (arg->macaddr)
- +- memcpy(cmd->peer_macaddr.addr, arg->macaddr, ETH_ALEN);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, arg->macaddr);
- + if (arg->key_data)
- + memcpy(cmd->key_data, arg->key_data, arg->key_len);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi vdev install key idx %d cipher %d len %d\n",
- + arg->key_idx, arg->key_cipher, arg->key_len);
- +- return ath10k_wmi_cmd_send(ar, skb,
- +- ar->wmi.cmd->vdev_install_key_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
- +- const u8 peer_addr[ETH_ALEN])
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_vdev_spectral_conf(struct ath10k *ar,
- ++ const struct wmi_vdev_spectral_conf_arg *arg)
- ++{
- ++ struct wmi_vdev_spectral_conf_cmd *cmd;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ cmd = (struct wmi_vdev_spectral_conf_cmd *)skb->data;
- ++ cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
- ++ cmd->scan_count = __cpu_to_le32(arg->scan_count);
- ++ cmd->scan_period = __cpu_to_le32(arg->scan_period);
- ++ cmd->scan_priority = __cpu_to_le32(arg->scan_priority);
- ++ cmd->scan_fft_size = __cpu_to_le32(arg->scan_fft_size);
- ++ cmd->scan_gc_ena = __cpu_to_le32(arg->scan_gc_ena);
- ++ cmd->scan_restart_ena = __cpu_to_le32(arg->scan_restart_ena);
- ++ cmd->scan_noise_floor_ref = __cpu_to_le32(arg->scan_noise_floor_ref);
- ++ cmd->scan_init_delay = __cpu_to_le32(arg->scan_init_delay);
- ++ cmd->scan_nb_tone_thr = __cpu_to_le32(arg->scan_nb_tone_thr);
- ++ cmd->scan_str_bin_thr = __cpu_to_le32(arg->scan_str_bin_thr);
- ++ cmd->scan_wb_rpt_mode = __cpu_to_le32(arg->scan_wb_rpt_mode);
- ++ cmd->scan_rssi_rpt_mode = __cpu_to_le32(arg->scan_rssi_rpt_mode);
- ++ cmd->scan_rssi_thr = __cpu_to_le32(arg->scan_rssi_thr);
- ++ cmd->scan_pwr_format = __cpu_to_le32(arg->scan_pwr_format);
- ++ cmd->scan_rpt_mode = __cpu_to_le32(arg->scan_rpt_mode);
- ++ cmd->scan_bin_scale = __cpu_to_le32(arg->scan_bin_scale);
- ++ cmd->scan_dbm_adj = __cpu_to_le32(arg->scan_dbm_adj);
- ++ cmd->scan_chn_mask = __cpu_to_le32(arg->scan_chn_mask);
- ++
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id,
- ++ u32 trigger, u32 enable)
- ++{
- ++ struct wmi_vdev_spectral_enable_cmd *cmd;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ cmd = (struct wmi_vdev_spectral_enable_cmd *)skb->data;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->trigger_cmd = __cpu_to_le32(trigger);
- ++ cmd->enable_cmd = __cpu_to_le32(enable);
- ++
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN])
- + {
- + struct wmi_peer_create_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_peer_create_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(vdev_id);
- +- memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi peer create vdev_id %d peer_addr %pM\n",
- + vdev_id, peer_addr);
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
- +- const u8 peer_addr[ETH_ALEN])
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_peer_delete(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN])
- + {
- + struct wmi_peer_delete_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_peer_delete_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(vdev_id);
- +- memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi peer delete vdev_id %d peer_addr %pM\n",
- + vdev_id, peer_addr);
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
- +- const u8 peer_addr[ETH_ALEN], u32 tid_bitmap)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_peer_flush(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN], u32 tid_bitmap)
- + {
- + struct wmi_peer_flush_tids_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_peer_flush_tids_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(vdev_id);
- + cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap);
- +- memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi peer flush vdev_id %d peer_addr %pM tids %08x\n",
- + vdev_id, peer_addr, tid_bitmap);
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
- +- const u8 *peer_addr, enum wmi_peer_param param_id,
- +- u32 param_value)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id,
- ++ const u8 *peer_addr,
- ++ enum wmi_peer_param param_id,
- ++ u32 param_value)
- + {
- + struct wmi_peer_set_param_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_peer_set_param_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(vdev_id);
- + cmd->param_id = __cpu_to_le32(param_id);
- + cmd->param_value = __cpu_to_le32(param_value);
- +- memcpy(&cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi vdev %d peer 0x%pM set param %d value %d\n",
- + vdev_id, peer_addr, param_id, param_value);
- +-
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_set_param_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
- +- enum wmi_sta_ps_mode psmode)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id,
- ++ enum wmi_sta_ps_mode psmode)
- + {
- + struct wmi_sta_powersave_mode_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_sta_powersave_mode_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(vdev_id);
- + cmd->sta_ps_mode = __cpu_to_le32(psmode);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi set powersave id 0x%x mode %d\n",
- + vdev_id, psmode);
- +-
- +- return ath10k_wmi_cmd_send(ar, skb,
- +- ar->wmi.cmd->sta_powersave_mode_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
- +- enum wmi_sta_powersave_param param_id,
- +- u32 value)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_set_sta_ps(struct ath10k *ar, u32 vdev_id,
- ++ enum wmi_sta_powersave_param param_id,
- ++ u32 value)
- + {
- + struct wmi_sta_powersave_param_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_sta_powersave_param_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(vdev_id);
- + cmd->param_id = __cpu_to_le32(param_id);
- + cmd->param_value = __cpu_to_le32(value);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi sta ps param vdev_id 0x%x param %d value %d\n",
- + vdev_id, param_id, value);
- +- return ath10k_wmi_cmd_send(ar, skb,
- +- ar->wmi.cmd->sta_powersave_param_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
- +- enum wmi_ap_ps_peer_param param_id, u32 value)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac,
- ++ enum wmi_ap_ps_peer_param param_id, u32 value)
- + {
- + struct wmi_ap_ps_peer_cmd *cmd;
- + struct sk_buff *skb;
- +
- + if (!mac)
- +- return -EINVAL;
- ++ return ERR_PTR(-EINVAL);
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_ap_ps_peer_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(vdev_id);
- + cmd->param_id = __cpu_to_le32(param_id);
- + cmd->param_value = __cpu_to_le32(value);
- +- memcpy(&cmd->peer_macaddr, mac, ETH_ALEN);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, mac);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi ap ps param vdev_id 0x%X param %d value %d mac_addr %pM\n",
- + vdev_id, param_id, value, mac);
- +-
- +- return ath10k_wmi_cmd_send(ar, skb,
- +- ar->wmi.cmd->ap_ps_peer_param_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_scan_chan_list(struct ath10k *ar,
- +- const struct wmi_scan_chan_list_arg *arg)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_scan_chan_list(struct ath10k *ar,
- ++ const struct wmi_scan_chan_list_arg *arg)
- + {
- + struct wmi_scan_chan_list_cmd *cmd;
- + struct sk_buff *skb;
- +@@ -3395,66 +4709,29 @@ int ath10k_wmi_scan_chan_list(struct ath
- +
- + len = sizeof(*cmd) + arg->n_channels * sizeof(struct wmi_channel);
- +
- +- skb = ath10k_wmi_alloc_skb(len);
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- + if (!skb)
- +- return -EINVAL;
- ++ return ERR_PTR(-EINVAL);
- +
- + cmd = (struct wmi_scan_chan_list_cmd *)skb->data;
- + cmd->num_scan_chans = __cpu_to_le32(arg->n_channels);
- +
- + for (i = 0; i < arg->n_channels; i++) {
- +- u32 flags = 0;
- +-
- + ch = &arg->channels[i];
- + ci = &cmd->chan_info[i];
- +
- +- if (ch->passive)
- +- flags |= WMI_CHAN_FLAG_PASSIVE;
- +- if (ch->allow_ibss)
- +- flags |= WMI_CHAN_FLAG_ADHOC_ALLOWED;
- +- if (ch->allow_ht)
- +- flags |= WMI_CHAN_FLAG_ALLOW_HT;
- +- if (ch->allow_vht)
- +- flags |= WMI_CHAN_FLAG_ALLOW_VHT;
- +- if (ch->ht40plus)
- +- flags |= WMI_CHAN_FLAG_HT40_PLUS;
- +- if (ch->chan_radar)
- +- flags |= WMI_CHAN_FLAG_DFS;
- +-
- +- ci->mhz = __cpu_to_le32(ch->freq);
- +- ci->band_center_freq1 = __cpu_to_le32(ch->freq);
- +- ci->band_center_freq2 = 0;
- +- ci->min_power = ch->min_power;
- +- ci->max_power = ch->max_power;
- +- ci->reg_power = ch->max_reg_power;
- +- ci->antenna_max = ch->max_antenna_gain;
- +-
- +- /* mode & flags share storage */
- +- ci->mode = ch->mode;
- +- ci->flags |= __cpu_to_le32(flags);
- ++ ath10k_wmi_put_wmi_channel(ci, ch);
- + }
- +
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_peer_assoc(struct ath10k *ar,
- +- const struct wmi_peer_assoc_complete_arg *arg)
- ++static void
- ++ath10k_wmi_peer_assoc_fill(struct ath10k *ar, void *buf,
- ++ const struct wmi_peer_assoc_complete_arg *arg)
- + {
- +- struct wmi_peer_assoc_complete_cmd *cmd;
- +- struct sk_buff *skb;
- ++ struct wmi_common_peer_assoc_complete_cmd *cmd = buf;
- +
- +- if (arg->peer_mpdu_density > 16)
- +- return -EINVAL;
- +- if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
- +- return -EINVAL;
- +- if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
- +- return -EINVAL;
- +-
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- +- if (!skb)
- +- return -ENOMEM;
- +-
- +- cmd = (struct wmi_peer_assoc_complete_cmd *)skb->data;
- + cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
- + cmd->peer_new_assoc = __cpu_to_le32(arg->peer_reassoc ? 0 : 1);
- + cmd->peer_associd = __cpu_to_le32(arg->peer_aid);
- +@@ -3469,7 +4746,7 @@ int ath10k_wmi_peer_assoc(struct ath10k
- + cmd->peer_vht_caps = __cpu_to_le32(arg->peer_vht_caps);
- + cmd->peer_phymode = __cpu_to_le32(arg->peer_phymode);
- +
- +- memcpy(cmd->peer_macaddr.addr, arg->addr, ETH_ALEN);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, arg->addr);
- +
- + cmd->peer_legacy_rates.num_rates =
- + __cpu_to_le32(arg->peer_legacy_rates.num_rates);
- +@@ -3489,57 +4766,183 @@ int ath10k_wmi_peer_assoc(struct ath10k
- + __cpu_to_le32(arg->peer_vht_rates.tx_max_rate);
- + cmd->peer_vht_rates.tx_mcs_set =
- + __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set);
- ++}
- ++
- ++static void
- ++ath10k_wmi_peer_assoc_fill_main(struct ath10k *ar, void *buf,
- ++ const struct wmi_peer_assoc_complete_arg *arg)
- ++{
- ++ struct wmi_main_peer_assoc_complete_cmd *cmd = buf;
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_wmi_peer_assoc_fill(ar, buf, arg);
- ++ memset(cmd->peer_ht_info, 0, sizeof(cmd->peer_ht_info));
- ++}
- ++
- ++static void
- ++ath10k_wmi_peer_assoc_fill_10_1(struct ath10k *ar, void *buf,
- ++ const struct wmi_peer_assoc_complete_arg *arg)
- ++{
- ++ ath10k_wmi_peer_assoc_fill(ar, buf, arg);
- ++}
- ++
- ++static void
- ++ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf,
- ++ const struct wmi_peer_assoc_complete_arg *arg)
- ++{
- ++ struct wmi_10_2_peer_assoc_complete_cmd *cmd = buf;
- ++ int max_mcs, max_nss;
- ++ u32 info0;
- ++
- ++ /* TODO: Is using max values okay with firmware? */
- ++ max_mcs = 0xf;
- ++ max_nss = 0xf;
- ++
- ++ info0 = SM(max_mcs, WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX) |
- ++ SM(max_nss, WMI_PEER_ASSOC_INFO0_MAX_NSS);
- ++
- ++ ath10k_wmi_peer_assoc_fill(ar, buf, arg);
- ++ cmd->info0 = __cpu_to_le32(info0);
- ++}
- ++
- ++static int
- ++ath10k_wmi_peer_assoc_check_arg(const struct wmi_peer_assoc_complete_arg *arg)
- ++{
- ++ if (arg->peer_mpdu_density > 16)
- ++ return -EINVAL;
- ++ if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
- ++ return -EINVAL;
- ++ if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
- ++ return -EINVAL;
- ++
- ++ return 0;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_peer_assoc(struct ath10k *ar,
- ++ const struct wmi_peer_assoc_complete_arg *arg)
- ++{
- ++ size_t len = sizeof(struct wmi_main_peer_assoc_complete_cmd);
- ++ struct sk_buff *skb;
- ++ int ret;
- ++
- ++ ret = ath10k_wmi_peer_assoc_check_arg(arg);
- ++ if (ret)
- ++ return ERR_PTR(ret);
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi peer assoc vdev %d addr %pM (%s)\n",
- ++ arg->vdev_id, arg->addr,
- ++ arg->peer_reassoc ? "reassociate" : "new");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_10_1_op_gen_peer_assoc(struct ath10k *ar,
- ++ const struct wmi_peer_assoc_complete_arg *arg)
- ++{
- ++ size_t len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd);
- ++ struct sk_buff *skb;
- ++ int ret;
- ++
- ++ ret = ath10k_wmi_peer_assoc_check_arg(arg);
- ++ if (ret)
- ++ return ERR_PTR(ret);
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi peer assoc vdev %d addr %pM (%s)\n",
- ++ arg->vdev_id, arg->addr,
- ++ arg->peer_reassoc ? "reassociate" : "new");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_10_2_op_gen_peer_assoc(struct ath10k *ar,
- ++ const struct wmi_peer_assoc_complete_arg *arg)
- ++{
- ++ size_t len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd);
- ++ struct sk_buff *skb;
- ++ int ret;
- ++
- ++ ret = ath10k_wmi_peer_assoc_check_arg(arg);
- ++ if (ret)
- ++ return ERR_PTR(ret);
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi peer assoc vdev %d addr %pM (%s)\n",
- + arg->vdev_id, arg->addr,
- + arg->peer_reassoc ? "reassociate" : "new");
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_10_2_op_gen_pdev_get_temperature(struct ath10k *ar)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, 0);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev get temperature\n");
- ++ return skb;
- + }
- +
- + /* This function assumes the beacon is already DMA mapped */
- +-int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_beacon_dma(struct ath10k *ar, u32 vdev_id, const void *bcn,
- ++ size_t bcn_len, u32 bcn_paddr, bool dtim_zero,
- ++ bool deliver_cab)
- + {
- + struct wmi_bcn_tx_ref_cmd *cmd;
- + struct sk_buff *skb;
- +- struct sk_buff *beacon = arvif->beacon;
- +- struct ath10k *ar = arvif->ar;
- + struct ieee80211_hdr *hdr;
- +- int ret;
- + u16 fc;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- +- hdr = (struct ieee80211_hdr *)beacon->data;
- ++ hdr = (struct ieee80211_hdr *)bcn;
- + fc = le16_to_cpu(hdr->frame_control);
- +
- + cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data;
- +- cmd->vdev_id = __cpu_to_le32(arvif->vdev_id);
- +- cmd->data_len = __cpu_to_le32(beacon->len);
- +- cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr);
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->data_len = __cpu_to_le32(bcn_len);
- ++ cmd->data_ptr = __cpu_to_le32(bcn_paddr);
- + cmd->msdu_id = 0;
- + cmd->frame_control = __cpu_to_le32(fc);
- + cmd->flags = 0;
- ++ cmd->antenna_mask = __cpu_to_le32(WMI_BCN_TX_REF_DEF_ANTENNA);
- +
- +- if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero)
- ++ if (dtim_zero)
- + cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
- +
- +- if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab)
- ++ if (deliver_cab)
- + cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB);
- +
- +- ret = ath10k_wmi_cmd_send_nowait(ar, skb,
- +- ar->wmi.cmd->pdev_send_bcn_cmdid);
- +-
- +- if (ret)
- +- dev_kfree_skb(skb);
- +-
- +- return ret;
- ++ return skb;
- + }
- +
- +-static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params,
- +- const struct wmi_wmm_params_arg *arg)
- ++void ath10k_wmi_set_wmm_param(struct wmi_wmm_params *params,
- ++ const struct wmi_wmm_params_arg *arg)
- + {
- + params->cwmin = __cpu_to_le32(arg->cwmin);
- + params->cwmax = __cpu_to_le32(arg->cwmax);
- +@@ -3549,76 +4952,81 @@ static void ath10k_wmi_pdev_set_wmm_para
- + params->no_ack = __cpu_to_le32(arg->no_ack);
- + }
- +
- +-int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
- +- const struct wmi_pdev_set_wmm_params_arg *arg)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_pdev_set_wmm(struct ath10k *ar,
- ++ const struct wmi_wmm_params_all_arg *arg)
- + {
- + struct wmi_pdev_set_wmm_params *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_pdev_set_wmm_params *)skb->data;
- +- ath10k_wmi_pdev_set_wmm_param(&cmd->ac_be, &arg->ac_be);
- +- ath10k_wmi_pdev_set_wmm_param(&cmd->ac_bk, &arg->ac_bk);
- +- ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vi, &arg->ac_vi);
- +- ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo);
- ++ ath10k_wmi_set_wmm_param(&cmd->ac_be, &arg->ac_be);
- ++ ath10k_wmi_set_wmm_param(&cmd->ac_bk, &arg->ac_bk);
- ++ ath10k_wmi_set_wmm_param(&cmd->ac_vi, &arg->ac_vi);
- ++ ath10k_wmi_set_wmm_param(&cmd->ac_vo, &arg->ac_vo);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set wmm params\n");
- +- return ath10k_wmi_cmd_send(ar, skb,
- +- ar->wmi.cmd->pdev_set_wmm_params_cmdid);
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set wmm params\n");
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
- + {
- + struct wmi_request_stats_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_request_stats_cmd *)skb->data;
- +- cmd->stats_id = __cpu_to_le32(stats_id);
- ++ cmd->stats_id = __cpu_to_le32(stats_mask);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id);
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats 0x%08x\n",
- ++ stats_mask);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_force_fw_hang(struct ath10k *ar,
- +- enum wmi_force_fw_hang_type type, u32 delay_ms)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_force_fw_hang(struct ath10k *ar,
- ++ enum wmi_force_fw_hang_type type, u32 delay_ms)
- + {
- + struct wmi_force_fw_hang_cmd *cmd;
- + struct sk_buff *skb;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_force_fw_hang_cmd *)skb->data;
- + cmd->type = __cpu_to_le32(type);
- + cmd->delay_ms = __cpu_to_le32(delay_ms);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",
- + type, delay_ms);
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
- ++ return skb;
- + }
- +
- +-int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable,
- ++ u32 log_level)
- + {
- + struct wmi_dbglog_cfg_cmd *cmd;
- + struct sk_buff *skb;
- + u32 cfg;
- +
- +- skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- + if (!skb)
- +- return -ENOMEM;
- ++ return ERR_PTR(-ENOMEM);
- +
- + cmd = (struct wmi_dbglog_cfg_cmd *)skb->data;
- +
- + if (module_enable) {
- +- cfg = SM(ATH10K_DBGLOG_LEVEL_VERBOSE,
- ++ cfg = SM(log_level,
- + ATH10K_DBGLOG_CFG_LOG_LVL);
- + } else {
- + /* set back defaults, all modules with WARN level */
- +@@ -3632,12 +5040,474 @@ int ath10k_wmi_dbglog_cfg(struct ath10k
- + cmd->config_enable = __cpu_to_le32(cfg);
- + cmd->config_valid = __cpu_to_le32(ATH10K_DBGLOG_CFG_LOG_LVL_MASK);
- +
- +- ath10k_dbg(ATH10K_DBG_WMI,
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- + "wmi dbglog cfg modules %08x %08x config %08x %08x\n",
- + __le32_to_cpu(cmd->module_enable),
- + __le32_to_cpu(cmd->module_valid),
- + __le32_to_cpu(cmd->config_enable),
- + __le32_to_cpu(cmd->config_valid));
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_pktlog_enable(struct ath10k *ar, u32 ev_bitmap)
- ++{
- ++ struct wmi_pdev_pktlog_enable_cmd *cmd;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ev_bitmap &= ATH10K_PKTLOG_ANY;
- ++
- ++ cmd = (struct wmi_pdev_pktlog_enable_cmd *)skb->data;
- ++ cmd->ev_bitmap = __cpu_to_le32(ev_bitmap);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi enable pktlog filter 0x%08x\n",
- ++ ev_bitmap);
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_pktlog_disable(struct ath10k *ar)
- ++{
- ++ struct sk_buff *skb;
- +
- +- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid);
- ++ skb = ath10k_wmi_alloc_skb(ar, 0);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi disable pktlog\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_pdev_set_quiet_mode(struct ath10k *ar, u32 period,
- ++ u32 duration, u32 next_offset,
- ++ u32 enabled)
- ++{
- ++ struct wmi_pdev_set_quiet_cmd *cmd;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ cmd = (struct wmi_pdev_set_quiet_cmd *)skb->data;
- ++ cmd->period = __cpu_to_le32(period);
- ++ cmd->duration = __cpu_to_le32(duration);
- ++ cmd->next_start = __cpu_to_le32(next_offset);
- ++ cmd->enabled = __cpu_to_le32(enabled);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi quiet param: period %u duration %u enabled %d\n",
- ++ period, duration, enabled);
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_addba_clear_resp(struct ath10k *ar, u32 vdev_id,
- ++ const u8 *mac)
- ++{
- ++ struct wmi_addba_clear_resp_cmd *cmd;
- ++ struct sk_buff *skb;
- ++
- ++ if (!mac)
- ++ return ERR_PTR(-EINVAL);
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ cmd = (struct wmi_addba_clear_resp_cmd *)skb->data;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, mac);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi addba clear resp vdev_id 0x%X mac_addr %pM\n",
- ++ vdev_id, mac);
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_addba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac,
- ++ u32 tid, u32 buf_size)
- ++{
- ++ struct wmi_addba_send_cmd *cmd;
- ++ struct sk_buff *skb;
- ++
- ++ if (!mac)
- ++ return ERR_PTR(-EINVAL);
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ cmd = (struct wmi_addba_send_cmd *)skb->data;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, mac);
- ++ cmd->tid = __cpu_to_le32(tid);
- ++ cmd->buffersize = __cpu_to_le32(buf_size);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi addba send vdev_id 0x%X mac_addr %pM tid %u bufsize %u\n",
- ++ vdev_id, mac, tid, buf_size);
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_addba_set_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac,
- ++ u32 tid, u32 status)
- ++{
- ++ struct wmi_addba_setresponse_cmd *cmd;
- ++ struct sk_buff *skb;
- ++
- ++ if (!mac)
- ++ return ERR_PTR(-EINVAL);
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ cmd = (struct wmi_addba_setresponse_cmd *)skb->data;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, mac);
- ++ cmd->tid = __cpu_to_le32(tid);
- ++ cmd->statuscode = __cpu_to_le32(status);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi addba set resp vdev_id 0x%X mac_addr %pM tid %u status %u\n",
- ++ vdev_id, mac, tid, status);
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_op_gen_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac,
- ++ u32 tid, u32 initiator, u32 reason)
- ++{
- ++ struct wmi_delba_send_cmd *cmd;
- ++ struct sk_buff *skb;
- ++
- ++ if (!mac)
- ++ return ERR_PTR(-EINVAL);
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ cmd = (struct wmi_delba_send_cmd *)skb->data;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, mac);
- ++ cmd->tid = __cpu_to_le32(tid);
- ++ cmd->initiator = __cpu_to_le32(initiator);
- ++ cmd->reasoncode = __cpu_to_le32(reason);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi delba send vdev_id 0x%X mac_addr %pM tid %u initiator %u reason %u\n",
- ++ vdev_id, mac, tid, initiator, reason);
- ++ return skb;
- ++}
- ++
- ++static const struct wmi_ops wmi_ops = {
- ++ .rx = ath10k_wmi_op_rx,
- ++ .map_svc = wmi_main_svc_map,
- ++
- ++ .pull_scan = ath10k_wmi_op_pull_scan_ev,
- ++ .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev,
- ++ .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
- ++ .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
- ++ .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
- ++ .pull_swba = ath10k_wmi_op_pull_swba_ev,
- ++ .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
- ++ .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev,
- ++ .pull_rdy = ath10k_wmi_op_pull_rdy_ev,
- ++ .pull_fw_stats = ath10k_wmi_main_op_pull_fw_stats,
- ++
- ++ .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
- ++ .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
- ++ .gen_pdev_set_rd = ath10k_wmi_op_gen_pdev_set_rd,
- ++ .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
- ++ .gen_init = ath10k_wmi_op_gen_init,
- ++ .gen_start_scan = ath10k_wmi_op_gen_start_scan,
- ++ .gen_stop_scan = ath10k_wmi_op_gen_stop_scan,
- ++ .gen_vdev_create = ath10k_wmi_op_gen_vdev_create,
- ++ .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete,
- ++ .gen_vdev_start = ath10k_wmi_op_gen_vdev_start,
- ++ .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop,
- ++ .gen_vdev_up = ath10k_wmi_op_gen_vdev_up,
- ++ .gen_vdev_down = ath10k_wmi_op_gen_vdev_down,
- ++ .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param,
- ++ .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key,
- ++ .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf,
- ++ .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable,
- ++ /* .gen_vdev_wmm_conf not implemented */
- ++ .gen_peer_create = ath10k_wmi_op_gen_peer_create,
- ++ .gen_peer_delete = ath10k_wmi_op_gen_peer_delete,
- ++ .gen_peer_flush = ath10k_wmi_op_gen_peer_flush,
- ++ .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param,
- ++ .gen_peer_assoc = ath10k_wmi_op_gen_peer_assoc,
- ++ .gen_set_psmode = ath10k_wmi_op_gen_set_psmode,
- ++ .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps,
- ++ .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps,
- ++ .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list,
- ++ .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma,
- ++ .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm,
- ++ .gen_request_stats = ath10k_wmi_op_gen_request_stats,
- ++ .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang,
- ++ .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx,
- ++ .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg,
- ++ .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable,
- ++ .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable,
- ++ .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode,
- ++ /* .gen_pdev_get_temperature not implemented */
- ++ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp,
- ++ .gen_addba_send = ath10k_wmi_op_gen_addba_send,
- ++ .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
- ++ .gen_delba_send = ath10k_wmi_op_gen_delba_send,
- ++ /* .gen_bcn_tmpl not implemented */
- ++ /* .gen_prb_tmpl not implemented */
- ++ /* .gen_p2p_go_bcn_ie not implemented */
- ++};
- ++
- ++static const struct wmi_ops wmi_10_1_ops = {
- ++ .rx = ath10k_wmi_10_1_op_rx,
- ++ .map_svc = wmi_10x_svc_map,
- ++ .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev,
- ++ .pull_fw_stats = ath10k_wmi_10x_op_pull_fw_stats,
- ++ .gen_init = ath10k_wmi_10_1_op_gen_init,
- ++ .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd,
- ++ .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan,
- ++ .gen_peer_assoc = ath10k_wmi_10_1_op_gen_peer_assoc,
- ++ /* .gen_pdev_get_temperature not implemented */
- ++
- ++ /* shared with main branch */
- ++ .pull_scan = ath10k_wmi_op_pull_scan_ev,
- ++ .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev,
- ++ .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
- ++ .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
- ++ .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
- ++ .pull_swba = ath10k_wmi_op_pull_swba_ev,
- ++ .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
- ++ .pull_rdy = ath10k_wmi_op_pull_rdy_ev,
- ++
- ++ .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
- ++ .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
- ++ .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
- ++ .gen_stop_scan = ath10k_wmi_op_gen_stop_scan,
- ++ .gen_vdev_create = ath10k_wmi_op_gen_vdev_create,
- ++ .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete,
- ++ .gen_vdev_start = ath10k_wmi_op_gen_vdev_start,
- ++ .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop,
- ++ .gen_vdev_up = ath10k_wmi_op_gen_vdev_up,
- ++ .gen_vdev_down = ath10k_wmi_op_gen_vdev_down,
- ++ .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param,
- ++ .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key,
- ++ .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf,
- ++ .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable,
- ++ /* .gen_vdev_wmm_conf not implemented */
- ++ .gen_peer_create = ath10k_wmi_op_gen_peer_create,
- ++ .gen_peer_delete = ath10k_wmi_op_gen_peer_delete,
- ++ .gen_peer_flush = ath10k_wmi_op_gen_peer_flush,
- ++ .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param,
- ++ .gen_set_psmode = ath10k_wmi_op_gen_set_psmode,
- ++ .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps,
- ++ .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps,
- ++ .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list,
- ++ .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma,
- ++ .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm,
- ++ .gen_request_stats = ath10k_wmi_op_gen_request_stats,
- ++ .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang,
- ++ .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx,
- ++ .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg,
- ++ .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable,
- ++ .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable,
- ++ .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode,
- ++ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp,
- ++ .gen_addba_send = ath10k_wmi_op_gen_addba_send,
- ++ .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
- ++ .gen_delba_send = ath10k_wmi_op_gen_delba_send,
- ++ /* .gen_bcn_tmpl not implemented */
- ++ /* .gen_prb_tmpl not implemented */
- ++ /* .gen_p2p_go_bcn_ie not implemented */
- ++};
- ++
- ++static const struct wmi_ops wmi_10_2_ops = {
- ++ .rx = ath10k_wmi_10_2_op_rx,
- ++ .pull_fw_stats = ath10k_wmi_10_2_op_pull_fw_stats,
- ++ .gen_init = ath10k_wmi_10_2_op_gen_init,
- ++ .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc,
- ++ /* .gen_pdev_get_temperature not implemented */
- ++
- ++ /* shared with 10.1 */
- ++ .map_svc = wmi_10x_svc_map,
- ++ .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev,
- ++ .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd,
- ++ .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan,
- ++
- ++ .pull_scan = ath10k_wmi_op_pull_scan_ev,
- ++ .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev,
- ++ .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
- ++ .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
- ++ .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
- ++ .pull_swba = ath10k_wmi_op_pull_swba_ev,
- ++ .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
- ++ .pull_rdy = ath10k_wmi_op_pull_rdy_ev,
- ++
- ++ .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
- ++ .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
- ++ .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
- ++ .gen_stop_scan = ath10k_wmi_op_gen_stop_scan,
- ++ .gen_vdev_create = ath10k_wmi_op_gen_vdev_create,
- ++ .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete,
- ++ .gen_vdev_start = ath10k_wmi_op_gen_vdev_start,
- ++ .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop,
- ++ .gen_vdev_up = ath10k_wmi_op_gen_vdev_up,
- ++ .gen_vdev_down = ath10k_wmi_op_gen_vdev_down,
- ++ .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param,
- ++ .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key,
- ++ .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf,
- ++ .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable,
- ++ /* .gen_vdev_wmm_conf not implemented */
- ++ .gen_peer_create = ath10k_wmi_op_gen_peer_create,
- ++ .gen_peer_delete = ath10k_wmi_op_gen_peer_delete,
- ++ .gen_peer_flush = ath10k_wmi_op_gen_peer_flush,
- ++ .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param,
- ++ .gen_set_psmode = ath10k_wmi_op_gen_set_psmode,
- ++ .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps,
- ++ .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps,
- ++ .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list,
- ++ .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma,
- ++ .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm,
- ++ .gen_request_stats = ath10k_wmi_op_gen_request_stats,
- ++ .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang,
- ++ .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx,
- ++ .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg,
- ++ .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable,
- ++ .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable,
- ++ .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode,
- ++ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp,
- ++ .gen_addba_send = ath10k_wmi_op_gen_addba_send,
- ++ .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
- ++ .gen_delba_send = ath10k_wmi_op_gen_delba_send,
- ++};
- ++
- ++static const struct wmi_ops wmi_10_2_4_ops = {
- ++ .rx = ath10k_wmi_10_2_op_rx,
- ++ .pull_fw_stats = ath10k_wmi_10_2_4_op_pull_fw_stats,
- ++ .gen_init = ath10k_wmi_10_2_op_gen_init,
- ++ .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc,
- ++ .gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature,
- ++
- ++ /* shared with 10.1 */
- ++ .map_svc = wmi_10x_svc_map,
- ++ .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev,
- ++ .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd,
- ++ .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan,
- ++
- ++ .pull_scan = ath10k_wmi_op_pull_scan_ev,
- ++ .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev,
- ++ .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
- ++ .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
- ++ .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
- ++ .pull_swba = ath10k_wmi_op_pull_swba_ev,
- ++ .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
- ++ .pull_rdy = ath10k_wmi_op_pull_rdy_ev,
- ++
- ++ .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
- ++ .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
- ++ .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
- ++ .gen_stop_scan = ath10k_wmi_op_gen_stop_scan,
- ++ .gen_vdev_create = ath10k_wmi_op_gen_vdev_create,
- ++ .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete,
- ++ .gen_vdev_start = ath10k_wmi_op_gen_vdev_start,
- ++ .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop,
- ++ .gen_vdev_up = ath10k_wmi_op_gen_vdev_up,
- ++ .gen_vdev_down = ath10k_wmi_op_gen_vdev_down,
- ++ .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param,
- ++ .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key,
- ++ .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf,
- ++ .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable,
- ++ .gen_peer_create = ath10k_wmi_op_gen_peer_create,
- ++ .gen_peer_delete = ath10k_wmi_op_gen_peer_delete,
- ++ .gen_peer_flush = ath10k_wmi_op_gen_peer_flush,
- ++ .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param,
- ++ .gen_set_psmode = ath10k_wmi_op_gen_set_psmode,
- ++ .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps,
- ++ .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps,
- ++ .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list,
- ++ .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma,
- ++ .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm,
- ++ .gen_request_stats = ath10k_wmi_op_gen_request_stats,
- ++ .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang,
- ++ .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx,
- ++ .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg,
- ++ .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable,
- ++ .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable,
- ++ .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode,
- ++ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp,
- ++ .gen_addba_send = ath10k_wmi_op_gen_addba_send,
- ++ .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
- ++ .gen_delba_send = ath10k_wmi_op_gen_delba_send,
- ++ /* .gen_bcn_tmpl not implemented */
- ++ /* .gen_prb_tmpl not implemented */
- ++ /* .gen_p2p_go_bcn_ie not implemented */
- ++};
- ++
- ++int ath10k_wmi_attach(struct ath10k *ar)
- ++{
- ++ switch (ar->wmi.op_version) {
- ++ case ATH10K_FW_WMI_OP_VERSION_10_2_4:
- ++ ar->wmi.cmd = &wmi_10_2_4_cmd_map;
- ++ ar->wmi.ops = &wmi_10_2_4_ops;
- ++ ar->wmi.vdev_param = &wmi_10_2_4_vdev_param_map;
- ++ ar->wmi.pdev_param = &wmi_10_2_4_pdev_param_map;
- ++ break;
- ++ case ATH10K_FW_WMI_OP_VERSION_10_2:
- ++ ar->wmi.cmd = &wmi_10_2_cmd_map;
- ++ ar->wmi.ops = &wmi_10_2_ops;
- ++ ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
- ++ ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
- ++ break;
- ++ case ATH10K_FW_WMI_OP_VERSION_10_1:
- ++ ar->wmi.cmd = &wmi_10x_cmd_map;
- ++ ar->wmi.ops = &wmi_10_1_ops;
- ++ ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
- ++ ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
- ++ break;
- ++ case ATH10K_FW_WMI_OP_VERSION_MAIN:
- ++ ar->wmi.cmd = &wmi_cmd_map;
- ++ ar->wmi.ops = &wmi_ops;
- ++ ar->wmi.vdev_param = &wmi_vdev_param_map;
- ++ ar->wmi.pdev_param = &wmi_pdev_param_map;
- ++ break;
- ++ case ATH10K_FW_WMI_OP_VERSION_TLV:
- ++ ath10k_wmi_tlv_attach(ar);
- ++ break;
- ++ case ATH10K_FW_WMI_OP_VERSION_UNSET:
- ++ case ATH10K_FW_WMI_OP_VERSION_MAX:
- ++ ath10k_err(ar, "unsupported WMI op version: %d\n",
- ++ ar->wmi.op_version);
- ++ return -EINVAL;
- ++ }
- ++
- ++ init_completion(&ar->wmi.service_ready);
- ++ init_completion(&ar->wmi.unified_ready);
- ++
- ++ return 0;
- ++}
- ++
- ++void ath10k_wmi_detach(struct ath10k *ar)
- ++{
- ++ int i;
- ++
- ++ /* free the host memory chunks requested by firmware */
- ++ for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
- ++ dma_free_coherent(ar->dev,
- ++ ar->wmi.mem_chunks[i].len,
- ++ ar->wmi.mem_chunks[i].vaddr,
- ++ ar->wmi.mem_chunks[i].paddr);
- ++ }
- ++
- ++ ar->wmi.num_mem_chunks = 0;
- + }
- +--- a/drivers/net/wireless/ath/ath10k/wmi.h
- ++++ b/drivers/net/wireless/ath/ath10k/wmi.h
- +@@ -73,119 +73,361 @@ struct wmi_cmd_hdr {
- + #define HTC_PROTOCOL_VERSION 0x0002
- + #define WMI_PROTOCOL_VERSION 0x0002
- +
- +-enum wmi_service_id {
- +- WMI_SERVICE_BEACON_OFFLOAD = 0, /* beacon offload */
- +- WMI_SERVICE_SCAN_OFFLOAD, /* scan offload */
- +- WMI_SERVICE_ROAM_OFFLOAD, /* roam offload */
- +- WMI_SERVICE_BCN_MISS_OFFLOAD, /* beacon miss offload */
- +- WMI_SERVICE_STA_PWRSAVE, /* fake sleep + basic power save */
- +- WMI_SERVICE_STA_ADVANCED_PWRSAVE, /* uapsd, pspoll, force sleep */
- +- WMI_SERVICE_AP_UAPSD, /* uapsd on AP */
- +- WMI_SERVICE_AP_DFS, /* DFS on AP */
- +- WMI_SERVICE_11AC, /* supports 11ac */
- +- WMI_SERVICE_BLOCKACK, /* Supports triggering ADDBA/DELBA from host*/
- +- WMI_SERVICE_PHYERR, /* PHY error */
- +- WMI_SERVICE_BCN_FILTER, /* Beacon filter support */
- +- WMI_SERVICE_RTT, /* RTT (round trip time) support */
- +- WMI_SERVICE_RATECTRL, /* Rate-control */
- +- WMI_SERVICE_WOW, /* WOW Support */
- +- WMI_SERVICE_RATECTRL_CACHE, /* Rate-control caching */
- +- WMI_SERVICE_IRAM_TIDS, /* TIDs in IRAM */
- +- WMI_SERVICE_ARPNS_OFFLOAD, /* ARP NS Offload support */
- +- WMI_SERVICE_NLO, /* Network list offload service */
- +- WMI_SERVICE_GTK_OFFLOAD, /* GTK offload */
- +- WMI_SERVICE_SCAN_SCH, /* Scan Scheduler Service */
- +- WMI_SERVICE_CSA_OFFLOAD, /* CSA offload service */
- +- WMI_SERVICE_CHATTER, /* Chatter service */
- +- WMI_SERVICE_COEX_FREQAVOID, /* FW report freq range to avoid */
- +- WMI_SERVICE_PACKET_POWER_SAVE, /* packet power save service */
- +- WMI_SERVICE_FORCE_FW_HANG, /* To test fw recovery mechanism */
- +- WMI_SERVICE_GPIO, /* GPIO service */
- +- WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, /* Modulated DTIM support */
- +- WMI_STA_UAPSD_BASIC_AUTO_TRIG, /* UAPSD AC Trigger Generation */
- +- WMI_STA_UAPSD_VAR_AUTO_TRIG, /* -do- */
- +- WMI_SERVICE_STA_KEEP_ALIVE, /* STA keep alive mechanism support */
- +- WMI_SERVICE_TX_ENCAP, /* Packet type for TX encapsulation */
- +-
- +- WMI_SERVICE_LAST,
- +- WMI_MAX_SERVICE = 64 /* max service */
- ++enum wmi_service {
- ++ WMI_SERVICE_BEACON_OFFLOAD = 0,
- ++ WMI_SERVICE_SCAN_OFFLOAD,
- ++ WMI_SERVICE_ROAM_OFFLOAD,
- ++ WMI_SERVICE_BCN_MISS_OFFLOAD,
- ++ WMI_SERVICE_STA_PWRSAVE,
- ++ WMI_SERVICE_STA_ADVANCED_PWRSAVE,
- ++ WMI_SERVICE_AP_UAPSD,
- ++ WMI_SERVICE_AP_DFS,
- ++ WMI_SERVICE_11AC,
- ++ WMI_SERVICE_BLOCKACK,
- ++ WMI_SERVICE_PHYERR,
- ++ WMI_SERVICE_BCN_FILTER,
- ++ WMI_SERVICE_RTT,
- ++ WMI_SERVICE_RATECTRL,
- ++ WMI_SERVICE_WOW,
- ++ WMI_SERVICE_RATECTRL_CACHE,
- ++ WMI_SERVICE_IRAM_TIDS,
- ++ WMI_SERVICE_ARPNS_OFFLOAD,
- ++ WMI_SERVICE_NLO,
- ++ WMI_SERVICE_GTK_OFFLOAD,
- ++ WMI_SERVICE_SCAN_SCH,
- ++ WMI_SERVICE_CSA_OFFLOAD,
- ++ WMI_SERVICE_CHATTER,
- ++ WMI_SERVICE_COEX_FREQAVOID,
- ++ WMI_SERVICE_PACKET_POWER_SAVE,
- ++ WMI_SERVICE_FORCE_FW_HANG,
- ++ WMI_SERVICE_GPIO,
- ++ WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
- ++ WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
- ++ WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
- ++ WMI_SERVICE_STA_KEEP_ALIVE,
- ++ WMI_SERVICE_TX_ENCAP,
- ++ WMI_SERVICE_BURST,
- ++ WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT,
- ++ WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT,
- ++ WMI_SERVICE_ROAM_SCAN_OFFLOAD,
- ++ WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC,
- ++ WMI_SERVICE_EARLY_RX,
- ++ WMI_SERVICE_STA_SMPS,
- ++ WMI_SERVICE_FWTEST,
- ++ WMI_SERVICE_STA_WMMAC,
- ++ WMI_SERVICE_TDLS,
- ++ WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE,
- ++ WMI_SERVICE_ADAPTIVE_OCS,
- ++ WMI_SERVICE_BA_SSN_SUPPORT,
- ++ WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE,
- ++ WMI_SERVICE_WLAN_HB,
- ++ WMI_SERVICE_LTE_ANT_SHARE_SUPPORT,
- ++ WMI_SERVICE_BATCH_SCAN,
- ++ WMI_SERVICE_QPOWER,
- ++ WMI_SERVICE_PLMREQ,
- ++ WMI_SERVICE_THERMAL_MGMT,
- ++ WMI_SERVICE_RMC,
- ++ WMI_SERVICE_MHF_OFFLOAD,
- ++ WMI_SERVICE_COEX_SAR,
- ++ WMI_SERVICE_BCN_TXRATE_OVERRIDE,
- ++ WMI_SERVICE_NAN,
- ++ WMI_SERVICE_L1SS_STAT,
- ++ WMI_SERVICE_ESTIMATE_LINKSPEED,
- ++ WMI_SERVICE_OBSS_SCAN,
- ++ WMI_SERVICE_TDLS_OFFCHAN,
- ++ WMI_SERVICE_TDLS_UAPSD_BUFFER_STA,
- ++ WMI_SERVICE_TDLS_UAPSD_SLEEP_STA,
- ++ WMI_SERVICE_IBSS_PWRSAVE,
- ++ WMI_SERVICE_LPASS,
- ++ WMI_SERVICE_EXTSCAN,
- ++ WMI_SERVICE_D0WOW,
- ++ WMI_SERVICE_HSOFFLOAD,
- ++ WMI_SERVICE_ROAM_HO_OFFLOAD,
- ++ WMI_SERVICE_RX_FULL_REORDER,
- ++ WMI_SERVICE_DHCP_OFFLOAD,
- ++ WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
- ++ WMI_SERVICE_MDNS_OFFLOAD,
- ++ WMI_SERVICE_SAP_AUTH_OFFLOAD,
- ++
- ++ /* keep last */
- ++ WMI_SERVICE_MAX,
- ++};
- ++
- ++enum wmi_10x_service {
- ++ WMI_10X_SERVICE_BEACON_OFFLOAD = 0,
- ++ WMI_10X_SERVICE_SCAN_OFFLOAD,
- ++ WMI_10X_SERVICE_ROAM_OFFLOAD,
- ++ WMI_10X_SERVICE_BCN_MISS_OFFLOAD,
- ++ WMI_10X_SERVICE_STA_PWRSAVE,
- ++ WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE,
- ++ WMI_10X_SERVICE_AP_UAPSD,
- ++ WMI_10X_SERVICE_AP_DFS,
- ++ WMI_10X_SERVICE_11AC,
- ++ WMI_10X_SERVICE_BLOCKACK,
- ++ WMI_10X_SERVICE_PHYERR,
- ++ WMI_10X_SERVICE_BCN_FILTER,
- ++ WMI_10X_SERVICE_RTT,
- ++ WMI_10X_SERVICE_RATECTRL,
- ++ WMI_10X_SERVICE_WOW,
- ++ WMI_10X_SERVICE_RATECTRL_CACHE,
- ++ WMI_10X_SERVICE_IRAM_TIDS,
- ++ WMI_10X_SERVICE_BURST,
- ++
- ++ /* introduced in 10.2 */
- ++ WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
- ++ WMI_10X_SERVICE_FORCE_FW_HANG,
- ++ WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
- ++};
- ++
- ++enum wmi_main_service {
- ++ WMI_MAIN_SERVICE_BEACON_OFFLOAD = 0,
- ++ WMI_MAIN_SERVICE_SCAN_OFFLOAD,
- ++ WMI_MAIN_SERVICE_ROAM_OFFLOAD,
- ++ WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD,
- ++ WMI_MAIN_SERVICE_STA_PWRSAVE,
- ++ WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE,
- ++ WMI_MAIN_SERVICE_AP_UAPSD,
- ++ WMI_MAIN_SERVICE_AP_DFS,
- ++ WMI_MAIN_SERVICE_11AC,
- ++ WMI_MAIN_SERVICE_BLOCKACK,
- ++ WMI_MAIN_SERVICE_PHYERR,
- ++ WMI_MAIN_SERVICE_BCN_FILTER,
- ++ WMI_MAIN_SERVICE_RTT,
- ++ WMI_MAIN_SERVICE_RATECTRL,
- ++ WMI_MAIN_SERVICE_WOW,
- ++ WMI_MAIN_SERVICE_RATECTRL_CACHE,
- ++ WMI_MAIN_SERVICE_IRAM_TIDS,
- ++ WMI_MAIN_SERVICE_ARPNS_OFFLOAD,
- ++ WMI_MAIN_SERVICE_NLO,
- ++ WMI_MAIN_SERVICE_GTK_OFFLOAD,
- ++ WMI_MAIN_SERVICE_SCAN_SCH,
- ++ WMI_MAIN_SERVICE_CSA_OFFLOAD,
- ++ WMI_MAIN_SERVICE_CHATTER,
- ++ WMI_MAIN_SERVICE_COEX_FREQAVOID,
- ++ WMI_MAIN_SERVICE_PACKET_POWER_SAVE,
- ++ WMI_MAIN_SERVICE_FORCE_FW_HANG,
- ++ WMI_MAIN_SERVICE_GPIO,
- ++ WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
- ++ WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
- ++ WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
- ++ WMI_MAIN_SERVICE_STA_KEEP_ALIVE,
- ++ WMI_MAIN_SERVICE_TX_ENCAP,
- + };
- +
- + static inline char *wmi_service_name(int service_id)
- + {
- ++#define SVCSTR(x) case x: return #x
- ++
- + switch (service_id) {
- +- case WMI_SERVICE_BEACON_OFFLOAD:
- +- return "BEACON_OFFLOAD";
- +- case WMI_SERVICE_SCAN_OFFLOAD:
- +- return "SCAN_OFFLOAD";
- +- case WMI_SERVICE_ROAM_OFFLOAD:
- +- return "ROAM_OFFLOAD";
- +- case WMI_SERVICE_BCN_MISS_OFFLOAD:
- +- return "BCN_MISS_OFFLOAD";
- +- case WMI_SERVICE_STA_PWRSAVE:
- +- return "STA_PWRSAVE";
- +- case WMI_SERVICE_STA_ADVANCED_PWRSAVE:
- +- return "STA_ADVANCED_PWRSAVE";
- +- case WMI_SERVICE_AP_UAPSD:
- +- return "AP_UAPSD";
- +- case WMI_SERVICE_AP_DFS:
- +- return "AP_DFS";
- +- case WMI_SERVICE_11AC:
- +- return "11AC";
- +- case WMI_SERVICE_BLOCKACK:
- +- return "BLOCKACK";
- +- case WMI_SERVICE_PHYERR:
- +- return "PHYERR";
- +- case WMI_SERVICE_BCN_FILTER:
- +- return "BCN_FILTER";
- +- case WMI_SERVICE_RTT:
- +- return "RTT";
- +- case WMI_SERVICE_RATECTRL:
- +- return "RATECTRL";
- +- case WMI_SERVICE_WOW:
- +- return "WOW";
- +- case WMI_SERVICE_RATECTRL_CACHE:
- +- return "RATECTRL CACHE";
- +- case WMI_SERVICE_IRAM_TIDS:
- +- return "IRAM TIDS";
- +- case WMI_SERVICE_ARPNS_OFFLOAD:
- +- return "ARPNS_OFFLOAD";
- +- case WMI_SERVICE_NLO:
- +- return "NLO";
- +- case WMI_SERVICE_GTK_OFFLOAD:
- +- return "GTK_OFFLOAD";
- +- case WMI_SERVICE_SCAN_SCH:
- +- return "SCAN_SCH";
- +- case WMI_SERVICE_CSA_OFFLOAD:
- +- return "CSA_OFFLOAD";
- +- case WMI_SERVICE_CHATTER:
- +- return "CHATTER";
- +- case WMI_SERVICE_COEX_FREQAVOID:
- +- return "COEX_FREQAVOID";
- +- case WMI_SERVICE_PACKET_POWER_SAVE:
- +- return "PACKET_POWER_SAVE";
- +- case WMI_SERVICE_FORCE_FW_HANG:
- +- return "FORCE FW HANG";
- +- case WMI_SERVICE_GPIO:
- +- return "GPIO";
- +- case WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM:
- +- return "MODULATED DTIM";
- +- case WMI_STA_UAPSD_BASIC_AUTO_TRIG:
- +- return "BASIC UAPSD";
- +- case WMI_STA_UAPSD_VAR_AUTO_TRIG:
- +- return "VAR UAPSD";
- +- case WMI_SERVICE_STA_KEEP_ALIVE:
- +- return "STA KEEP ALIVE";
- +- case WMI_SERVICE_TX_ENCAP:
- +- return "TX ENCAP";
- ++ SVCSTR(WMI_SERVICE_BEACON_OFFLOAD);
- ++ SVCSTR(WMI_SERVICE_SCAN_OFFLOAD);
- ++ SVCSTR(WMI_SERVICE_ROAM_OFFLOAD);
- ++ SVCSTR(WMI_SERVICE_BCN_MISS_OFFLOAD);
- ++ SVCSTR(WMI_SERVICE_STA_PWRSAVE);
- ++ SVCSTR(WMI_SERVICE_STA_ADVANCED_PWRSAVE);
- ++ SVCSTR(WMI_SERVICE_AP_UAPSD);
- ++ SVCSTR(WMI_SERVICE_AP_DFS);
- ++ SVCSTR(WMI_SERVICE_11AC);
- ++ SVCSTR(WMI_SERVICE_BLOCKACK);
- ++ SVCSTR(WMI_SERVICE_PHYERR);
- ++ SVCSTR(WMI_SERVICE_BCN_FILTER);
- ++ SVCSTR(WMI_SERVICE_RTT);
- ++ SVCSTR(WMI_SERVICE_RATECTRL);
- ++ SVCSTR(WMI_SERVICE_WOW);
- ++ SVCSTR(WMI_SERVICE_RATECTRL_CACHE);
- ++ SVCSTR(WMI_SERVICE_IRAM_TIDS);
- ++ SVCSTR(WMI_SERVICE_ARPNS_OFFLOAD);
- ++ SVCSTR(WMI_SERVICE_NLO);
- ++ SVCSTR(WMI_SERVICE_GTK_OFFLOAD);
- ++ SVCSTR(WMI_SERVICE_SCAN_SCH);
- ++ SVCSTR(WMI_SERVICE_CSA_OFFLOAD);
- ++ SVCSTR(WMI_SERVICE_CHATTER);
- ++ SVCSTR(WMI_SERVICE_COEX_FREQAVOID);
- ++ SVCSTR(WMI_SERVICE_PACKET_POWER_SAVE);
- ++ SVCSTR(WMI_SERVICE_FORCE_FW_HANG);
- ++ SVCSTR(WMI_SERVICE_GPIO);
- ++ SVCSTR(WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM);
- ++ SVCSTR(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG);
- ++ SVCSTR(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG);
- ++ SVCSTR(WMI_SERVICE_STA_KEEP_ALIVE);
- ++ SVCSTR(WMI_SERVICE_TX_ENCAP);
- ++ SVCSTR(WMI_SERVICE_BURST);
- ++ SVCSTR(WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
- ++ SVCSTR(WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
- ++ SVCSTR(WMI_SERVICE_ROAM_SCAN_OFFLOAD);
- ++ SVCSTR(WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC);
- ++ SVCSTR(WMI_SERVICE_EARLY_RX);
- ++ SVCSTR(WMI_SERVICE_STA_SMPS);
- ++ SVCSTR(WMI_SERVICE_FWTEST);
- ++ SVCSTR(WMI_SERVICE_STA_WMMAC);
- ++ SVCSTR(WMI_SERVICE_TDLS);
- ++ SVCSTR(WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE);
- ++ SVCSTR(WMI_SERVICE_ADAPTIVE_OCS);
- ++ SVCSTR(WMI_SERVICE_BA_SSN_SUPPORT);
- ++ SVCSTR(WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE);
- ++ SVCSTR(WMI_SERVICE_WLAN_HB);
- ++ SVCSTR(WMI_SERVICE_LTE_ANT_SHARE_SUPPORT);
- ++ SVCSTR(WMI_SERVICE_BATCH_SCAN);
- ++ SVCSTR(WMI_SERVICE_QPOWER);
- ++ SVCSTR(WMI_SERVICE_PLMREQ);
- ++ SVCSTR(WMI_SERVICE_THERMAL_MGMT);
- ++ SVCSTR(WMI_SERVICE_RMC);
- ++ SVCSTR(WMI_SERVICE_MHF_OFFLOAD);
- ++ SVCSTR(WMI_SERVICE_COEX_SAR);
- ++ SVCSTR(WMI_SERVICE_BCN_TXRATE_OVERRIDE);
- ++ SVCSTR(WMI_SERVICE_NAN);
- ++ SVCSTR(WMI_SERVICE_L1SS_STAT);
- ++ SVCSTR(WMI_SERVICE_ESTIMATE_LINKSPEED);
- ++ SVCSTR(WMI_SERVICE_OBSS_SCAN);
- ++ SVCSTR(WMI_SERVICE_TDLS_OFFCHAN);
- ++ SVCSTR(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA);
- ++ SVCSTR(WMI_SERVICE_TDLS_UAPSD_SLEEP_STA);
- ++ SVCSTR(WMI_SERVICE_IBSS_PWRSAVE);
- ++ SVCSTR(WMI_SERVICE_LPASS);
- ++ SVCSTR(WMI_SERVICE_EXTSCAN);
- ++ SVCSTR(WMI_SERVICE_D0WOW);
- ++ SVCSTR(WMI_SERVICE_HSOFFLOAD);
- ++ SVCSTR(WMI_SERVICE_ROAM_HO_OFFLOAD);
- ++ SVCSTR(WMI_SERVICE_RX_FULL_REORDER);
- ++ SVCSTR(WMI_SERVICE_DHCP_OFFLOAD);
- ++ SVCSTR(WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT);
- ++ SVCSTR(WMI_SERVICE_MDNS_OFFLOAD);
- ++ SVCSTR(WMI_SERVICE_SAP_AUTH_OFFLOAD);
- + default:
- +- return "UNKNOWN SERVICE\n";
- ++ return NULL;
- + }
- ++
- ++#undef SVCSTR
- + }
- +
- ++#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
- ++ ((svc_id) < (len) && \
- ++ __le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
- ++ BIT((svc_id)%(sizeof(u32))))
- ++
- ++#define SVCMAP(x, y, len) \
- ++ do { \
- ++ if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \
- ++ __set_bit(y, out); \
- ++ } while (0)
- ++
- ++static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out,
- ++ size_t len)
- ++{
- ++ SVCMAP(WMI_10X_SERVICE_BEACON_OFFLOAD,
- ++ WMI_SERVICE_BEACON_OFFLOAD, len);
- ++ SVCMAP(WMI_10X_SERVICE_SCAN_OFFLOAD,
- ++ WMI_SERVICE_SCAN_OFFLOAD, len);
- ++ SVCMAP(WMI_10X_SERVICE_ROAM_OFFLOAD,
- ++ WMI_SERVICE_ROAM_OFFLOAD, len);
- ++ SVCMAP(WMI_10X_SERVICE_BCN_MISS_OFFLOAD,
- ++ WMI_SERVICE_BCN_MISS_OFFLOAD, len);
- ++ SVCMAP(WMI_10X_SERVICE_STA_PWRSAVE,
- ++ WMI_SERVICE_STA_PWRSAVE, len);
- ++ SVCMAP(WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE,
- ++ WMI_SERVICE_STA_ADVANCED_PWRSAVE, len);
- ++ SVCMAP(WMI_10X_SERVICE_AP_UAPSD,
- ++ WMI_SERVICE_AP_UAPSD, len);
- ++ SVCMAP(WMI_10X_SERVICE_AP_DFS,
- ++ WMI_SERVICE_AP_DFS, len);
- ++ SVCMAP(WMI_10X_SERVICE_11AC,
- ++ WMI_SERVICE_11AC, len);
- ++ SVCMAP(WMI_10X_SERVICE_BLOCKACK,
- ++ WMI_SERVICE_BLOCKACK, len);
- ++ SVCMAP(WMI_10X_SERVICE_PHYERR,
- ++ WMI_SERVICE_PHYERR, len);
- ++ SVCMAP(WMI_10X_SERVICE_BCN_FILTER,
- ++ WMI_SERVICE_BCN_FILTER, len);
- ++ SVCMAP(WMI_10X_SERVICE_RTT,
- ++ WMI_SERVICE_RTT, len);
- ++ SVCMAP(WMI_10X_SERVICE_RATECTRL,
- ++ WMI_SERVICE_RATECTRL, len);
- ++ SVCMAP(WMI_10X_SERVICE_WOW,
- ++ WMI_SERVICE_WOW, len);
- ++ SVCMAP(WMI_10X_SERVICE_RATECTRL_CACHE,
- ++ WMI_SERVICE_RATECTRL_CACHE, len);
- ++ SVCMAP(WMI_10X_SERVICE_IRAM_TIDS,
- ++ WMI_SERVICE_IRAM_TIDS, len);
- ++ SVCMAP(WMI_10X_SERVICE_BURST,
- ++ WMI_SERVICE_BURST, len);
- ++ SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
- ++ WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, len);
- ++ SVCMAP(WMI_10X_SERVICE_FORCE_FW_HANG,
- ++ WMI_SERVICE_FORCE_FW_HANG, len);
- ++ SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
- ++ WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, len);
- ++}
- ++
- ++static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out,
- ++ size_t len)
- ++{
- ++ SVCMAP(WMI_MAIN_SERVICE_BEACON_OFFLOAD,
- ++ WMI_SERVICE_BEACON_OFFLOAD, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_SCAN_OFFLOAD,
- ++ WMI_SERVICE_SCAN_OFFLOAD, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_ROAM_OFFLOAD,
- ++ WMI_SERVICE_ROAM_OFFLOAD, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD,
- ++ WMI_SERVICE_BCN_MISS_OFFLOAD, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_STA_PWRSAVE,
- ++ WMI_SERVICE_STA_PWRSAVE, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE,
- ++ WMI_SERVICE_STA_ADVANCED_PWRSAVE, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_AP_UAPSD,
- ++ WMI_SERVICE_AP_UAPSD, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_AP_DFS,
- ++ WMI_SERVICE_AP_DFS, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_11AC,
- ++ WMI_SERVICE_11AC, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_BLOCKACK,
- ++ WMI_SERVICE_BLOCKACK, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_PHYERR,
- ++ WMI_SERVICE_PHYERR, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_BCN_FILTER,
- ++ WMI_SERVICE_BCN_FILTER, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_RTT,
- ++ WMI_SERVICE_RTT, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_RATECTRL,
- ++ WMI_SERVICE_RATECTRL, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_WOW,
- ++ WMI_SERVICE_WOW, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_RATECTRL_CACHE,
- ++ WMI_SERVICE_RATECTRL_CACHE, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_IRAM_TIDS,
- ++ WMI_SERVICE_IRAM_TIDS, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_ARPNS_OFFLOAD,
- ++ WMI_SERVICE_ARPNS_OFFLOAD, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_NLO,
- ++ WMI_SERVICE_NLO, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_GTK_OFFLOAD,
- ++ WMI_SERVICE_GTK_OFFLOAD, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_SCAN_SCH,
- ++ WMI_SERVICE_SCAN_SCH, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_CSA_OFFLOAD,
- ++ WMI_SERVICE_CSA_OFFLOAD, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_CHATTER,
- ++ WMI_SERVICE_CHATTER, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_COEX_FREQAVOID,
- ++ WMI_SERVICE_COEX_FREQAVOID, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_PACKET_POWER_SAVE,
- ++ WMI_SERVICE_PACKET_POWER_SAVE, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_FORCE_FW_HANG,
- ++ WMI_SERVICE_FORCE_FW_HANG, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_GPIO,
- ++ WMI_SERVICE_GPIO, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
- ++ WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
- ++ WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
- ++ WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_STA_KEEP_ALIVE,
- ++ WMI_SERVICE_STA_KEEP_ALIVE, len);
- ++ SVCMAP(WMI_MAIN_SERVICE_TX_ENCAP,
- ++ WMI_SERVICE_TX_ENCAP, len);
- ++}
- +
- +-#define WMI_SERVICE_BM_SIZE \
- +- ((WMI_MAX_SERVICE + sizeof(u32) - 1)/sizeof(u32))
- ++#undef SVCMAP
- +
- + /* 2 word representation of MAC addr */
- + struct wmi_mac_addr {
- +@@ -308,6 +550,8 @@ struct wmi_cmd_map {
- + u32 force_fw_hang_cmdid;
- + u32 gpio_config_cmdid;
- + u32 gpio_output_cmdid;
- ++ u32 pdev_get_temperature_cmdid;
- ++ u32 vdev_set_wmm_params_cmdid;
- + };
- +
- + /*
- +@@ -803,6 +1047,166 @@ enum wmi_10x_event_id {
- + WMI_10X_PDEV_UTF_EVENTID = WMI_10X_END_EVENTID-1,
- + };
- +
- ++enum wmi_10_2_cmd_id {
- ++ WMI_10_2_START_CMDID = 0x9000,
- ++ WMI_10_2_END_CMDID = 0x9FFF,
- ++ WMI_10_2_INIT_CMDID,
- ++ WMI_10_2_START_SCAN_CMDID = WMI_10_2_START_CMDID,
- ++ WMI_10_2_STOP_SCAN_CMDID,
- ++ WMI_10_2_SCAN_CHAN_LIST_CMDID,
- ++ WMI_10_2_ECHO_CMDID,
- ++ WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
- ++ WMI_10_2_PDEV_SET_CHANNEL_CMDID,
- ++ WMI_10_2_PDEV_SET_PARAM_CMDID,
- ++ WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
- ++ WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
- ++ WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
- ++ WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
- ++ WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
- ++ WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
- ++ WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
- ++ WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
- ++ WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
- ++ WMI_10_2_VDEV_CREATE_CMDID,
- ++ WMI_10_2_VDEV_DELETE_CMDID,
- ++ WMI_10_2_VDEV_START_REQUEST_CMDID,
- ++ WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
- ++ WMI_10_2_VDEV_UP_CMDID,
- ++ WMI_10_2_VDEV_STOP_CMDID,
- ++ WMI_10_2_VDEV_DOWN_CMDID,
- ++ WMI_10_2_VDEV_STANDBY_RESPONSE_CMDID,
- ++ WMI_10_2_VDEV_RESUME_RESPONSE_CMDID,
- ++ WMI_10_2_VDEV_SET_PARAM_CMDID,
- ++ WMI_10_2_VDEV_INSTALL_KEY_CMDID,
- ++ WMI_10_2_VDEV_SET_DSCP_TID_MAP_CMDID,
- ++ WMI_10_2_PEER_CREATE_CMDID,
- ++ WMI_10_2_PEER_DELETE_CMDID,
- ++ WMI_10_2_PEER_FLUSH_TIDS_CMDID,
- ++ WMI_10_2_PEER_SET_PARAM_CMDID,
- ++ WMI_10_2_PEER_ASSOC_CMDID,
- ++ WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
- ++ WMI_10_2_PEER_UPDATE_WDS_ENTRY_CMDID,
- ++ WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
- ++ WMI_10_2_PEER_MCAST_GROUP_CMDID,
- ++ WMI_10_2_BCN_TX_CMDID,
- ++ WMI_10_2_BCN_PRB_TMPL_CMDID,
- ++ WMI_10_2_BCN_FILTER_RX_CMDID,
- ++ WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
- ++ WMI_10_2_MGMT_TX_CMDID,
- ++ WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
- ++ WMI_10_2_ADDBA_SEND_CMDID,
- ++ WMI_10_2_ADDBA_STATUS_CMDID,
- ++ WMI_10_2_DELBA_SEND_CMDID,
- ++ WMI_10_2_ADDBA_SET_RESP_CMDID,
- ++ WMI_10_2_SEND_SINGLEAMSDU_CMDID,
- ++ WMI_10_2_STA_POWERSAVE_MODE_CMDID,
- ++ WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
- ++ WMI_10_2_STA_MIMO_PS_MODE_CMDID,
- ++ WMI_10_2_DBGLOG_CFG_CMDID,
- ++ WMI_10_2_PDEV_DFS_ENABLE_CMDID,
- ++ WMI_10_2_PDEV_DFS_DISABLE_CMDID,
- ++ WMI_10_2_PDEV_QVIT_CMDID,
- ++ WMI_10_2_ROAM_SCAN_MODE,
- ++ WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
- ++ WMI_10_2_ROAM_SCAN_PERIOD,
- ++ WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
- ++ WMI_10_2_ROAM_AP_PROFILE,
- ++ WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
- ++ WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
- ++ WMI_10_2_OFL_SCAN_PERIOD,
- ++ WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
- ++ WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
- ++ WMI_10_2_P2P_GO_SET_BEACON_IE,
- ++ WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
- ++ WMI_10_2_AP_PS_PEER_PARAM_CMDID,
- ++ WMI_10_2_AP_PS_PEER_UAPSD_COEX_CMDID,
- ++ WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
- ++ WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
- ++ WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
- ++ WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
- ++ WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
- ++ WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
- ++ WMI_10_2_PDEV_SUSPEND_CMDID,
- ++ WMI_10_2_PDEV_RESUME_CMDID,
- ++ WMI_10_2_ADD_BCN_FILTER_CMDID,
- ++ WMI_10_2_RMV_BCN_FILTER_CMDID,
- ++ WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
- ++ WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
- ++ WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
- ++ WMI_10_2_WOW_ENABLE_CMDID,
- ++ WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
- ++ WMI_10_2_RTT_MEASREQ_CMDID,
- ++ WMI_10_2_RTT_TSF_CMDID,
- ++ WMI_10_2_RTT_KEEPALIVE_CMDID,
- ++ WMI_10_2_PDEV_SEND_BCN_CMDID,
- ++ WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
- ++ WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
- ++ WMI_10_2_REQUEST_STATS_CMDID,
- ++ WMI_10_2_GPIO_CONFIG_CMDID,
- ++ WMI_10_2_GPIO_OUTPUT_CMDID,
- ++ WMI_10_2_VDEV_RATEMASK_CMDID,
- ++ WMI_10_2_PDEV_SMART_ANT_ENABLE_CMDID,
- ++ WMI_10_2_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID,
- ++ WMI_10_2_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID,
- ++ WMI_10_2_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID,
- ++ WMI_10_2_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID,
- ++ WMI_10_2_FORCE_FW_HANG_CMDID,
- ++ WMI_10_2_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID,
- ++ WMI_10_2_PDEV_SET_CTL_TABLE_CMDID,
- ++ WMI_10_2_PDEV_SET_MIMOGAIN_TABLE_CMDID,
- ++ WMI_10_2_PDEV_RATEPWR_TABLE_CMDID,
- ++ WMI_10_2_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID,
- ++ WMI_10_2_PDEV_GET_INFO,
- ++ WMI_10_2_VDEV_GET_INFO,
- ++ WMI_10_2_VDEV_ATF_REQUEST_CMDID,
- ++ WMI_10_2_PEER_ATF_REQUEST_CMDID,
- ++ WMI_10_2_PDEV_GET_TEMPERATURE_CMDID,
- ++ WMI_10_2_PDEV_UTF_CMDID = WMI_10_2_END_CMDID - 1,
- ++};
- ++
- ++enum wmi_10_2_event_id {
- ++ WMI_10_2_SERVICE_READY_EVENTID = 0x8000,
- ++ WMI_10_2_READY_EVENTID,
- ++ WMI_10_2_DEBUG_MESG_EVENTID,
- ++ WMI_10_2_START_EVENTID = 0x9000,
- ++ WMI_10_2_END_EVENTID = 0x9FFF,
- ++ WMI_10_2_SCAN_EVENTID = WMI_10_2_START_EVENTID,
- ++ WMI_10_2_ECHO_EVENTID,
- ++ WMI_10_2_UPDATE_STATS_EVENTID,
- ++ WMI_10_2_INST_RSSI_STATS_EVENTID,
- ++ WMI_10_2_VDEV_START_RESP_EVENTID,
- ++ WMI_10_2_VDEV_STANDBY_REQ_EVENTID,
- ++ WMI_10_2_VDEV_RESUME_REQ_EVENTID,
- ++ WMI_10_2_VDEV_STOPPED_EVENTID,
- ++ WMI_10_2_PEER_STA_KICKOUT_EVENTID,
- ++ WMI_10_2_HOST_SWBA_EVENTID,
- ++ WMI_10_2_TBTTOFFSET_UPDATE_EVENTID,
- ++ WMI_10_2_MGMT_RX_EVENTID,
- ++ WMI_10_2_CHAN_INFO_EVENTID,
- ++ WMI_10_2_PHYERR_EVENTID,
- ++ WMI_10_2_ROAM_EVENTID,
- ++ WMI_10_2_PROFILE_MATCH,
- ++ WMI_10_2_DEBUG_PRINT_EVENTID,
- ++ WMI_10_2_PDEV_QVIT_EVENTID,
- ++ WMI_10_2_WLAN_PROFILE_DATA_EVENTID,
- ++ WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID,
- ++ WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID,
- ++ WMI_10_2_RTT_ERROR_REPORT_EVENTID,
- ++ WMI_10_2_RTT_KEEPALIVE_EVENTID,
- ++ WMI_10_2_WOW_WAKEUP_HOST_EVENTID,
- ++ WMI_10_2_DCS_INTERFERENCE_EVENTID,
- ++ WMI_10_2_PDEV_TPC_CONFIG_EVENTID,
- ++ WMI_10_2_GPIO_INPUT_EVENTID,
- ++ WMI_10_2_PEER_RATECODE_LIST_EVENTID,
- ++ WMI_10_2_GENERIC_BUFFER_EVENTID,
- ++ WMI_10_2_MCAST_BUF_RELEASE_EVENTID,
- ++ WMI_10_2_MCAST_LIST_AGEOUT_EVENTID,
- ++ WMI_10_2_WDS_PEER_EVENTID,
- ++ WMI_10_2_PEER_STA_PS_STATECHG_EVENTID,
- ++ WMI_10_2_PDEV_TEMPERATURE_EVENTID,
- ++ WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1,
- ++};
- ++
- + enum wmi_phy_mode {
- + MODE_11A = 0, /* 11a Mode */
- + MODE_11G = 1, /* 11b/g Mode */
- +@@ -955,7 +1359,6 @@ enum wmi_channel_change_cause {
- + WMI_HT_CAP_RX_STBC | \
- + WMI_HT_CAP_LDPC)
- +
- +-
- + /*
- + * WMI_VHT_CAP_* these maps to ieee 802.11ac vht capability information
- + * field. The fields not defined here are not supported, or reserved.
- +@@ -1076,10 +1479,6 @@ struct wlan_host_mem_req {
- + __le32 num_units;
- + } __packed;
- +
- +-#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \
- +- ((((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
- +- (1 << ((svc_id)%(sizeof(u32))))) != 0)
- +-
- + /*
- + * The following struct holds optional payload for
- + * wmi_service_ready_event,e.g., 11ac pass some of the
- +@@ -1093,7 +1492,7 @@ struct wmi_service_ready_event {
- + __le32 phy_capability;
- + /* Maximum number of frag table entries that SW will populate less 1 */
- + __le32 max_frag_entry;
- +- __le32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE];
- ++ __le32 wmi_service_bitmap[16];
- + __le32 num_rf_chains;
- + /*
- + * The following field is only valid for service type
- +@@ -1119,11 +1518,11 @@ struct wmi_service_ready_event {
- + * where FW can access this memory directly (or) by DMA.
- + */
- + __le32 num_mem_reqs;
- +- struct wlan_host_mem_req mem_reqs[1];
- ++ struct wlan_host_mem_req mem_reqs[0];
- + } __packed;
- +
- + /* This is the definition from 10.X firmware branch */
- +-struct wmi_service_ready_event_10x {
- ++struct wmi_10x_service_ready_event {
- + __le32 sw_version;
- + __le32 abi_version;
- +
- +@@ -1132,7 +1531,7 @@ struct wmi_service_ready_event_10x {
- +
- + /* Maximum number of frag table entries that SW will populate less 1 */
- + __le32 max_frag_entry;
- +- __le32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE];
- ++ __le32 wmi_service_bitmap[16];
- + __le32 num_rf_chains;
- +
- + /*
- +@@ -1158,10 +1557,9 @@ struct wmi_service_ready_event_10x {
- + */
- + __le32 num_mem_reqs;
- +
- +- struct wlan_host_mem_req mem_reqs[1];
- ++ struct wlan_host_mem_req mem_reqs[0];
- + } __packed;
- +
- +-
- + #define WMI_SERVICE_READY_TIMEOUT_HZ (5*HZ)
- + #define WMI_UNIFIED_READY_TIMEOUT_HZ (5*HZ)
- +
- +@@ -1255,7 +1653,7 @@ struct wmi_resource_config {
- + */
- + __le32 rx_decap_mode;
- +
- +- /* what is the maximum scan requests than can be queued */
- ++ /* what is the maximum number of scan requests that can be queued */
- + __le32 scan_max_pending_reqs;
- +
- + /* maximum VDEV that could use BMISS offload */
- +@@ -1440,7 +1838,7 @@ struct wmi_resource_config_10x {
- + */
- + __le32 rx_decap_mode;
- +
- +- /* what is the maximum scan requests than can be queued */
- ++ /* what is the maximum number of scan requests that can be queued */
- + __le32 scan_max_pending_reqs;
- +
- + /* maximum VDEV that could use BMISS offload */
- +@@ -1551,6 +1949,21 @@ struct wmi_resource_config_10x {
- + __le32 max_frag_entries;
- + } __packed;
- +
- ++enum wmi_10_2_feature_mask {
- ++ WMI_10_2_RX_BATCH_MODE = BIT(0),
- ++ WMI_10_2_ATF_CONFIG = BIT(1),
- ++};
- ++
- ++struct wmi_resource_config_10_2 {
- ++ struct wmi_resource_config_10x common;
- ++ __le32 max_peer_ext_stats;
- ++ __le32 smart_ant_cap; /* 0-disable, 1-enable */
- ++ __le32 bk_min_free;
- ++ __le32 be_min_free;
- ++ __le32 vi_min_free;
- ++ __le32 vo_min_free;
- ++ __le32 feature_mask;
- ++} __packed;
- +
- + #define NUM_UNITS_IS_NUM_VDEVS 0x1
- + #define NUM_UNITS_IS_NUM_PEERS 0x2
- +@@ -1565,34 +1978,39 @@ struct host_memory_chunk {
- + __le32 size;
- + } __packed;
- +
- ++struct wmi_host_mem_chunks {
- ++ __le32 count;
- ++ /* some fw revisions require at least 1 chunk regardless of count */
- ++ struct host_memory_chunk items[1];
- ++} __packed;
- ++
- + struct wmi_init_cmd {
- + struct wmi_resource_config resource_config;
- +- __le32 num_host_mem_chunks;
- +-
- +- /*
- +- * variable number of host memory chunks.
- +- * This should be the last element in the structure
- +- */
- +- struct host_memory_chunk host_mem_chunks[1];
- ++ struct wmi_host_mem_chunks mem_chunks;
- + } __packed;
- +
- + /* _10x stucture is from 10.X FW API */
- + struct wmi_init_cmd_10x {
- + struct wmi_resource_config_10x resource_config;
- +- __le32 num_host_mem_chunks;
- ++ struct wmi_host_mem_chunks mem_chunks;
- ++} __packed;
- +
- +- /*
- +- * variable number of host memory chunks.
- +- * This should be the last element in the structure
- +- */
- +- struct host_memory_chunk host_mem_chunks[1];
- ++struct wmi_init_cmd_10_2 {
- ++ struct wmi_resource_config_10_2 resource_config;
- ++ struct wmi_host_mem_chunks mem_chunks;
- ++} __packed;
- ++
- ++struct wmi_chan_list_entry {
- ++ __le16 freq;
- ++ u8 phy_mode; /* valid for 10.2 only */
- ++ u8 reserved;
- + } __packed;
- +
- + /* TLV for channel list */
- + struct wmi_chan_list {
- + __le32 tag; /* WMI_CHAN_LIST_TAG */
- + __le32 num_chan;
- +- __le32 channel_list[0];
- ++ struct wmi_chan_list_entry channel_list[0];
- + } __packed;
- +
- + struct wmi_bssid_list {
- +@@ -1629,6 +2047,11 @@ struct wmi_ssid_list {
- + #define WLAN_SCAN_PARAMS_MAX_BSSID 4
- + #define WLAN_SCAN_PARAMS_MAX_IE_LEN 256
- +
- ++/* Values lower than this may be refused by some firmware revisions with a scan
- ++ * completion with a timedout reason.
- ++ */
- ++#define WMI_SCAN_CHAN_MIN_TIME_MSEC 40
- ++
- + /* Scan priority numbers must be sequential, starting with 0 */
- + enum wmi_scan_priority {
- + WMI_SCAN_PRIORITY_VERY_LOW = 0,
- +@@ -1639,7 +2062,7 @@ enum wmi_scan_priority {
- + WMI_SCAN_PRIORITY_COUNT /* number of priorities supported */
- + };
- +
- +-struct wmi_start_scan_cmd {
- ++struct wmi_start_scan_common {
- + /* Scan ID */
- + __le32 scan_id;
- + /* Scan requestor ID */
- +@@ -1697,97 +2120,26 @@ struct wmi_start_scan_cmd {
- + __le32 probe_delay;
- + /* Scan control flags */
- + __le32 scan_ctrl_flags;
- +-
- +- /* Burst duration time in msecs */
- +- __le32 burst_duration;
- +- /*
- +- * TLV (tag length value ) paramerters follow the scan_cmd structure.
- +- * TLV can contain channel list, bssid list, ssid list and
- +- * ie. the TLV tags are defined above;
- +- */
- + } __packed;
- +
- +-/* This is the definition from 10.X firmware branch */
- +-struct wmi_start_scan_cmd_10x {
- +- /* Scan ID */
- +- __le32 scan_id;
- +-
- +- /* Scan requestor ID */
- +- __le32 scan_req_id;
- +-
- +- /* VDEV id(interface) that is requesting scan */
- +- __le32 vdev_id;
- +-
- +- /* Scan Priority, input to scan scheduler */
- +- __le32 scan_priority;
- +-
- +- /* Scan events subscription */
- +- __le32 notify_scan_events;
- +-
- +- /* dwell time in msec on active channels */
- +- __le32 dwell_time_active;
- +-
- +- /* dwell time in msec on passive channels */
- +- __le32 dwell_time_passive;
- +-
- +- /*
- +- * min time in msec on the BSS channel,only valid if atleast one
- +- * VDEV is active
- +- */
- +- __le32 min_rest_time;
- +-
- +- /*
- +- * max rest time in msec on the BSS channel,only valid if at least
- +- * one VDEV is active
- +- */
- +- /*
- +- * the scanner will rest on the bss channel at least min_rest_time
- +- * after min_rest_time the scanner will start checking for tx/rx
- +- * activity on all VDEVs. if there is no activity the scanner will
- +- * switch to off channel. if there is activity the scanner will let
- +- * the radio on the bss channel until max_rest_time expires.at
- +- * max_rest_time scanner will switch to off channel irrespective of
- +- * activity. activity is determined by the idle_time parameter.
- +- */
- +- __le32 max_rest_time;
- +-
- +- /*
- +- * time before sending next set of probe requests.
- +- * The scanner keeps repeating probe requests transmission with
- +- * period specified by repeat_probe_time.
- +- * The number of probe requests specified depends on the ssid_list
- +- * and bssid_list
- +- */
- +- __le32 repeat_probe_time;
- +-
- +- /* time in msec between 2 consequetive probe requests with in a set. */
- +- __le32 probe_spacing_time;
- +-
- +- /*
- +- * data inactivity time in msec on bss channel that will be used by
- +- * scanner for measuring the inactivity.
- ++struct wmi_start_scan_tlvs {
- ++ /* TLV parameters. These includes channel list, ssid list, bssid list,
- ++ * extra ies.
- + */
- +- __le32 idle_time;
- +-
- +- /* maximum time in msec allowed for scan */
- +- __le32 max_scan_time;
- +-
- +- /*
- +- * delay in msec before sending first probe request after switching
- +- * to a channel
- +- */
- +- __le32 probe_delay;
- +-
- +- /* Scan control flags */
- +- __le32 scan_ctrl_flags;
- ++ u8 tlvs[0];
- ++} __packed;
- +
- +- /*
- +- * TLV (tag length value ) paramerters follow the scan_cmd structure.
- +- * TLV can contain channel list, bssid list, ssid list and
- +- * ie. the TLV tags are defined above;
- +- */
- ++struct wmi_start_scan_cmd {
- ++ struct wmi_start_scan_common common;
- ++ __le32 burst_duration_ms;
- ++ struct wmi_start_scan_tlvs tlvs;
- + } __packed;
- +
- ++/* This is the definition from 10.X firmware branch */
- ++struct wmi_10x_start_scan_cmd {
- ++ struct wmi_start_scan_common common;
- ++ struct wmi_start_scan_tlvs tlvs;
- ++} __packed;
- +
- + struct wmi_ssid_arg {
- + int len;
- +@@ -1821,7 +2173,7 @@ struct wmi_start_scan_arg {
- + u32 n_bssids;
- +
- + u8 ie[WLAN_SCAN_PARAMS_MAX_IE_LEN];
- +- u32 channels[64];
- ++ u16 channels[64];
- + struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID];
- + struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID];
- + };
- +@@ -1849,7 +2201,6 @@ struct wmi_start_scan_arg {
- + /* WMI_SCAN_CLASS_MASK must be the same value as IEEE80211_SCAN_CLASS_MASK */
- + #define WMI_SCAN_CLASS_MASK 0xFF000000
- +
- +-
- + enum wmi_stop_scan_type {
- + WMI_SCAN_STOP_ONE = 0x00000000, /* stop by scan_id */
- + WMI_SCAN_STOP_VDEV_ALL = 0x01000000, /* stop by vdev_id */
- +@@ -1973,100 +2324,31 @@ struct wmi_mgmt_rx_event_v2 {
- + #define PHY_ERROR_FALSE_RADAR_EXT 0x24
- + #define PHY_ERROR_RADAR 0x05
- +
- +-struct wmi_single_phyerr_rx_hdr {
- +- /* TSF timestamp */
- ++struct wmi_phyerr {
- + __le32 tsf_timestamp;
- +-
- +- /*
- +- * Current freq1, freq2
- +- *
- +- * [7:0]: freq1[lo]
- +- * [15:8] : freq1[hi]
- +- * [23:16]: freq2[lo]
- +- * [31:24]: freq2[hi]
- +- */
- + __le16 freq1;
- + __le16 freq2;
- +-
- +- /*
- +- * Combined RSSI over all chains and channel width for this PHY error
- +- *
- +- * [7:0]: RSSI combined
- +- * [15:8]: Channel width (MHz)
- +- * [23:16]: PHY error code
- +- * [24:16]: reserved (future use)
- +- */
- + u8 rssi_combined;
- + u8 chan_width_mhz;
- + u8 phy_err_code;
- + u8 rsvd0;
- +-
- +- /*
- +- * RSSI on chain 0 through 3
- +- *
- +- * This is formatted the same as the PPDU_START RX descriptor
- +- * field:
- +- *
- +- * [7:0]: pri20
- +- * [15:8]: sec20
- +- * [23:16]: sec40
- +- * [31:24]: sec80
- +- */
- +-
- +- __le32 rssi_chain0;
- +- __le32 rssi_chain1;
- +- __le32 rssi_chain2;
- +- __le32 rssi_chain3;
- +-
- +- /*
- +- * Last calibrated NF value for chain 0 through 3
- +- *
- +- * nf_list_1:
- +- *
- +- * + [15:0] - chain 0
- +- * + [31:16] - chain 1
- +- *
- +- * nf_list_2:
- +- *
- +- * + [15:0] - chain 2
- +- * + [31:16] - chain 3
- +- */
- +- __le32 nf_list_1;
- +- __le32 nf_list_2;
- +-
- +-
- +- /* Length of the frame */
- ++ __le32 rssi_chains[4];
- ++ __le16 nf_chains[4];
- + __le32 buf_len;
- ++ u8 buf[0];
- + } __packed;
- +
- +-struct wmi_single_phyerr_rx_event {
- +- /* Phy error event header */
- +- struct wmi_single_phyerr_rx_hdr hdr;
- +- /* frame buffer */
- +- u8 bufp[0];
- +-} __packed;
- +-
- +-struct wmi_comb_phyerr_rx_hdr {
- +- /* Phy error phy error count */
- +- __le32 num_phyerr_events;
- ++struct wmi_phyerr_event {
- ++ __le32 num_phyerrs;
- + __le32 tsf_l32;
- + __le32 tsf_u32;
- +-} __packed;
- +-
- +-struct wmi_comb_phyerr_rx_event {
- +- /* Phy error phy error count */
- +- struct wmi_comb_phyerr_rx_hdr hdr;
- +- /*
- +- * frame buffer - contains multiple payloads in the order:
- +- * header - payload, header - payload...
- +- * (The header is of type: wmi_single_phyerr_rx_hdr)
- +- */
- +- u8 bufp[0];
- ++ struct wmi_phyerr phyerrs[0];
- + } __packed;
- +
- + #define PHYERR_TLV_SIG 0xBB
- + #define PHYERR_TLV_TAG_SEARCH_FFT_REPORT 0xFB
- + #define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY 0xF8
- ++#define PHYERR_TLV_TAG_SPECTRAL_SUMMARY_REPORT 0xF9
- +
- + struct phyerr_radar_report {
- + __le32 reg0; /* RADAR_REPORT_REG0_* */
- +@@ -2135,7 +2417,6 @@ struct phyerr_fft_report {
- + #define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_MASK 0x000000FF
- + #define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_LSB 0
- +
- +-
- + struct phyerr_tlv {
- + __le16 len;
- + u8 tag;
- +@@ -2166,7 +2447,6 @@ struct wmi_echo_cmd {
- + __le32 value;
- + } __packed;
- +
- +-
- + struct wmi_pdev_set_regdomain_cmd {
- + __le32 reg_domain;
- + __le32 reg_domain_2G;
- +@@ -2215,7 +2495,6 @@ struct wmi_pdev_set_quiet_cmd {
- + __le32 enabled;
- + } __packed;
- +
- +-
- + /*
- + * 802.11g protection mode.
- + */
- +@@ -2318,14 +2597,15 @@ struct wmi_pdev_param_map {
- + u32 fast_channel_reset;
- + u32 burst_dur;
- + u32 burst_enable;
- ++ u32 cal_period;
- + };
- +
- + #define WMI_PDEV_PARAM_UNSUPPORTED 0
- +
- + enum wmi_pdev_param {
- +- /* TX chian mask */
- ++ /* TX chain mask */
- + WMI_PDEV_PARAM_TX_CHAIN_MASK = 0x1,
- +- /* RX chian mask */
- ++ /* RX chain mask */
- + WMI_PDEV_PARAM_RX_CHAIN_MASK,
- + /* TX power limit for 2G Radio */
- + WMI_PDEV_PARAM_TXPOWER_LIMIT2G,
- +@@ -2515,6 +2795,22 @@ enum wmi_10x_pdev_param {
- + WMI_10X_PDEV_PARAM_BURST_DUR,
- + /* Set Bursting Enable*/
- + WMI_10X_PDEV_PARAM_BURST_ENABLE,
- ++
- ++ /* following are available as of firmware 10.2 */
- ++ WMI_10X_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA,
- ++ WMI_10X_PDEV_PARAM_IGMPMLD_OVERRIDE,
- ++ WMI_10X_PDEV_PARAM_IGMPMLD_TID,
- ++ WMI_10X_PDEV_PARAM_ANTENNA_GAIN,
- ++ WMI_10X_PDEV_PARAM_RX_DECAP_MODE,
- ++ WMI_10X_PDEV_PARAM_RX_FILTER,
- ++ WMI_10X_PDEV_PARAM_SET_MCAST_TO_UCAST_TID,
- ++ WMI_10X_PDEV_PARAM_PROXY_STA_MODE,
- ++ WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_MODE,
- ++ WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_BUFFER,
- ++ WMI_10X_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER,
- ++ WMI_10X_PDEV_PARAM_PEER_STA_PS_STATECHG_ENABLE,
- ++ WMI_10X_PDEV_PARAM_RTS_FIXED_RATE,
- ++ WMI_10X_PDEV_PARAM_CAL_PERIOD
- + };
- +
- + struct wmi_pdev_set_param_cmd {
- +@@ -2522,6 +2818,9 @@ struct wmi_pdev_set_param_cmd {
- + __le32 param_value;
- + } __packed;
- +
- ++/* valid period is 1 ~ 60000ms, unit in millisecond */
- ++#define WMI_PDEV_PARAM_CAL_PERIOD_MAX 60000
- ++
- + struct wmi_pdev_get_tpc_config_cmd {
- + /* parameter */
- + __le32 param;
- +@@ -2565,11 +2864,6 @@ enum wmi_tp_scale {
- + WMI_TP_SCALE_SIZE = 5, /* max num of enum */
- + };
- +
- +-struct wmi_set_channel_cmd {
- +- /* channel (only frequency and mode info are used) */
- +- struct wmi_channel chan;
- +-} __packed;
- +-
- + struct wmi_pdev_chanlist_update_event {
- + /* number of channels */
- + __le32 num_chan;
- +@@ -2600,6 +2894,10 @@ struct wmi_pdev_set_channel_cmd {
- + struct wmi_channel chan;
- + } __packed;
- +
- ++struct wmi_pdev_pktlog_enable_cmd {
- ++ __le32 ev_bitmap;
- ++} __packed;
- ++
- + /* Customize the DSCP (bit) to TID (0-7) mapping for QOS */
- + #define WMI_DSCP_MAP_MAX (64)
- + struct wmi_pdev_set_dscp_tid_map_cmd {
- +@@ -2642,14 +2940,14 @@ struct wmi_wmm_params_arg {
- + u32 no_ack;
- + };
- +
- +-struct wmi_pdev_set_wmm_params_arg {
- ++struct wmi_wmm_params_all_arg {
- + struct wmi_wmm_params_arg ac_be;
- + struct wmi_wmm_params_arg ac_bk;
- + struct wmi_wmm_params_arg ac_vi;
- + struct wmi_wmm_params_arg ac_vo;
- + };
- +
- +-struct wal_dbg_tx_stats {
- ++struct wmi_pdev_stats_tx {
- + /* Num HTT cookies queued to dispatch list */
- + __le32 comp_queued;
- +
- +@@ -2719,7 +3017,7 @@ struct wal_dbg_tx_stats {
- + __le32 txop_ovf;
- + } __packed;
- +
- +-struct wal_dbg_rx_stats {
- ++struct wmi_pdev_stats_rx {
- + /* Cnts any change in ring routing mid-ppdu */
- + __le32 mid_ppdu_route_change;
- +
- +@@ -2753,20 +3051,18 @@ struct wal_dbg_rx_stats {
- + __le32 mpdu_errs;
- + } __packed;
- +
- +-struct wal_dbg_peer_stats {
- ++struct wmi_pdev_stats_peer {
- + /* REMOVE THIS ONCE REAL PEER STAT COUNTERS ARE ADDED */
- + __le32 dummy;
- + } __packed;
- +
- +-struct wal_dbg_stats {
- +- struct wal_dbg_tx_stats tx;
- +- struct wal_dbg_rx_stats rx;
- +- struct wal_dbg_peer_stats peer;
- +-} __packed;
- +-
- + enum wmi_stats_id {
- +- WMI_REQUEST_PEER_STAT = 0x01,
- +- WMI_REQUEST_AP_STAT = 0x02
- ++ WMI_STAT_PEER = BIT(0),
- ++ WMI_STAT_AP = BIT(1),
- ++ WMI_STAT_PDEV = BIT(2),
- ++ WMI_STAT_VDEV = BIT(3),
- ++ WMI_STAT_BCNFLT = BIT(4),
- ++ WMI_STAT_VDEV_RATE = BIT(5),
- + };
- +
- + struct wlan_inst_rssi_args {
- +@@ -2801,7 +3097,7 @@ struct wmi_pdev_suspend_cmd {
- + } __packed;
- +
- + struct wmi_stats_event {
- +- __le32 stats_id; /* %WMI_REQUEST_ */
- ++ __le32 stats_id; /* WMI_STAT_ */
- + /*
- + * number of pdev stats event structures
- + * (wmi_pdev_stats) 0 or 1
- +@@ -2830,30 +3126,38 @@ struct wmi_stats_event {
- + u8 data[0];
- + } __packed;
- +
- ++struct wmi_10_2_stats_event {
- ++ __le32 stats_id; /* %WMI_REQUEST_ */
- ++ __le32 num_pdev_stats;
- ++ __le32 num_pdev_ext_stats;
- ++ __le32 num_vdev_stats;
- ++ __le32 num_peer_stats;
- ++ __le32 num_bcnflt_stats;
- ++ u8 data[0];
- ++} __packed;
- ++
- + /*
- + * PDEV statistics
- + * TODO: add all PDEV stats here
- + */
- +-struct wmi_pdev_stats_old {
- +- __le32 chan_nf; /* Channel noise floor */
- +- __le32 tx_frame_count; /* TX frame count */
- +- __le32 rx_frame_count; /* RX frame count */
- +- __le32 rx_clear_count; /* rx clear count */
- +- __le32 cycle_count; /* cycle count */
- +- __le32 phy_err_count; /* Phy error count */
- +- __le32 chan_tx_pwr; /* channel tx power */
- +- struct wal_dbg_stats wal; /* WAL dbg stats */
- +-} __packed;
- +-
- +-struct wmi_pdev_stats_10x {
- +- __le32 chan_nf; /* Channel noise floor */
- +- __le32 tx_frame_count; /* TX frame count */
- +- __le32 rx_frame_count; /* RX frame count */
- +- __le32 rx_clear_count; /* rx clear count */
- +- __le32 cycle_count; /* cycle count */
- +- __le32 phy_err_count; /* Phy error count */
- +- __le32 chan_tx_pwr; /* channel tx power */
- +- struct wal_dbg_stats wal; /* WAL dbg stats */
- ++struct wmi_pdev_stats_base {
- ++ __le32 chan_nf;
- ++ __le32 tx_frame_count;
- ++ __le32 rx_frame_count;
- ++ __le32 rx_clear_count;
- ++ __le32 cycle_count;
- ++ __le32 phy_err_count;
- ++ __le32 chan_tx_pwr;
- ++} __packed;
- ++
- ++struct wmi_pdev_stats {
- ++ struct wmi_pdev_stats_base base;
- ++ struct wmi_pdev_stats_tx tx;
- ++ struct wmi_pdev_stats_rx rx;
- ++ struct wmi_pdev_stats_peer peer;
- ++} __packed;
- ++
- ++struct wmi_pdev_stats_extra {
- + __le32 ack_rx_bad;
- + __le32 rts_bad;
- + __le32 rts_good;
- +@@ -2862,6 +3166,30 @@ struct wmi_pdev_stats_10x {
- + __le32 mib_int_count;
- + } __packed;
- +
- ++struct wmi_10x_pdev_stats {
- ++ struct wmi_pdev_stats_base base;
- ++ struct wmi_pdev_stats_tx tx;
- ++ struct wmi_pdev_stats_rx rx;
- ++ struct wmi_pdev_stats_peer peer;
- ++ struct wmi_pdev_stats_extra extra;
- ++} __packed;
- ++
- ++struct wmi_pdev_stats_mem {
- ++ __le32 dram_free;
- ++ __le32 iram_free;
- ++} __packed;
- ++
- ++struct wmi_10_2_pdev_stats {
- ++ struct wmi_pdev_stats_base base;
- ++ struct wmi_pdev_stats_tx tx;
- ++ __le32 mc_drop;
- ++ struct wmi_pdev_stats_rx rx;
- ++ __le32 pdev_rx_timeout;
- ++ struct wmi_pdev_stats_mem mem;
- ++ struct wmi_pdev_stats_peer peer;
- ++ struct wmi_pdev_stats_extra extra;
- ++} __packed;
- ++
- + /*
- + * VDEV statistics
- + * TODO: add all VDEV stats here
- +@@ -2874,19 +3202,43 @@ struct wmi_vdev_stats {
- + * peer statistics.
- + * TODO: add more stats
- + */
- +-struct wmi_peer_stats_old {
- ++struct wmi_peer_stats {
- + struct wmi_mac_addr peer_macaddr;
- + __le32 peer_rssi;
- + __le32 peer_tx_rate;
- + } __packed;
- +
- +-struct wmi_peer_stats_10x {
- +- struct wmi_mac_addr peer_macaddr;
- +- __le32 peer_rssi;
- +- __le32 peer_tx_rate;
- ++struct wmi_10x_peer_stats {
- ++ struct wmi_peer_stats old;
- + __le32 peer_rx_rate;
- + } __packed;
- +
- ++struct wmi_10_2_peer_stats {
- ++ struct wmi_peer_stats old;
- ++ __le32 peer_rx_rate;
- ++ __le32 current_per;
- ++ __le32 retries;
- ++ __le32 tx_rate_count;
- ++ __le32 max_4ms_frame_len;
- ++ __le32 total_sub_frames;
- ++ __le32 tx_bytes;
- ++ __le32 num_pkt_loss_overflow[4];
- ++ __le32 num_pkt_loss_excess_retry[4];
- ++} __packed;
- ++
- ++struct wmi_10_2_4_peer_stats {
- ++ struct wmi_10_2_peer_stats common;
- ++ __le32 unknown_value; /* FIXME: what is this word? */
- ++} __packed;
- ++
- ++struct wmi_10_2_pdev_ext_stats {
- ++ __le32 rx_rssi_comb;
- ++ __le32 rx_rssi[4];
- ++ __le32 rx_mcs[10];
- ++ __le32 tx_mcs[10];
- ++ __le32 ack_rssi;
- ++} __packed;
- ++
- + struct wmi_vdev_create_cmd {
- + __le32 vdev_id;
- + __le32 vdev_type;
- +@@ -3387,8 +3739,21 @@ enum wmi_10x_vdev_param {
- + WMI_10X_VDEV_PARAM_ENABLE_RTSCTS,
- +
- + WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
- ++
- ++ /* following are available as of firmware 10.2 */
- ++ WMI_10X_VDEV_PARAM_TX_ENCAP_TYPE,
- ++ WMI_10X_VDEV_PARAM_CABQ_MAXDUR,
- ++ WMI_10X_VDEV_PARAM_MFPTEST_SET,
- ++ WMI_10X_VDEV_PARAM_RTS_FIXED_RATE,
- ++ WMI_10X_VDEV_PARAM_VHT_SGIMASK,
- ++ WMI_10X_VDEV_PARAM_VHT80_RATEMASK,
- + };
- +
- ++#define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
- ++#define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1)
- ++#define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2)
- ++#define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3)
- ++
- + /* slot time long */
- + #define WMI_VDEV_SLOT_TIME_LONG 0x1
- + /* slot time short */
- +@@ -3444,6 +3809,98 @@ struct wmi_vdev_simple_event {
- + /* unsupported VDEV combination */
- + #define WMI_INIFIED_VDEV_START_RESPONSE_NOT_SUPPORTED 0x2
- +
- ++/* TODO: please add more comments if you have in-depth information */
- ++struct wmi_vdev_spectral_conf_cmd {
- ++ __le32 vdev_id;
- ++
- ++ /* number of fft samples to send (0 for infinite) */
- ++ __le32 scan_count;
- ++ __le32 scan_period;
- ++ __le32 scan_priority;
- ++
- ++ /* number of bins in the FFT: 2^(fft_size - bin_scale) */
- ++ __le32 scan_fft_size;
- ++ __le32 scan_gc_ena;
- ++ __le32 scan_restart_ena;
- ++ __le32 scan_noise_floor_ref;
- ++ __le32 scan_init_delay;
- ++ __le32 scan_nb_tone_thr;
- ++ __le32 scan_str_bin_thr;
- ++ __le32 scan_wb_rpt_mode;
- ++ __le32 scan_rssi_rpt_mode;
- ++ __le32 scan_rssi_thr;
- ++ __le32 scan_pwr_format;
- ++
- ++ /* rpt_mode: Format of FFT report to software for spectral scan
- ++ * triggered FFTs:
- ++ * 0: No FFT report (only spectral scan summary report)
- ++ * 1: 2-dword summary of metrics for each completed FFT + spectral
- ++ * scan summary report
- ++ * 2: 2-dword summary of metrics for each completed FFT +
- ++ * 1x- oversampled bins(in-band) per FFT + spectral scan summary
- ++ * report
- ++ * 3: 2-dword summary of metrics for each completed FFT +
- ++ * 2x- oversampled bins (all) per FFT + spectral scan summary
- ++ */
- ++ __le32 scan_rpt_mode;
- ++ __le32 scan_bin_scale;
- ++ __le32 scan_dbm_adj;
- ++ __le32 scan_chn_mask;
- ++} __packed;
- ++
- ++struct wmi_vdev_spectral_conf_arg {
- ++ u32 vdev_id;
- ++ u32 scan_count;
- ++ u32 scan_period;
- ++ u32 scan_priority;
- ++ u32 scan_fft_size;
- ++ u32 scan_gc_ena;
- ++ u32 scan_restart_ena;
- ++ u32 scan_noise_floor_ref;
- ++ u32 scan_init_delay;
- ++ u32 scan_nb_tone_thr;
- ++ u32 scan_str_bin_thr;
- ++ u32 scan_wb_rpt_mode;
- ++ u32 scan_rssi_rpt_mode;
- ++ u32 scan_rssi_thr;
- ++ u32 scan_pwr_format;
- ++ u32 scan_rpt_mode;
- ++ u32 scan_bin_scale;
- ++ u32 scan_dbm_adj;
- ++ u32 scan_chn_mask;
- ++};
- ++
- ++#define WMI_SPECTRAL_ENABLE_DEFAULT 0
- ++#define WMI_SPECTRAL_COUNT_DEFAULT 0
- ++#define WMI_SPECTRAL_PERIOD_DEFAULT 35
- ++#define WMI_SPECTRAL_PRIORITY_DEFAULT 1
- ++#define WMI_SPECTRAL_FFT_SIZE_DEFAULT 7
- ++#define WMI_SPECTRAL_GC_ENA_DEFAULT 1
- ++#define WMI_SPECTRAL_RESTART_ENA_DEFAULT 0
- ++#define WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT -96
- ++#define WMI_SPECTRAL_INIT_DELAY_DEFAULT 80
- ++#define WMI_SPECTRAL_NB_TONE_THR_DEFAULT 12
- ++#define WMI_SPECTRAL_STR_BIN_THR_DEFAULT 8
- ++#define WMI_SPECTRAL_WB_RPT_MODE_DEFAULT 0
- ++#define WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT 0
- ++#define WMI_SPECTRAL_RSSI_THR_DEFAULT 0xf0
- ++#define WMI_SPECTRAL_PWR_FORMAT_DEFAULT 0
- ++#define WMI_SPECTRAL_RPT_MODE_DEFAULT 2
- ++#define WMI_SPECTRAL_BIN_SCALE_DEFAULT 1
- ++#define WMI_SPECTRAL_DBM_ADJ_DEFAULT 1
- ++#define WMI_SPECTRAL_CHN_MASK_DEFAULT 1
- ++
- ++struct wmi_vdev_spectral_enable_cmd {
- ++ __le32 vdev_id;
- ++ __le32 trigger_cmd;
- ++ __le32 enable_cmd;
- ++} __packed;
- ++
- ++#define WMI_SPECTRAL_TRIGGER_CMD_TRIGGER 1
- ++#define WMI_SPECTRAL_TRIGGER_CMD_CLEAR 2
- ++#define WMI_SPECTRAL_ENABLE_CMD_ENABLE 1
- ++#define WMI_SPECTRAL_ENABLE_CMD_DISABLE 2
- ++
- + /* Beacon processing related command and event structures */
- + struct wmi_bcn_tx_hdr {
- + __le32 vdev_id;
- +@@ -3470,6 +3927,11 @@ enum wmi_bcn_tx_ref_flags {
- + WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2,
- + };
- +
- ++/* TODO: It is unclear why "no antenna" works while any other seemingly valid
- ++ * chainmask yields no beacons on the air at all.
- ++ */
- ++#define WMI_BCN_TX_REF_DEF_ANTENNA 0
- ++
- + struct wmi_bcn_tx_ref_cmd {
- + __le32 vdev_id;
- + __le32 data_len;
- +@@ -3481,6 +3943,8 @@ struct wmi_bcn_tx_ref_cmd {
- + __le32 frame_control;
- + /* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */
- + __le32 flags;
- ++ /* introduced in 10.2 */
- ++ __le32 antenna_mask;
- + } __packed;
- +
- + /* Beacon filter */
- +@@ -3633,6 +4097,13 @@ enum wmi_sta_ps_param_pspoll_count {
- + * Values greater than 0 indicate the maximum numer of PS-Poll frames
- + * FW will send before waking up.
- + */
- ++
- ++ /* When u-APSD is enabled the firmware will be very reluctant to exit
- ++ * STA PS. This could result in very poor Rx performance with STA doing
- ++ * PS-Poll for each and every buffered frame. This value is a bit
- ++ * arbitrary.
- ++ */
- ++ WMI_STA_PS_PSPOLL_COUNT_UAPSD = 3,
- + };
- +
- + /*
- +@@ -3658,6 +4129,30 @@ enum wmi_sta_ps_param_uapsd {
- + WMI_STA_PS_UAPSD_AC3_TRIGGER_EN = (1 << 7),
- + };
- +
- ++#define WMI_STA_UAPSD_MAX_INTERVAL_MSEC UINT_MAX
- ++
- ++struct wmi_sta_uapsd_auto_trig_param {
- ++ __le32 wmm_ac;
- ++ __le32 user_priority;
- ++ __le32 service_interval;
- ++ __le32 suspend_interval;
- ++ __le32 delay_interval;
- ++};
- ++
- ++struct wmi_sta_uapsd_auto_trig_cmd_fixed_param {
- ++ __le32 vdev_id;
- ++ struct wmi_mac_addr peer_macaddr;
- ++ __le32 num_ac;
- ++};
- ++
- ++struct wmi_sta_uapsd_auto_trig_arg {
- ++ u32 wmm_ac;
- ++ u32 user_priority;
- ++ u32 service_interval;
- ++ u32 suspend_interval;
- ++ u32 delay_interval;
- ++};
- ++
- + enum wmi_sta_powersave_param {
- + /*
- + * Controls how frames are retrievd from AP while STA is sleeping
- +@@ -3823,7 +4318,7 @@ struct wmi_bcn_info {
- +
- + struct wmi_host_swba_event {
- + __le32 vdev_map;
- +- struct wmi_bcn_info bcn_info[1];
- ++ struct wmi_bcn_info bcn_info[0];
- + } __packed;
- +
- + #define WMI_MAX_AP_VDEV 16
- +@@ -3833,7 +4328,6 @@ struct wmi_tbtt_offset_event {
- + __le32 tbttoffset_list[WMI_MAX_AP_VDEV];
- + } __packed;
- +
- +-
- + struct wmi_peer_create_cmd {
- + __le32 vdev_id;
- + struct wmi_mac_addr peer_macaddr;
- +@@ -3951,7 +4445,8 @@ enum wmi_peer_param {
- + WMI_PEER_AUTHORIZE = 0x3,
- + WMI_PEER_CHAN_WIDTH = 0x4,
- + WMI_PEER_NSS = 0x5,
- +- WMI_PEER_USE_4ADDR = 0x6
- ++ WMI_PEER_USE_4ADDR = 0x6,
- ++ WMI_PEER_DUMMY_VAR = 0xff, /* dummy parameter for STA PS workaround */
- + };
- +
- + struct wmi_peer_set_param_cmd {
- +@@ -4029,7 +4524,7 @@ struct wmi_peer_set_q_empty_callback_cmd
- + #define WMI_PEER_SPATIAL_MUX 0x00200000
- + #define WMI_PEER_VHT 0x02000000
- + #define WMI_PEER_80MHZ 0x04000000
- +-#define WMI_PEER_PMF 0x08000000
- ++#define WMI_PEER_VHT_2G 0x08000000
- +
- + /*
- + * Peer rate capabilities.
- +@@ -4053,7 +4548,7 @@ struct wmi_peer_set_q_empty_callback_cmd
- + /* Maximum listen interval supported by hw in units of beacon interval */
- + #define ATH10K_MAX_HW_LISTEN_INTERVAL 5
- +
- +-struct wmi_peer_assoc_complete_cmd {
- ++struct wmi_common_peer_assoc_complete_cmd {
- + struct wmi_mac_addr peer_macaddr;
- + __le32 vdev_id;
- + __le32 peer_new_assoc; /* 1=assoc, 0=reassoc */
- +@@ -4071,11 +4566,30 @@ struct wmi_peer_assoc_complete_cmd {
- + __le32 peer_vht_caps;
- + __le32 peer_phymode;
- + struct wmi_vht_rate_set peer_vht_rates;
- ++};
- ++
- ++struct wmi_main_peer_assoc_complete_cmd {
- ++ struct wmi_common_peer_assoc_complete_cmd cmd;
- ++
- + /* HT Operation Element of the peer. Five bytes packed in 2
- + * INT32 array and filled from lsb to msb. */
- + __le32 peer_ht_info[2];
- + } __packed;
- +
- ++struct wmi_10_1_peer_assoc_complete_cmd {
- ++ struct wmi_common_peer_assoc_complete_cmd cmd;
- ++} __packed;
- ++
- ++#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_LSB 0
- ++#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_MASK 0x0f
- ++#define WMI_PEER_ASSOC_INFO0_MAX_NSS_LSB 4
- ++#define WMI_PEER_ASSOC_INFO0_MAX_NSS_MASK 0xf0
- ++
- ++struct wmi_10_2_peer_assoc_complete_cmd {
- ++ struct wmi_common_peer_assoc_complete_cmd cmd;
- ++ __le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
- ++} __packed;
- ++
- + struct wmi_peer_assoc_complete_arg {
- + u8 addr[ETH_ALEN];
- + u32 vdev_id;
- +@@ -4161,6 +4675,11 @@ enum wmi_sta_keepalive_method {
- + WMI_STA_KEEPALIVE_METHOD_UNSOLICITATED_ARP_RESPONSE = 2,
- + };
- +
- ++#define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0
- ++
- ++/* Firmware crashes if keepalive interval exceeds this limit */
- ++#define WMI_STA_KEEPALIVE_INTERVAL_MAX_SECONDS 0xffff
- ++
- + /* note: ip4 addresses are in network byte order, i.e. big endian */
- + struct wmi_sta_keepalive_arp_resp {
- + __be32 src_ip4_addr;
- +@@ -4176,6 +4695,16 @@ struct wmi_sta_keepalive_cmd {
- + struct wmi_sta_keepalive_arp_resp arp_resp;
- + } __packed;
- +
- ++struct wmi_sta_keepalive_arg {
- ++ u32 vdev_id;
- ++ u32 enabled;
- ++ u32 method;
- ++ u32 interval;
- ++ __be32 src_ip4_addr;
- ++ __be32 dest_ip4_addr;
- ++ const u8 dest_mac_addr[ETH_ALEN];
- ++};
- ++
- + enum wmi_force_fw_hang_type {
- + WMI_FORCE_FW_HANG_ASSERT = 1,
- + WMI_FORCE_FW_HANG_NO_DETECT,
- +@@ -4240,7 +4769,6 @@ struct wmi_dbglog_cfg_cmd {
- + __le32 config_valid;
- + } __packed;
- +
- +-#define ATH10K_RTS_MAX 2347
- + #define ATH10K_FRAGMT_THRESHOLD_MIN 540
- + #define ATH10K_FRAGMT_THRESHOLD_MAX 2346
- +
- +@@ -4251,72 +4779,170 @@ struct wmi_dbglog_cfg_cmd {
- + /* By default disable power save for IBSS */
- + #define ATH10K_DEFAULT_ATIM 0
- +
- ++#define WMI_MAX_MEM_REQS 16
- ++
- ++struct wmi_scan_ev_arg {
- ++ __le32 event_type; /* %WMI_SCAN_EVENT_ */
- ++ __le32 reason; /* %WMI_SCAN_REASON_ */
- ++ __le32 channel_freq; /* only valid for WMI_SCAN_EVENT_FOREIGN_CHANNEL */
- ++ __le32 scan_req_id;
- ++ __le32 scan_id;
- ++ __le32 vdev_id;
- ++};
- ++
- ++struct wmi_mgmt_rx_ev_arg {
- ++ __le32 channel;
- ++ __le32 snr;
- ++ __le32 rate;
- ++ __le32 phy_mode;
- ++ __le32 buf_len;
- ++ __le32 status; /* %WMI_RX_STATUS_ */
- ++};
- ++
- ++struct wmi_ch_info_ev_arg {
- ++ __le32 err_code;
- ++ __le32 freq;
- ++ __le32 cmd_flags;
- ++ __le32 noise_floor;
- ++ __le32 rx_clear_count;
- ++ __le32 cycle_count;
- ++};
- ++
- ++struct wmi_vdev_start_ev_arg {
- ++ __le32 vdev_id;
- ++ __le32 req_id;
- ++ __le32 resp_type; /* %WMI_VDEV_RESP_ */
- ++ __le32 status;
- ++};
- ++
- ++struct wmi_peer_kick_ev_arg {
- ++ const u8 *mac_addr;
- ++};
- ++
- ++struct wmi_swba_ev_arg {
- ++ __le32 vdev_map;
- ++ const struct wmi_tim_info *tim_info[WMI_MAX_AP_VDEV];
- ++ const struct wmi_p2p_noa_info *noa_info[WMI_MAX_AP_VDEV];
- ++};
- ++
- ++struct wmi_phyerr_ev_arg {
- ++ __le32 num_phyerrs;
- ++ __le32 tsf_l32;
- ++ __le32 tsf_u32;
- ++ __le32 buf_len;
- ++ const struct wmi_phyerr *phyerrs;
- ++};
- ++
- ++struct wmi_svc_rdy_ev_arg {
- ++ __le32 min_tx_power;
- ++ __le32 max_tx_power;
- ++ __le32 ht_cap;
- ++ __le32 vht_cap;
- ++ __le32 sw_ver0;
- ++ __le32 sw_ver1;
- ++ __le32 fw_build;
- ++ __le32 phy_capab;
- ++ __le32 num_rf_chains;
- ++ __le32 eeprom_rd;
- ++ __le32 num_mem_reqs;
- ++ const __le32 *service_map;
- ++ size_t service_map_len;
- ++ const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];
- ++};
- ++
- ++struct wmi_rdy_ev_arg {
- ++ __le32 sw_version;
- ++ __le32 abi_version;
- ++ __le32 status;
- ++ const u8 *mac_addr;
- ++};
- ++
- ++struct wmi_pdev_temperature_event {
- ++ /* temperature value in Celcius degree */
- ++ __le32 temperature;
- ++} __packed;
- ++
- + struct ath10k;
- + struct ath10k_vif;
- ++struct ath10k_fw_stats_pdev;
- ++struct ath10k_fw_stats_peer;
- +
- + int ath10k_wmi_attach(struct ath10k *ar);
- + void ath10k_wmi_detach(struct ath10k *ar);
- + int ath10k_wmi_wait_for_service_ready(struct ath10k *ar);
- + int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
- +
- +-int ath10k_wmi_connect_htc_service(struct ath10k *ar);
- +-int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
- +- const struct wmi_channel_arg *);
- +-int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
- +-int ath10k_wmi_pdev_resume_target(struct ath10k *ar);
- +-int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
- +- u16 rd5g, u16 ctl2g, u16 ctl5g,
- +- enum wmi_dfs_region dfs_reg);
- +-int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value);
- +-int ath10k_wmi_cmd_init(struct ath10k *ar);
- +-int ath10k_wmi_start_scan(struct ath10k *ar, const struct wmi_start_scan_arg *);
- ++struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
- ++int ath10k_wmi_connect(struct ath10k *ar);
- ++
- ++struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
- ++int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
- ++int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
- ++ u32 cmd_id);
- + void ath10k_wmi_start_scan_init(struct ath10k *ar, struct wmi_start_scan_arg *);
- +-int ath10k_wmi_stop_scan(struct ath10k *ar,
- +- const struct wmi_stop_scan_arg *arg);
- +-int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
- +- enum wmi_vdev_type type,
- +- enum wmi_vdev_subtype subtype,
- +- const u8 macaddr[ETH_ALEN]);
- +-int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id);
- +-int ath10k_wmi_vdev_start(struct ath10k *ar,
- +- const struct wmi_vdev_start_request_arg *);
- +-int ath10k_wmi_vdev_restart(struct ath10k *ar,
- +- const struct wmi_vdev_start_request_arg *);
- +-int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id);
- +-int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid,
- +- const u8 *bssid);
- +-int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id);
- +-int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
- +- u32 param_id, u32 param_value);
- +-int ath10k_wmi_vdev_install_key(struct ath10k *ar,
- +- const struct wmi_vdev_install_key_arg *arg);
- +-int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
- +- const u8 peer_addr[ETH_ALEN]);
- +-int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
- +- const u8 peer_addr[ETH_ALEN]);
- +-int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
- +- const u8 peer_addr[ETH_ALEN], u32 tid_bitmap);
- +-int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
- +- const u8 *peer_addr,
- +- enum wmi_peer_param param_id, u32 param_value);
- +-int ath10k_wmi_peer_assoc(struct ath10k *ar,
- +- const struct wmi_peer_assoc_complete_arg *arg);
- +-int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
- +- enum wmi_sta_ps_mode psmode);
- +-int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
- +- enum wmi_sta_powersave_param param_id,
- +- u32 value);
- +-int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
- +- enum wmi_ap_ps_peer_param param_id, u32 value);
- +-int ath10k_wmi_scan_chan_list(struct ath10k *ar,
- +- const struct wmi_scan_chan_list_arg *arg);
- +-int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif);
- +-int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
- +- const struct wmi_pdev_set_wmm_params_arg *arg);
- +-int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);
- +-int ath10k_wmi_force_fw_hang(struct ath10k *ar,
- +- enum wmi_force_fw_hang_type type, u32 delay_ms);
- +-int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb);
- +-int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable);
- ++
- ++void ath10k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src,
- ++ struct ath10k_fw_stats_pdev *dst);
- ++void ath10k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src,
- ++ struct ath10k_fw_stats_pdev *dst);
- ++void ath10k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src,
- ++ struct ath10k_fw_stats_pdev *dst);
- ++void ath10k_wmi_pull_pdev_stats_extra(const struct wmi_pdev_stats_extra *src,
- ++ struct ath10k_fw_stats_pdev *dst);
- ++void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src,
- ++ struct ath10k_fw_stats_peer *dst);
- ++void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
- ++ struct wmi_host_mem_chunks *chunks);
- ++void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn,
- ++ const struct wmi_start_scan_arg *arg);
- ++void ath10k_wmi_set_wmm_param(struct wmi_wmm_params *params,
- ++ const struct wmi_wmm_params_arg *arg);
- ++void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
- ++ const struct wmi_channel_arg *arg);
- ++int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg);
- ++
- ++int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb);
- ++int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb);
- ++int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_dfs(struct ath10k *ar,
- ++ const struct wmi_phyerr *phyerr, u64 tsf);
- ++void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
- ++ const struct wmi_phyerr *phyerr,
- ++ u64 tsf);
- ++void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar,
- ++ struct sk_buff *skb);
- ++void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar,
- ++ struct sk_buff *skb);
- ++void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar,
- ++ struct sk_buff *skb);
- ++void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_delba_complete(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_addba_complete(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
- ++ struct sk_buff *skb);
- ++void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb);
- ++void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb);
- ++int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb);
- +
- + #endif /* _WMI_H_ */
- +--- /dev/null
- ++++ b/drivers/net/wireless/ath/ath10k/spectral.c
- +@@ -0,0 +1,552 @@
- ++/*
- ++ * Copyright (c) 2013 Qualcomm Atheros, Inc.
- ++ *
- ++ * Permission to use, copy, modify, and/or distribute this software for any
- ++ * purpose with or without fee is hereby granted, provided that the above
- ++ * copyright notice and this permission notice appear in all copies.
- ++ *
- ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ++ */
- ++
- ++#include <linux/relay.h>
- ++#include "core.h"
- ++#include "debug.h"
- ++#include "wmi-ops.h"
- ++
- ++static void send_fft_sample(struct ath10k *ar,
- ++ const struct fft_sample_tlv *fft_sample_tlv)
- ++{
- ++ int length;
- ++
- ++ if (!ar->spectral.rfs_chan_spec_scan)
- ++ return;
- ++
- ++ length = __be16_to_cpu(fft_sample_tlv->length) +
- ++ sizeof(*fft_sample_tlv);
- ++ relay_write(ar->spectral.rfs_chan_spec_scan, fft_sample_tlv, length);
- ++}
- ++
- ++static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len,
- ++ u8 *data)
- ++{
- ++ int dc_pos;
- ++ u8 max_exp;
- ++
- ++ dc_pos = bin_len / 2;
- ++
- ++ /* peak index outside of bins */
- ++ if (dc_pos < max_index || -dc_pos >= max_index)
- ++ return 0;
- ++
- ++ for (max_exp = 0; max_exp < 8; max_exp++) {
- ++ if (data[dc_pos + max_index] == (max_magnitude >> max_exp))
- ++ break;
- ++ }
- ++
- ++ /* max_exp not found */
- ++ if (data[dc_pos + max_index] != (max_magnitude >> max_exp))
- ++ return 0;
- ++
- ++ return max_exp;
- ++}
- ++
- ++int ath10k_spectral_process_fft(struct ath10k *ar,
- ++ const struct wmi_phyerr *phyerr,
- ++ const struct phyerr_fft_report *fftr,
- ++ size_t bin_len, u64 tsf)
- ++{
- ++ struct fft_sample_ath10k *fft_sample;
- ++ u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS];
- ++ u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag;
- ++ u32 reg0, reg1;
- ++ u8 chain_idx, *bins;
- ++ int dc_pos;
- ++
- ++ fft_sample = (struct fft_sample_ath10k *)&buf;
- ++
- ++ if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS)
- ++ return -EINVAL;
- ++
- ++ reg0 = __le32_to_cpu(fftr->reg0);
- ++ reg1 = __le32_to_cpu(fftr->reg1);
- ++
- ++ length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + bin_len;
- ++ fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH10K;
- ++ fft_sample->tlv.length = __cpu_to_be16(length);
- ++
- ++ /* TODO: there might be a reason why the hardware reports 20/40/80 MHz,
- ++ * but the results/plots suggest that its actually 22/44/88 MHz.
- ++ */
- ++ switch (phyerr->chan_width_mhz) {
- ++ case 20:
- ++ fft_sample->chan_width_mhz = 22;
- ++ break;
- ++ case 40:
- ++ fft_sample->chan_width_mhz = 44;
- ++ break;
- ++ case 80:
- ++ /* TODO: As experiments with an analogue sender and various
- ++ * configuaritions (fft-sizes of 64/128/256 and 20/40/80 Mhz)
- ++ * show, the particular configuration of 80 MHz/64 bins does
- ++ * not match with the other smaples at all. Until the reason
- ++ * for that is found, don't report these samples.
- ++ */
- ++ if (bin_len == 64)
- ++ return -EINVAL;
- ++ fft_sample->chan_width_mhz = 88;
- ++ break;
- ++ default:
- ++ fft_sample->chan_width_mhz = phyerr->chan_width_mhz;
- ++ }
- ++
- ++ fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB);
- ++ fft_sample->avgpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB);
- ++
- ++ peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
- ++ fft_sample->max_magnitude = __cpu_to_be16(peak_mag);
- ++ fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX);
- ++ fft_sample->rssi = phyerr->rssi_combined;
- ++
- ++ total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB);
- ++ base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB);
- ++ fft_sample->total_gain_db = __cpu_to_be16(total_gain_db);
- ++ fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db);
- ++
- ++ freq1 = __le16_to_cpu(phyerr->freq1);
- ++ freq2 = __le16_to_cpu(phyerr->freq2);
- ++ fft_sample->freq1 = __cpu_to_be16(freq1);
- ++ fft_sample->freq2 = __cpu_to_be16(freq2);
- ++
- ++ chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX);
- ++
- ++ fft_sample->noise = __cpu_to_be16(
- ++ __le16_to_cpu(phyerr->nf_chains[chain_idx]));
- ++
- ++ bins = (u8 *)fftr;
- ++ bins += sizeof(*fftr);
- ++
- ++ fft_sample->tsf = __cpu_to_be64(tsf);
- ++
- ++ /* max_exp has been directly reported by previous hardware (ath9k),
- ++ * maybe its possible to get it by other means?
- ++ */
- ++ fft_sample->max_exp = get_max_exp(fft_sample->max_index, peak_mag,
- ++ bin_len, bins);
- ++
- ++ memcpy(fft_sample->data, bins, bin_len);
- ++
- ++ /* DC value (value in the middle) is the blind spot of the spectral
- ++ * sample and invalid, interpolate it.
- ++ */
- ++ dc_pos = bin_len / 2;
- ++ fft_sample->data[dc_pos] = (fft_sample->data[dc_pos + 1] +
- ++ fft_sample->data[dc_pos - 1]) / 2;
- ++
- ++ send_fft_sample(ar, &fft_sample->tlv);
- ++
- ++ return 0;
- ++}
- ++
- ++static struct ath10k_vif *ath10k_get_spectral_vdev(struct ath10k *ar)
- ++{
- ++ struct ath10k_vif *arvif;
- ++
- ++ lockdep_assert_held(&ar->conf_mutex);
- ++
- ++ if (list_empty(&ar->arvifs))
- ++ return NULL;
- ++
- ++ /* if there already is a vif doing spectral, return that. */
- ++ list_for_each_entry(arvif, &ar->arvifs, list)
- ++ if (arvif->spectral_enabled)
- ++ return arvif;
- ++
- ++ /* otherwise, return the first vif. */
- ++ return list_first_entry(&ar->arvifs, typeof(*arvif), list);
- ++}
- ++
- ++static int ath10k_spectral_scan_trigger(struct ath10k *ar)
- ++{
- ++ struct ath10k_vif *arvif;
- ++ int res;
- ++ int vdev_id;
- ++
- ++ lockdep_assert_held(&ar->conf_mutex);
- ++
- ++ arvif = ath10k_get_spectral_vdev(ar);
- ++ if (!arvif)
- ++ return -ENODEV;
- ++ vdev_id = arvif->vdev_id;
- ++
- ++ if (ar->spectral.mode == SPECTRAL_DISABLED)
- ++ return 0;
- ++
- ++ res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
- ++ WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
- ++ WMI_SPECTRAL_ENABLE_CMD_ENABLE);
- ++ if (res < 0)
- ++ return res;
- ++
- ++ res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
- ++ WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
- ++ WMI_SPECTRAL_ENABLE_CMD_ENABLE);
- ++ if (res < 0)
- ++ return res;
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_spectral_scan_config(struct ath10k *ar,
- ++ enum ath10k_spectral_mode mode)
- ++{
- ++ struct wmi_vdev_spectral_conf_arg arg;
- ++ struct ath10k_vif *arvif;
- ++ int vdev_id, count, res = 0;
- ++
- ++ lockdep_assert_held(&ar->conf_mutex);
- ++
- ++ arvif = ath10k_get_spectral_vdev(ar);
- ++ if (!arvif)
- ++ return -ENODEV;
- ++
- ++ vdev_id = arvif->vdev_id;
- ++
- ++ arvif->spectral_enabled = (mode != SPECTRAL_DISABLED);
- ++ ar->spectral.mode = mode;
- ++
- ++ res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
- ++ WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
- ++ WMI_SPECTRAL_ENABLE_CMD_DISABLE);
- ++ if (res < 0) {
- ++ ath10k_warn(ar, "failed to enable spectral scan: %d\n", res);
- ++ return res;
- ++ }
- ++
- ++ if (mode == SPECTRAL_DISABLED)
- ++ return 0;
- ++
- ++ if (mode == SPECTRAL_BACKGROUND)
- ++ count = WMI_SPECTRAL_COUNT_DEFAULT;
- ++ else
- ++ count = max_t(u8, 1, ar->spectral.config.count);
- ++
- ++ arg.vdev_id = vdev_id;
- ++ arg.scan_count = count;
- ++ arg.scan_period = WMI_SPECTRAL_PERIOD_DEFAULT;
- ++ arg.scan_priority = WMI_SPECTRAL_PRIORITY_DEFAULT;
- ++ arg.scan_fft_size = ar->spectral.config.fft_size;
- ++ arg.scan_gc_ena = WMI_SPECTRAL_GC_ENA_DEFAULT;
- ++ arg.scan_restart_ena = WMI_SPECTRAL_RESTART_ENA_DEFAULT;
- ++ arg.scan_noise_floor_ref = WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
- ++ arg.scan_init_delay = WMI_SPECTRAL_INIT_DELAY_DEFAULT;
- ++ arg.scan_nb_tone_thr = WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
- ++ arg.scan_str_bin_thr = WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
- ++ arg.scan_wb_rpt_mode = WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
- ++ arg.scan_rssi_rpt_mode = WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
- ++ arg.scan_rssi_thr = WMI_SPECTRAL_RSSI_THR_DEFAULT;
- ++ arg.scan_pwr_format = WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
- ++ arg.scan_rpt_mode = WMI_SPECTRAL_RPT_MODE_DEFAULT;
- ++ arg.scan_bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
- ++ arg.scan_dbm_adj = WMI_SPECTRAL_DBM_ADJ_DEFAULT;
- ++ arg.scan_chn_mask = WMI_SPECTRAL_CHN_MASK_DEFAULT;
- ++
- ++ res = ath10k_wmi_vdev_spectral_conf(ar, &arg);
- ++ if (res < 0) {
- ++ ath10k_warn(ar, "failed to configure spectral scan: %d\n", res);
- ++ return res;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- ++static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ char *mode = "";
- ++ unsigned int len;
- ++ enum ath10k_spectral_mode spectral_mode;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ spectral_mode = ar->spectral.mode;
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ switch (spectral_mode) {
- ++ case SPECTRAL_DISABLED:
- ++ mode = "disable";
- ++ break;
- ++ case SPECTRAL_BACKGROUND:
- ++ mode = "background";
- ++ break;
- ++ case SPECTRAL_MANUAL:
- ++ mode = "manual";
- ++ break;
- ++ }
- ++
- ++ len = strlen(mode);
- ++ return simple_read_from_buffer(user_buf, count, ppos, mode, len);
- ++}
- ++
- ++static ssize_t write_file_spec_scan_ctl(struct file *file,
- ++ const char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ char buf[32];
- ++ ssize_t len;
- ++ int res;
- ++
- ++ len = min(count, sizeof(buf) - 1);
- ++ if (copy_from_user(buf, user_buf, len))
- ++ return -EFAULT;
- ++
- ++ buf[len] = '\0';
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ if (strncmp("trigger", buf, 7) == 0) {
- ++ if (ar->spectral.mode == SPECTRAL_MANUAL ||
- ++ ar->spectral.mode == SPECTRAL_BACKGROUND) {
- ++ /* reset the configuration to adopt possibly changed
- ++ * debugfs parameters
- ++ */
- ++ res = ath10k_spectral_scan_config(ar,
- ++ ar->spectral.mode);
- ++ if (res < 0) {
- ++ ath10k_warn(ar, "failed to reconfigure spectral scan: %d\n",
- ++ res);
- ++ }
- ++ res = ath10k_spectral_scan_trigger(ar);
- ++ if (res < 0) {
- ++ ath10k_warn(ar, "failed to trigger spectral scan: %d\n",
- ++ res);
- ++ }
- ++ } else {
- ++ res = -EINVAL;
- ++ }
- ++ } else if (strncmp("background", buf, 9) == 0) {
- ++ res = ath10k_spectral_scan_config(ar, SPECTRAL_BACKGROUND);
- ++ } else if (strncmp("manual", buf, 6) == 0) {
- ++ res = ath10k_spectral_scan_config(ar, SPECTRAL_MANUAL);
- ++ } else if (strncmp("disable", buf, 7) == 0) {
- ++ res = ath10k_spectral_scan_config(ar, SPECTRAL_DISABLED);
- ++ } else {
- ++ res = -EINVAL;
- ++ }
- ++
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ if (res < 0)
- ++ return res;
- ++
- ++ return count;
- ++}
- ++
- ++static const struct file_operations fops_spec_scan_ctl = {
- ++ .read = read_file_spec_scan_ctl,
- ++ .write = write_file_spec_scan_ctl,
- ++ .open = simple_open,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- ++static ssize_t read_file_spectral_count(struct file *file,
- ++ char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ char buf[32];
- ++ unsigned int len;
- ++ u8 spectral_count;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ spectral_count = ar->spectral.config.count;
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ len = sprintf(buf, "%d\n", spectral_count);
- ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
- ++}
- ++
- ++static ssize_t write_file_spectral_count(struct file *file,
- ++ const char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ unsigned long val;
- ++ char buf[32];
- ++ ssize_t len;
- ++
- ++ len = min(count, sizeof(buf) - 1);
- ++ if (copy_from_user(buf, user_buf, len))
- ++ return -EFAULT;
- ++
- ++ buf[len] = '\0';
- ++ if (kstrtoul(buf, 0, &val))
- ++ return -EINVAL;
- ++
- ++ if (val < 0 || val > 255)
- ++ return -EINVAL;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ ar->spectral.config.count = val;
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return count;
- ++}
- ++
- ++static const struct file_operations fops_spectral_count = {
- ++ .read = read_file_spectral_count,
- ++ .write = write_file_spectral_count,
- ++ .open = simple_open,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- ++static ssize_t read_file_spectral_bins(struct file *file,
- ++ char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ char buf[32];
- ++ unsigned int len, bins, fft_size, bin_scale;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ fft_size = ar->spectral.config.fft_size;
- ++ bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
- ++ bins = 1 << (fft_size - bin_scale);
- ++
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ len = sprintf(buf, "%d\n", bins);
- ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
- ++}
- ++
- ++static ssize_t write_file_spectral_bins(struct file *file,
- ++ const char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ath10k *ar = file->private_data;
- ++ unsigned long val;
- ++ char buf[32];
- ++ ssize_t len;
- ++
- ++ len = min(count, sizeof(buf) - 1);
- ++ if (copy_from_user(buf, user_buf, len))
- ++ return -EFAULT;
- ++
- ++ buf[len] = '\0';
- ++ if (kstrtoul(buf, 0, &val))
- ++ return -EINVAL;
- ++
- ++ if (val < 64 || val > SPECTRAL_ATH10K_MAX_NUM_BINS)
- ++ return -EINVAL;
- ++
- ++ if (!is_power_of_2(val))
- ++ return -EINVAL;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ ar->spectral.config.fft_size = ilog2(val);
- ++ ar->spectral.config.fft_size += WMI_SPECTRAL_BIN_SCALE_DEFAULT;
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return count;
- ++}
- ++
- ++static const struct file_operations fops_spectral_bins = {
- ++ .read = read_file_spectral_bins,
- ++ .write = write_file_spectral_bins,
- ++ .open = simple_open,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- ++static struct dentry *create_buf_file_handler(const char *filename,
- ++ struct dentry *parent,
- ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0))
- ++ umode_t mode,
- ++#else
- ++ int mode,
- ++#endif
- ++ struct rchan_buf *buf,
- ++ int *is_global)
- ++{
- ++ struct dentry *buf_file;
- ++
- ++ buf_file = debugfs_create_file(filename, mode, parent, buf,
- ++ &relay_file_operations);
- ++ *is_global = 1;
- ++ return buf_file;
- ++}
- ++
- ++static int remove_buf_file_handler(struct dentry *dentry)
- ++{
- ++ debugfs_remove(dentry);
- ++
- ++ return 0;
- ++}
- ++
- ++static struct rchan_callbacks rfs_spec_scan_cb = {
- ++ .create_buf_file = create_buf_file_handler,
- ++ .remove_buf_file = remove_buf_file_handler,
- ++};
- ++
- ++int ath10k_spectral_start(struct ath10k *ar)
- ++{
- ++ struct ath10k_vif *arvif;
- ++
- ++ lockdep_assert_held(&ar->conf_mutex);
- ++
- ++ list_for_each_entry(arvif, &ar->arvifs, list)
- ++ arvif->spectral_enabled = 0;
- ++
- ++ ar->spectral.mode = SPECTRAL_DISABLED;
- ++ ar->spectral.config.count = WMI_SPECTRAL_COUNT_DEFAULT;
- ++ ar->spectral.config.fft_size = WMI_SPECTRAL_FFT_SIZE_DEFAULT;
- ++
- ++ return 0;
- ++}
- ++
- ++int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
- ++{
- ++ if (!arvif->spectral_enabled)
- ++ return 0;
- ++
- ++ return ath10k_spectral_scan_config(arvif->ar, SPECTRAL_DISABLED);
- ++}
- ++
- ++int ath10k_spectral_create(struct ath10k *ar)
- ++{
- ++ ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan",
- ++ ar->debug.debugfs_phy,
- ++ 1024, 256,
- ++ &rfs_spec_scan_cb, NULL);
- ++ debugfs_create_file("spectral_scan_ctl",
- ++ S_IRUSR | S_IWUSR,
- ++ ar->debug.debugfs_phy, ar,
- ++ &fops_spec_scan_ctl);
- ++ debugfs_create_file("spectral_count",
- ++ S_IRUSR | S_IWUSR,
- ++ ar->debug.debugfs_phy, ar,
- ++ &fops_spectral_count);
- ++ debugfs_create_file("spectral_bins",
- ++ S_IRUSR | S_IWUSR,
- ++ ar->debug.debugfs_phy, ar,
- ++ &fops_spectral_bins);
- ++
- ++ return 0;
- ++}
- ++
- ++void ath10k_spectral_destroy(struct ath10k *ar)
- ++{
- ++ if (ar->spectral.rfs_chan_spec_scan) {
- ++ relay_close(ar->spectral.rfs_chan_spec_scan);
- ++ ar->spectral.rfs_chan_spec_scan = NULL;
- ++ }
- ++}
- +--- /dev/null
- ++++ b/drivers/net/wireless/ath/ath10k/spectral.h
- +@@ -0,0 +1,90 @@
- ++/*
- ++ * Copyright (c) 2013 Qualcomm Atheros, Inc.
- ++ *
- ++ * Permission to use, copy, modify, and/or distribute this software for any
- ++ * purpose with or without fee is hereby granted, provided that the above
- ++ * copyright notice and this permission notice appear in all copies.
- ++ *
- ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ++ */
- ++
- ++#ifndef SPECTRAL_H
- ++#define SPECTRAL_H
- ++
- ++#include "../spectral_common.h"
- ++
- ++/**
- ++ * struct ath10k_spec_scan - parameters for Atheros spectral scan
- ++ *
- ++ * @count: number of scan results requested for manual mode
- ++ * @fft_size: number of bins to be requested = 2^(fft_size - bin_scale)
- ++ */
- ++struct ath10k_spec_scan {
- ++ u8 count;
- ++ u8 fft_size;
- ++};
- ++
- ++/* enum ath10k_spectral_mode:
- ++ *
- ++ * @SPECTRAL_DISABLED: spectral mode is disabled
- ++ * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
- ++ * something else.
- ++ * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
- ++ * is performed manually.
- ++ */
- ++enum ath10k_spectral_mode {
- ++ SPECTRAL_DISABLED = 0,
- ++ SPECTRAL_BACKGROUND,
- ++ SPECTRAL_MANUAL,
- ++};
- ++
- ++#ifdef CPTCFG_ATH10K_DEBUGFS
- ++
- ++int ath10k_spectral_process_fft(struct ath10k *ar,
- ++ const struct wmi_phyerr *phyerr,
- ++ const struct phyerr_fft_report *fftr,
- ++ size_t bin_len, u64 tsf);
- ++int ath10k_spectral_start(struct ath10k *ar);
- ++int ath10k_spectral_vif_stop(struct ath10k_vif *arvif);
- ++int ath10k_spectral_create(struct ath10k *ar);
- ++void ath10k_spectral_destroy(struct ath10k *ar);
- ++
- ++#else
- ++
- ++static inline int
- ++ath10k_spectral_process_fft(struct ath10k *ar,
- ++ const struct wmi_phyerr *phyerr,
- ++ const struct phyerr_fft_report *fftr,
- ++ size_t bin_len, u64 tsf)
- ++{
- ++ return 0;
- ++}
- ++
- ++static inline int ath10k_spectral_start(struct ath10k *ar)
- ++{
- ++ return 0;
- ++}
- ++
- ++static inline int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
- ++{
- ++ return 0;
- ++}
- ++
- ++static inline int ath10k_spectral_create(struct ath10k *ar)
- ++{
- ++ return 0;
- ++}
- ++
- ++static inline void ath10k_spectral_destroy(struct ath10k *ar)
- ++{
- ++}
- ++
- ++#endif /* CPTCFG_ATH10K_DEBUGFS */
- ++
- ++#endif /* SPECTRAL_H */
- +--- /dev/null
- ++++ b/drivers/net/wireless/ath/ath10k/testmode.c
- +@@ -0,0 +1,385 @@
- ++/*
- ++ * Copyright (c) 2014 Qualcomm Atheros, Inc.
- ++ *
- ++ * Permission to use, copy, modify, and/or distribute this software for any
- ++ * purpose with or without fee is hereby granted, provided that the above
- ++ * copyright notice and this permission notice appear in all copies.
- ++ *
- ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ++ */
- ++
- ++#include "testmode.h"
- ++
- ++#include <net/netlink.h>
- ++#include <linux/firmware.h>
- ++
- ++#include "debug.h"
- ++#include "wmi.h"
- ++#include "hif.h"
- ++#include "hw.h"
- ++
- ++#include "testmode_i.h"
- ++
- ++static const struct nla_policy ath10k_tm_policy[ATH10K_TM_ATTR_MAX + 1] = {
- ++ [ATH10K_TM_ATTR_CMD] = { .type = NLA_U32 },
- ++ [ATH10K_TM_ATTR_DATA] = { .type = NLA_BINARY,
- ++ .len = ATH10K_TM_DATA_MAX_LEN },
- ++ [ATH10K_TM_ATTR_WMI_CMDID] = { .type = NLA_U32 },
- ++ [ATH10K_TM_ATTR_VERSION_MAJOR] = { .type = NLA_U32 },
- ++ [ATH10K_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 },
- ++};
- ++
- ++/* Returns true if callee consumes the skb and the skb should be discarded.
- ++ * Returns false if skb is not used. Does not sleep.
- ++ */
- ++bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb)
- ++{
- ++ struct sk_buff *nl_skb;
- ++ bool consumed;
- ++ int ret;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
- ++ "testmode event wmi cmd_id %d skb %p skb->len %d\n",
- ++ cmd_id, skb, skb->len);
- ++
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++
- ++ if (!ar->testmode.utf_monitor) {
- ++ consumed = false;
- ++ goto out;
- ++ }
- ++
- ++ /* Only testmode.c should be handling events from utf firmware,
- ++ * otherwise all sort of problems will arise as mac80211 operations
- ++ * are not initialised.
- ++ */
- ++ consumed = true;
- ++
- ++ nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
- ++ 2 * sizeof(u32) + skb->len,
- ++ GFP_ATOMIC);
- ++ if (!nl_skb) {
- ++ ath10k_warn(ar,
- ++ "failed to allocate skb for testmode wmi event\n");
- ++ goto out;
- ++ }
- ++
- ++ ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_CMD, ATH10K_TM_CMD_WMI);
- ++ if (ret) {
- ++ ath10k_warn(ar,
- ++ "failed to to put testmode wmi event cmd attribute: %d\n",
- ++ ret);
- ++ kfree_skb(nl_skb);
- ++ goto out;
- ++ }
- ++
- ++ ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_WMI_CMDID, cmd_id);
- ++ if (ret) {
- ++ ath10k_warn(ar,
- ++ "failed to to put testmode wmi even cmd_id: %d\n",
- ++ ret);
- ++ kfree_skb(nl_skb);
- ++ goto out;
- ++ }
- ++
- ++ ret = nla_put(nl_skb, ATH10K_TM_ATTR_DATA, skb->len, skb->data);
- ++ if (ret) {
- ++ ath10k_warn(ar,
- ++ "failed to copy skb to testmode wmi event: %d\n",
- ++ ret);
- ++ kfree_skb(nl_skb);
- ++ goto out;
- ++ }
- ++
- ++ cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
- ++
- ++out:
- ++ spin_unlock_bh(&ar->data_lock);
- ++
- ++ return consumed;
- ++}
- ++
- ++static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])
- ++{
- ++ struct sk_buff *skb;
- ++ int ret;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
- ++ "testmode cmd get version_major %d version_minor %d\n",
- ++ ATH10K_TESTMODE_VERSION_MAJOR,
- ++ ATH10K_TESTMODE_VERSION_MINOR);
- ++
- ++ skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy,
- ++ nla_total_size(sizeof(u32)));
- ++ if (!skb)
- ++ return -ENOMEM;
- ++
- ++ ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MAJOR,
- ++ ATH10K_TESTMODE_VERSION_MAJOR);
- ++ if (ret) {
- ++ kfree_skb(skb);
- ++ return ret;
- ++ }
- ++
- ++ ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MINOR,
- ++ ATH10K_TESTMODE_VERSION_MINOR);
- ++ if (ret) {
- ++ kfree_skb(skb);
- ++ return ret;
- ++ }
- ++
- ++ return cfg80211_testmode_reply(skb);
- ++}
- ++
- ++static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
- ++{
- ++ char filename[100];
- ++ int ret;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n");
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ if (ar->state == ATH10K_STATE_UTF) {
- ++ ret = -EALREADY;
- ++ goto err;
- ++ }
- ++
- ++ /* start utf only when the driver is not in use */
- ++ if (ar->state != ATH10K_STATE_OFF) {
- ++ ret = -EBUSY;
- ++ goto err;
- ++ }
- ++
- ++ if (WARN_ON(ar->testmode.utf != NULL)) {
- ++ /* utf image is already downloaded, it shouldn't be */
- ++ ret = -EEXIST;
- ++ goto err;
- ++ }
- ++
- ++ snprintf(filename, sizeof(filename), "%s/%s",
- ++ ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);
- ++
- ++ /* load utf firmware image */
- ++ ret = request_firmware(&ar->testmode.utf, filename, ar->dev);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
- ++ filename, ret);
- ++ goto err;
- ++ }
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++
- ++ ar->testmode.utf_monitor = true;
- ++
- ++ spin_unlock_bh(&ar->data_lock);
- ++
- ++ BUILD_BUG_ON(sizeof(ar->fw_features) !=
- ++ sizeof(ar->testmode.orig_fw_features));
- ++
- ++ memcpy(ar->testmode.orig_fw_features, ar->fw_features,
- ++ sizeof(ar->fw_features));
- ++ ar->testmode.orig_wmi_op_version = ar->wmi.op_version;
- ++
- ++ /* utf.bin firmware image does not advertise firmware features. Do
- ++ * an ugly hack where we force the firmware features so that wmi.c
- ++ * will use the correct WMI interface.
- ++ */
- ++ memset(ar->fw_features, 0, sizeof(ar->fw_features));
- ++ ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
- ++
- ++ ret = ath10k_hif_power_up(ar);
- ++ if (ret) {
- ++ ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret);
- ++ ar->state = ATH10K_STATE_OFF;
- ++ goto err_fw_features;
- ++ }
- ++
- ++ ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF);
- ++ if (ret) {
- ++ ath10k_err(ar, "failed to start core (testmode): %d\n", ret);
- ++ ar->state = ATH10K_STATE_OFF;
- ++ goto err_power_down;
- ++ }
- ++
- ++ ar->state = ATH10K_STATE_UTF;
- ++
- ++ ath10k_info(ar, "UTF firmware started\n");
- ++
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return 0;
- ++
- ++err_power_down:
- ++ ath10k_hif_power_down(ar);
- ++
- ++err_fw_features:
- ++ /* return the original firmware features */
- ++ memcpy(ar->fw_features, ar->testmode.orig_fw_features,
- ++ sizeof(ar->fw_features));
- ++ ar->wmi.op_version = ar->testmode.orig_wmi_op_version;
- ++
- ++ release_firmware(ar->testmode.utf);
- ++ ar->testmode.utf = NULL;
- ++
- ++err:
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return ret;
- ++}
- ++
- ++static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)
- ++{
- ++ lockdep_assert_held(&ar->conf_mutex);
- ++
- ++ ath10k_core_stop(ar);
- ++ ath10k_hif_power_down(ar);
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++
- ++ ar->testmode.utf_monitor = false;
- ++
- ++ spin_unlock_bh(&ar->data_lock);
- ++
- ++ /* return the original firmware features */
- ++ memcpy(ar->fw_features, ar->testmode.orig_fw_features,
- ++ sizeof(ar->fw_features));
- ++ ar->wmi.op_version = ar->testmode.orig_wmi_op_version;
- ++
- ++ release_firmware(ar->testmode.utf);
- ++ ar->testmode.utf = NULL;
- ++
- ++ ar->state = ATH10K_STATE_OFF;
- ++}
- ++
- ++static int ath10k_tm_cmd_utf_stop(struct ath10k *ar, struct nlattr *tb[])
- ++{
- ++ int ret;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf stop\n");
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ if (ar->state != ATH10K_STATE_UTF) {
- ++ ret = -ENETDOWN;
- ++ goto out;
- ++ }
- ++
- ++ __ath10k_tm_cmd_utf_stop(ar);
- ++
- ++ ret = 0;
- ++
- ++ ath10k_info(ar, "UTF firmware stopped\n");
- ++
- ++out:
- ++ mutex_unlock(&ar->conf_mutex);
- ++ return ret;
- ++}
- ++
- ++static int ath10k_tm_cmd_wmi(struct ath10k *ar, struct nlattr *tb[])
- ++{
- ++ struct sk_buff *skb;
- ++ int ret, buf_len;
- ++ u32 cmd_id;
- ++ void *buf;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ if (ar->state != ATH10K_STATE_UTF) {
- ++ ret = -ENETDOWN;
- ++ goto out;
- ++ }
- ++
- ++ if (!tb[ATH10K_TM_ATTR_DATA]) {
- ++ ret = -EINVAL;
- ++ goto out;
- ++ }
- ++
- ++ if (!tb[ATH10K_TM_ATTR_WMI_CMDID]) {
- ++ ret = -EINVAL;
- ++ goto out;
- ++ }
- ++
- ++ buf = nla_data(tb[ATH10K_TM_ATTR_DATA]);
- ++ buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]);
- ++ cmd_id = nla_get_u32(tb[ATH10K_TM_ATTR_WMI_CMDID]);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
- ++ "testmode cmd wmi cmd_id %d buf %p buf_len %d\n",
- ++ cmd_id, buf, buf_len);
- ++
- ++ ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len);
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, buf_len);
- ++ if (!skb) {
- ++ ret = -ENOMEM;
- ++ goto out;
- ++ }
- ++
- ++ memcpy(skb->data, buf, buf_len);
- ++
- ++ ret = ath10k_wmi_cmd_send(ar, skb, cmd_id);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to transmit wmi command (testmode): %d\n",
- ++ ret);
- ++ goto out;
- ++ }
- ++
- ++ ret = 0;
- ++
- ++out:
- ++ mutex_unlock(&ar->conf_mutex);
- ++ return ret;
- ++}
- ++
- ++int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- ++ void *data, int len)
- ++{
- ++ struct ath10k *ar = hw->priv;
- ++ struct nlattr *tb[ATH10K_TM_ATTR_MAX + 1];
- ++ int ret;
- ++
- ++ ret = nla_parse(tb, ATH10K_TM_ATTR_MAX, data, len,
- ++ ath10k_tm_policy);
- ++ if (ret)
- ++ return ret;
- ++
- ++ if (!tb[ATH10K_TM_ATTR_CMD])
- ++ return -EINVAL;
- ++
- ++ switch (nla_get_u32(tb[ATH10K_TM_ATTR_CMD])) {
- ++ case ATH10K_TM_CMD_GET_VERSION:
- ++ return ath10k_tm_cmd_get_version(ar, tb);
- ++ case ATH10K_TM_CMD_UTF_START:
- ++ return ath10k_tm_cmd_utf_start(ar, tb);
- ++ case ATH10K_TM_CMD_UTF_STOP:
- ++ return ath10k_tm_cmd_utf_stop(ar, tb);
- ++ case ATH10K_TM_CMD_WMI:
- ++ return ath10k_tm_cmd_wmi(ar, tb);
- ++ default:
- ++ return -EOPNOTSUPP;
- ++ }
- ++}
- ++
- ++void ath10k_testmode_destroy(struct ath10k *ar)
- ++{
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ if (ar->state != ATH10K_STATE_UTF) {
- ++ /* utf firmware is not running, nothing to do */
- ++ goto out;
- ++ }
- ++
- ++ __ath10k_tm_cmd_utf_stop(ar);
- ++
- ++out:
- ++ mutex_unlock(&ar->conf_mutex);
- ++}
- +--- /dev/null
- ++++ b/drivers/net/wireless/ath/ath10k/testmode.h
- +@@ -0,0 +1,46 @@
- ++/*
- ++ * Copyright (c) 2014 Qualcomm Atheros, Inc.
- ++ *
- ++ * Permission to use, copy, modify, and/or distribute this software for any
- ++ * purpose with or without fee is hereby granted, provided that the above
- ++ * copyright notice and this permission notice appear in all copies.
- ++ *
- ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ++ */
- ++
- ++#include "core.h"
- ++
- ++#ifdef CPTCFG_NL80211_TESTMODE
- ++
- ++void ath10k_testmode_destroy(struct ath10k *ar);
- ++
- ++bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb);
- ++int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- ++ void *data, int len);
- ++
- ++#else
- ++
- ++static inline void ath10k_testmode_destroy(struct ath10k *ar)
- ++{
- ++}
- ++
- ++static inline bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id,
- ++ struct sk_buff *skb)
- ++{
- ++ return false;
- ++}
- ++
- ++static inline int ath10k_tm_cmd(struct ieee80211_hw *hw,
- ++ struct ieee80211_vif *vif,
- ++ void *data, int len)
- ++{
- ++ return 0;
- ++}
- ++
- ++#endif
- +--- /dev/null
- ++++ b/drivers/net/wireless/ath/ath10k/testmode_i.h
- +@@ -0,0 +1,70 @@
- ++/*
- ++ * Copyright (c) 2014 Qualcomm Atheros, Inc.
- ++ *
- ++ * Permission to use, copy, modify, and/or distribute this software for any
- ++ * purpose with or without fee is hereby granted, provided that the above
- ++ * copyright notice and this permission notice appear in all copies.
- ++ *
- ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ++ */
- ++
- ++/* "API" level of the ath10k testmode interface. Bump it after every
- ++ * incompatible interface change.
- ++ */
- ++#define ATH10K_TESTMODE_VERSION_MAJOR 1
- ++
- ++/* Bump this after every _compatible_ interface change, for example
- ++ * addition of a new command or an attribute.
- ++ */
- ++#define ATH10K_TESTMODE_VERSION_MINOR 0
- ++
- ++#define ATH10K_TM_DATA_MAX_LEN 5000
- ++
- ++enum ath10k_tm_attr {
- ++ __ATH10K_TM_ATTR_INVALID = 0,
- ++ ATH10K_TM_ATTR_CMD = 1,
- ++ ATH10K_TM_ATTR_DATA = 2,
- ++ ATH10K_TM_ATTR_WMI_CMDID = 3,
- ++ ATH10K_TM_ATTR_VERSION_MAJOR = 4,
- ++ ATH10K_TM_ATTR_VERSION_MINOR = 5,
- ++
- ++ /* keep last */
- ++ __ATH10K_TM_ATTR_AFTER_LAST,
- ++ ATH10K_TM_ATTR_MAX = __ATH10K_TM_ATTR_AFTER_LAST - 1,
- ++};
- ++
- ++/* All ath10k testmode interface commands specified in
- ++ * ATH10K_TM_ATTR_CMD
- ++ */
- ++enum ath10k_tm_cmd {
- ++ /* Returns the supported ath10k testmode interface version in
- ++ * ATH10K_TM_ATTR_VERSION. Always guaranteed to work. User space
- ++ * uses this to verify it's using the correct version of the
- ++ * testmode interface
- ++ */
- ++ ATH10K_TM_CMD_GET_VERSION = 0,
- ++
- ++ /* Boots the UTF firmware, the netdev interface must be down at the
- ++ * time.
- ++ */
- ++ ATH10K_TM_CMD_UTF_START = 1,
- ++
- ++ /* Shuts down the UTF firmware and puts the driver back into OFF
- ++ * state.
- ++ */
- ++ ATH10K_TM_CMD_UTF_STOP = 2,
- ++
- ++ /* The command used to transmit a WMI command to the firmware and
- ++ * the event to receive WMI events from the firmware. Without
- ++ * struct wmi_cmd_hdr header, only the WMI payload. Command id is
- ++ * provided with ATH10K_TM_ATTR_WMI_CMDID and payload in
- ++ * ATH10K_TM_ATTR_DATA.
- ++ */
- ++ ATH10K_TM_CMD_WMI = 3,
- ++};
- +--- /dev/null
- ++++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
- +@@ -0,0 +1,243 @@
- ++/*
- ++ * Copyright (c) 2014 Qualcomm Atheros, Inc.
- ++ *
- ++ * Permission to use, copy, modify, and/or distribute this software for any
- ++ * purpose with or without fee is hereby granted, provided that the above
- ++ * copyright notice and this permission notice appear in all copies.
- ++ *
- ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ++ */
- ++
- ++#include "core.h"
- ++#include "wmi-ops.h"
- ++#include "debug.h"
- ++
- ++static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
- ++ char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ieee80211_sta *sta = file->private_data;
- ++ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
- ++ struct ath10k *ar = arsta->arvif->ar;
- ++ char buf[32];
- ++ int len = 0;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n",
- ++ (arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ?
- ++ "auto" : "manual");
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
- ++}
- ++
- ++static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file,
- ++ const char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ieee80211_sta *sta = file->private_data;
- ++ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
- ++ struct ath10k *ar = arsta->arvif->ar;
- ++ u32 aggr_mode;
- ++ int ret;
- ++
- ++ if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
- ++ return -EINVAL;
- ++
- ++ if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX)
- ++ return -EINVAL;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ if ((ar->state != ATH10K_STATE_ON) ||
- ++ (aggr_mode == arsta->aggr_mode)) {
- ++ ret = count;
- ++ goto out;
- ++ }
- ++
- ++ ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret);
- ++ goto out;
- ++ }
- ++
- ++ arsta->aggr_mode = aggr_mode;
- ++out:
- ++ mutex_unlock(&ar->conf_mutex);
- ++ return ret;
- ++}
- ++
- ++static const struct file_operations fops_aggr_mode = {
- ++ .read = ath10k_dbg_sta_read_aggr_mode,
- ++ .write = ath10k_dbg_sta_write_aggr_mode,
- ++ .open = simple_open,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- ++static ssize_t ath10k_dbg_sta_write_addba(struct file *file,
- ++ const char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ieee80211_sta *sta = file->private_data;
- ++ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
- ++ struct ath10k *ar = arsta->arvif->ar;
- ++ u32 tid, buf_size;
- ++ int ret;
- ++ char buf[64];
- ++
- ++ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
- ++
- ++ /* make sure that buf is null terminated */
- ++ buf[sizeof(buf) - 1] = '\0';
- ++
- ++ ret = sscanf(buf, "%u %u", &tid, &buf_size);
- ++ if (ret != 2)
- ++ return -EINVAL;
- ++
- ++ /* Valid TID values are 0 through 15 */
- ++ if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
- ++ return -EINVAL;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ if ((ar->state != ATH10K_STATE_ON) ||
- ++ (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
- ++ ret = count;
- ++ goto out;
- ++ }
- ++
- ++ ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
- ++ tid, buf_size);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
- ++ arsta->arvif->vdev_id, sta->addr, tid, buf_size);
- ++ }
- ++
- ++ ret = count;
- ++out:
- ++ mutex_unlock(&ar->conf_mutex);
- ++ return ret;
- ++}
- ++
- ++static const struct file_operations fops_addba = {
- ++ .write = ath10k_dbg_sta_write_addba,
- ++ .open = simple_open,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- ++static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file,
- ++ const char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ieee80211_sta *sta = file->private_data;
- ++ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
- ++ struct ath10k *ar = arsta->arvif->ar;
- ++ u32 tid, status;
- ++ int ret;
- ++ char buf[64];
- ++
- ++ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
- ++
- ++ /* make sure that buf is null terminated */
- ++ buf[sizeof(buf) - 1] = '\0';
- ++
- ++ ret = sscanf(buf, "%u %u", &tid, &status);
- ++ if (ret != 2)
- ++ return -EINVAL;
- ++
- ++ /* Valid TID values are 0 through 15 */
- ++ if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
- ++ return -EINVAL;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ if ((ar->state != ATH10K_STATE_ON) ||
- ++ (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
- ++ ret = count;
- ++ goto out;
- ++ }
- ++
- ++ ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
- ++ tid, status);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
- ++ arsta->arvif->vdev_id, sta->addr, tid, status);
- ++ }
- ++ ret = count;
- ++out:
- ++ mutex_unlock(&ar->conf_mutex);
- ++ return ret;
- ++}
- ++
- ++static const struct file_operations fops_addba_resp = {
- ++ .write = ath10k_dbg_sta_write_addba_resp,
- ++ .open = simple_open,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- ++static ssize_t ath10k_dbg_sta_write_delba(struct file *file,
- ++ const char __user *user_buf,
- ++ size_t count, loff_t *ppos)
- ++{
- ++ struct ieee80211_sta *sta = file->private_data;
- ++ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
- ++ struct ath10k *ar = arsta->arvif->ar;
- ++ u32 tid, initiator, reason;
- ++ int ret;
- ++ char buf[64];
- ++
- ++ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
- ++
- ++ /* make sure that buf is null terminated */
- ++ buf[sizeof(buf) - 1] = '\0';
- ++
- ++ ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
- ++ if (ret != 3)
- ++ return -EINVAL;
- ++
- ++ /* Valid TID values are 0 through 15 */
- ++ if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
- ++ return -EINVAL;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ if ((ar->state != ATH10K_STATE_ON) ||
- ++ (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
- ++ ret = count;
- ++ goto out;
- ++ }
- ++
- ++ ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
- ++ tid, initiator, reason);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
- ++ arsta->arvif->vdev_id, sta->addr, tid, initiator,
- ++ reason);
- ++ }
- ++ ret = count;
- ++out:
- ++ mutex_unlock(&ar->conf_mutex);
- ++ return ret;
- ++}
- ++
- ++static const struct file_operations fops_delba = {
- ++ .write = ath10k_dbg_sta_write_delba,
- ++ .open = simple_open,
- ++ .owner = THIS_MODULE,
- ++ .llseek = default_llseek,
- ++};
- ++
- ++void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- ++ struct ieee80211_sta *sta, struct dentry *dir)
- ++{
- ++ debugfs_create_file("aggr_mode", S_IRUGO | S_IWUSR, dir, sta,
- ++ &fops_aggr_mode);
- ++ debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba);
- ++ debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp);
- ++ debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba);
- ++}
- +--- /dev/null
- ++++ b/drivers/net/wireless/ath/ath10k/hw.c
- +@@ -0,0 +1,58 @@
- ++/*
- ++ * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
- ++ *
- ++ * Permission to use, copy, modify, and/or distribute this software for any
- ++ * purpose with or without fee is hereby granted, provided that the above
- ++ * copyright notice and this permission notice appear in all copies.
- ++ *
- ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ++ */
- ++
- ++#include <linux/types.h>
- ++#include "hw.h"
- ++
- ++const struct ath10k_hw_regs qca988x_regs = {
- ++ .rtc_state_cold_reset_mask = 0x00000400,
- ++ .rtc_soc_base_address = 0x00004000,
- ++ .rtc_wmac_base_address = 0x00005000,
- ++ .soc_core_base_address = 0x00009000,
- ++ .ce_wrapper_base_address = 0x00057000,
- ++ .ce0_base_address = 0x00057400,
- ++ .ce1_base_address = 0x00057800,
- ++ .ce2_base_address = 0x00057c00,
- ++ .ce3_base_address = 0x00058000,
- ++ .ce4_base_address = 0x00058400,
- ++ .ce5_base_address = 0x00058800,
- ++ .ce6_base_address = 0x00058c00,
- ++ .ce7_base_address = 0x00059000,
- ++ .soc_reset_control_si0_rst_mask = 0x00000001,
- ++ .soc_reset_control_ce_rst_mask = 0x00040000,
- ++ .soc_chip_id_address = 0x00ec,
- ++ .scratch_3_address = 0x0030,
- ++};
- ++
- ++const struct ath10k_hw_regs qca6174_regs = {
- ++ .rtc_state_cold_reset_mask = 0x00002000,
- ++ .rtc_soc_base_address = 0x00000800,
- ++ .rtc_wmac_base_address = 0x00001000,
- ++ .soc_core_base_address = 0x0003a000,
- ++ .ce_wrapper_base_address = 0x00034000,
- ++ .ce0_base_address = 0x00034400,
- ++ .ce1_base_address = 0x00034800,
- ++ .ce2_base_address = 0x00034c00,
- ++ .ce3_base_address = 0x00035000,
- ++ .ce4_base_address = 0x00035400,
- ++ .ce5_base_address = 0x00035800,
- ++ .ce6_base_address = 0x00035c00,
- ++ .ce7_base_address = 0x00036000,
- ++ .soc_reset_control_si0_rst_mask = 0x00000000,
- ++ .soc_reset_control_ce_rst_mask = 0x00000001,
- ++ .soc_chip_id_address = 0x000f0,
- ++ .scratch_3_address = 0x0028,
- ++};
- +--- /dev/null
- ++++ b/drivers/net/wireless/ath/ath10k/thermal.c
- +@@ -0,0 +1,244 @@
- ++/*
- ++ * Copyright (c) 2014 Qualcomm Atheros, Inc.
- ++ *
- ++ * Permission to use, copy, modify, and/or distribute this software for any
- ++ * purpose with or without fee is hereby granted, provided that the above
- ++ * copyright notice and this permission notice appear in all copies.
- ++ *
- ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ++ */
- ++
- ++#include <linux/device.h>
- ++#include <linux/sysfs.h>
- ++#include <linux/thermal.h>
- ++#include <linux/hwmon.h>
- ++#include <linux/hwmon-sysfs.h>
- ++#include "core.h"
- ++#include "debug.h"
- ++#include "wmi-ops.h"
- ++
- ++static int ath10k_thermal_get_active_vifs(struct ath10k *ar,
- ++ enum wmi_vdev_type type)
- ++{
- ++ struct ath10k_vif *arvif;
- ++ int count = 0;
- ++
- ++ lockdep_assert_held(&ar->conf_mutex);
- ++
- ++ list_for_each_entry(arvif, &ar->arvifs, list) {
- ++ if (!arvif->is_started)
- ++ continue;
- ++
- ++ if (!arvif->is_up)
- ++ continue;
- ++
- ++ if (arvif->vdev_type != type)
- ++ continue;
- ++
- ++ count++;
- ++ }
- ++ return count;
- ++}
- ++
- ++static int ath10k_thermal_get_max_dutycycle(struct thermal_cooling_device *cdev,
- ++ unsigned long *state)
- ++{
- ++ *state = ATH10K_QUIET_DUTY_CYCLE_MAX;
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_thermal_get_cur_dutycycle(struct thermal_cooling_device *cdev,
- ++ unsigned long *state)
- ++{
- ++ struct ath10k *ar = cdev->devdata;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ *state = ar->thermal.duty_cycle;
- ++ mutex_unlock(&ar->conf_mutex);
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_thermal_set_cur_dutycycle(struct thermal_cooling_device *cdev,
- ++ unsigned long duty_cycle)
- ++{
- ++ struct ath10k *ar = cdev->devdata;
- ++ u32 period, duration, enabled;
- ++ int num_bss, ret = 0;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++ if (ar->state != ATH10K_STATE_ON) {
- ++ ret = -ENETDOWN;
- ++ goto out;
- ++ }
- ++
- ++ if (duty_cycle > ATH10K_QUIET_DUTY_CYCLE_MAX) {
- ++ ath10k_warn(ar, "duty cycle %ld is exceeding the limit %d\n",
- ++ duty_cycle, ATH10K_QUIET_DUTY_CYCLE_MAX);
- ++ ret = -EINVAL;
- ++ goto out;
- ++ }
- ++ /* TODO: Right now, thermal mitigation is handled only for single/multi
- ++ * vif AP mode. Since quiet param is not validated in STA mode, it needs
- ++ * to be investigated further to handle multi STA and multi-vif (AP+STA)
- ++ * mode properly.
- ++ */
- ++ num_bss = ath10k_thermal_get_active_vifs(ar, WMI_VDEV_TYPE_AP);
- ++ if (!num_bss) {
- ++ ath10k_warn(ar, "no active AP interfaces\n");
- ++ ret = -ENETDOWN;
- ++ goto out;
- ++ }
- ++ period = max(ATH10K_QUIET_PERIOD_MIN,
- ++ (ATH10K_QUIET_PERIOD_DEFAULT / num_bss));
- ++ duration = (period * duty_cycle) / 100;
- ++ enabled = duration ? 1 : 0;
- ++
- ++ ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration,
- ++ ATH10K_QUIET_START_OFFSET,
- ++ enabled);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",
- ++ period, duration, enabled, ret);
- ++ goto out;
- ++ }
- ++ ar->thermal.duty_cycle = duty_cycle;
- ++out:
- ++ mutex_unlock(&ar->conf_mutex);
- ++ return ret;
- ++}
- ++
- ++static struct thermal_cooling_device_ops ath10k_thermal_ops = {
- ++ .get_max_state = ath10k_thermal_get_max_dutycycle,
- ++ .get_cur_state = ath10k_thermal_get_cur_dutycycle,
- ++ .set_cur_state = ath10k_thermal_set_cur_dutycycle,
- ++};
- ++
- ++static ssize_t ath10k_thermal_show_temp(struct device *dev,
- ++ struct device_attribute *attr,
- ++ char *buf)
- ++{
- ++ struct ath10k *ar = dev_get_drvdata(dev);
- ++ int ret, temperature;
- ++
- ++ mutex_lock(&ar->conf_mutex);
- ++
- ++ /* Can't get temperature when the card is off */
- ++ if (ar->state != ATH10K_STATE_ON) {
- ++ ret = -ENETDOWN;
- ++ goto out;
- ++ }
- ++
- ++ reinit_completion(&ar->thermal.wmi_sync);
- ++ ret = ath10k_wmi_pdev_get_temperature(ar);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to read temperature %d\n", ret);
- ++ goto out;
- ++ }
- ++
- ++ if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
- ++ ret = -ESHUTDOWN;
- ++ goto out;
- ++ }
- ++
- ++ ret = wait_for_completion_timeout(&ar->thermal.wmi_sync,
- ++ ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
- ++ if (ret == 0) {
- ++ ath10k_warn(ar, "failed to synchronize thermal read\n");
- ++ ret = -ETIMEDOUT;
- ++ goto out;
- ++ }
- ++
- ++ spin_lock_bh(&ar->data_lock);
- ++ temperature = ar->thermal.temperature;
- ++ spin_unlock_bh(&ar->data_lock);
- ++
- ++ /* display in millidegree celcius */
- ++ ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000);
- ++out:
- ++ mutex_unlock(&ar->conf_mutex);
- ++ return ret;
- ++}
- ++
- ++void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature)
- ++{
- ++ spin_lock_bh(&ar->data_lock);
- ++ ar->thermal.temperature = temperature;
- ++ spin_unlock_bh(&ar->data_lock);
- ++ complete(&ar->thermal.wmi_sync);
- ++}
- ++
- ++static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ath10k_thermal_show_temp,
- ++ NULL, 0);
- ++
- ++static struct attribute *ath10k_hwmon_attrs[] = {
- ++ &sensor_dev_attr_temp1_input.dev_attr.attr,
- ++ NULL,
- ++};
- ++ATTRIBUTE_GROUPS(ath10k_hwmon);
- ++
- ++int ath10k_thermal_register(struct ath10k *ar)
- ++{
- ++ struct thermal_cooling_device *cdev;
- ++ struct device *hwmon_dev;
- ++ int ret;
- ++
- ++ cdev = thermal_cooling_device_register("ath10k_thermal", ar,
- ++ &ath10k_thermal_ops);
- ++
- ++ if (IS_ERR(cdev)) {
- ++ ath10k_err(ar, "failed to setup thermal device result: %ld\n",
- ++ PTR_ERR(cdev));
- ++ return -EINVAL;
- ++ }
- ++
- ++ ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj,
- ++ "cooling_device");
- ++ if (ret) {
- ++ ath10k_err(ar, "failed to create thermal symlink\n");
- ++ goto err_cooling_destroy;
- ++ }
- ++
- ++ ar->thermal.cdev = cdev;
- ++
- ++ /* Do not register hwmon device when temperature reading is not
- ++ * supported by firmware
- ++ */
- ++ if (ar->wmi.op_version != ATH10K_FW_WMI_OP_VERSION_10_2_4)
- ++ return 0;
- ++
- ++ /* Avoid linking error on devm_hwmon_device_register_with_groups, I
- ++ * guess linux/hwmon.h is missing proper stubs. */
- ++ if (!config_enabled(CONFIG_HWMON))
- ++ return 0;
- ++
- ++ hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev,
- ++ "ath10k_hwmon", ar,
- ++ ath10k_hwmon_groups);
- ++ if (IS_ERR(hwmon_dev)) {
- ++ ath10k_err(ar, "failed to register hwmon device: %ld\n",
- ++ PTR_ERR(hwmon_dev));
- ++ ret = -EINVAL;
- ++ goto err_remove_link;
- ++ }
- ++ return 0;
- ++
- ++err_remove_link:
- ++ sysfs_remove_link(&ar->dev->kobj, "thermal_sensor");
- ++err_cooling_destroy:
- ++ thermal_cooling_device_unregister(cdev);
- ++ return ret;
- ++}
- ++
- ++void ath10k_thermal_unregister(struct ath10k *ar)
- ++{
- ++ thermal_cooling_device_unregister(ar->thermal.cdev);
- ++ sysfs_remove_link(&ar->dev->kobj, "cooling_device");
- ++}
- +--- /dev/null
- ++++ b/drivers/net/wireless/ath/ath10k/thermal.h
- +@@ -0,0 +1,58 @@
- ++/*
- ++ * Copyright (c) 2014 Qualcomm Atheros, Inc.
- ++ *
- ++ * Permission to use, copy, modify, and/or distribute this software for any
- ++ * purpose with or without fee is hereby granted, provided that the above
- ++ * copyright notice and this permission notice appear in all copies.
- ++ *
- ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ++ */
- ++#ifndef _THERMAL_
- ++#define _THERMAL_
- ++
- ++#define ATH10K_QUIET_PERIOD_DEFAULT 100
- ++#define ATH10K_QUIET_PERIOD_MIN 25
- ++#define ATH10K_QUIET_START_OFFSET 10
- ++#define ATH10K_QUIET_DUTY_CYCLE_MAX 70
- ++#define ATH10K_HWMON_NAME_LEN 15
- ++#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5*HZ)
- ++
- ++struct ath10k_thermal {
- ++ struct thermal_cooling_device *cdev;
- ++ struct completion wmi_sync;
- ++
- ++ /* protected by conf_mutex */
- ++ u32 duty_cycle;
- ++ /* temperature value in Celcius degree
- ++ * protected by data_lock
- ++ */
- ++ int temperature;
- ++};
- ++
- ++#ifdef CONFIG_THERMAL
- ++int ath10k_thermal_register(struct ath10k *ar);
- ++void ath10k_thermal_unregister(struct ath10k *ar);
- ++void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature);
- ++#else
- ++static inline int ath10k_thermal_register(struct ath10k *ar)
- ++{
- ++ return 0;
- ++}
- ++
- ++static inline void ath10k_thermal_unregister(struct ath10k *ar)
- ++{
- ++}
- ++
- ++static inline void ath10k_thermal_event_temperature(struct ath10k *ar,
- ++ int temperature)
- ++{
- ++}
- ++
- ++#endif
- ++#endif /* _THERMAL_ */
- +--- /dev/null
- ++++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
- +@@ -0,0 +1,1063 @@
- ++/*
- ++ * Copyright (c) 2005-2011 Atheros Communications Inc.
- ++ * Copyright (c) 2011-2014 Qualcomm Atheros, Inc.
- ++ *
- ++ * Permission to use, copy, modify, and/or distribute this software for any
- ++ * purpose with or without fee is hereby granted, provided that the above
- ++ * copyright notice and this permission notice appear in all copies.
- ++ *
- ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ++ */
- ++
- ++#ifndef _WMI_OPS_H_
- ++#define _WMI_OPS_H_
- ++
- ++struct ath10k;
- ++struct sk_buff;
- ++
- ++struct wmi_ops {
- ++ void (*rx)(struct ath10k *ar, struct sk_buff *skb);
- ++ void (*map_svc)(const __le32 *in, unsigned long *out, size_t len);
- ++
- ++ int (*pull_scan)(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_scan_ev_arg *arg);
- ++ int (*pull_mgmt_rx)(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_mgmt_rx_ev_arg *arg);
- ++ int (*pull_ch_info)(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_ch_info_ev_arg *arg);
- ++ int (*pull_vdev_start)(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_vdev_start_ev_arg *arg);
- ++ int (*pull_peer_kick)(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_peer_kick_ev_arg *arg);
- ++ int (*pull_swba)(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_swba_ev_arg *arg);
- ++ int (*pull_phyerr)(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_phyerr_ev_arg *arg);
- ++ int (*pull_svc_rdy)(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_svc_rdy_ev_arg *arg);
- ++ int (*pull_rdy)(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_rdy_ev_arg *arg);
- ++ int (*pull_fw_stats)(struct ath10k *ar, struct sk_buff *skb,
- ++ struct ath10k_fw_stats *stats);
- ++
- ++ struct sk_buff *(*gen_pdev_suspend)(struct ath10k *ar, u32 suspend_opt);
- ++ struct sk_buff *(*gen_pdev_resume)(struct ath10k *ar);
- ++ struct sk_buff *(*gen_pdev_set_rd)(struct ath10k *ar, u16 rd, u16 rd2g,
- ++ u16 rd5g, u16 ctl2g, u16 ctl5g,
- ++ enum wmi_dfs_region dfs_reg);
- ++ struct sk_buff *(*gen_pdev_set_param)(struct ath10k *ar, u32 id,
- ++ u32 value);
- ++ struct sk_buff *(*gen_init)(struct ath10k *ar);
- ++ struct sk_buff *(*gen_start_scan)(struct ath10k *ar,
- ++ const struct wmi_start_scan_arg *arg);
- ++ struct sk_buff *(*gen_stop_scan)(struct ath10k *ar,
- ++ const struct wmi_stop_scan_arg *arg);
- ++ struct sk_buff *(*gen_vdev_create)(struct ath10k *ar, u32 vdev_id,
- ++ enum wmi_vdev_type type,
- ++ enum wmi_vdev_subtype subtype,
- ++ const u8 macaddr[ETH_ALEN]);
- ++ struct sk_buff *(*gen_vdev_delete)(struct ath10k *ar, u32 vdev_id);
- ++ struct sk_buff *(*gen_vdev_start)(struct ath10k *ar,
- ++ const struct wmi_vdev_start_request_arg *arg,
- ++ bool restart);
- ++ struct sk_buff *(*gen_vdev_stop)(struct ath10k *ar, u32 vdev_id);
- ++ struct sk_buff *(*gen_vdev_up)(struct ath10k *ar, u32 vdev_id, u32 aid,
- ++ const u8 *bssid);
- ++ struct sk_buff *(*gen_vdev_down)(struct ath10k *ar, u32 vdev_id);
- ++ struct sk_buff *(*gen_vdev_set_param)(struct ath10k *ar, u32 vdev_id,
- ++ u32 param_id, u32 param_value);
- ++ struct sk_buff *(*gen_vdev_install_key)(struct ath10k *ar,
- ++ const struct wmi_vdev_install_key_arg *arg);
- ++ struct sk_buff *(*gen_vdev_spectral_conf)(struct ath10k *ar,
- ++ const struct wmi_vdev_spectral_conf_arg *arg);
- ++ struct sk_buff *(*gen_vdev_spectral_enable)(struct ath10k *ar, u32 vdev_id,
- ++ u32 trigger, u32 enable);
- ++ struct sk_buff *(*gen_vdev_wmm_conf)(struct ath10k *ar, u32 vdev_id,
- ++ const struct wmi_wmm_params_all_arg *arg);
- ++ struct sk_buff *(*gen_peer_create)(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN]);
- ++ struct sk_buff *(*gen_peer_delete)(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN]);
- ++ struct sk_buff *(*gen_peer_flush)(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN],
- ++ u32 tid_bitmap);
- ++ struct sk_buff *(*gen_peer_set_param)(struct ath10k *ar, u32 vdev_id,
- ++ const u8 *peer_addr,
- ++ enum wmi_peer_param param_id,
- ++ u32 param_value);
- ++ struct sk_buff *(*gen_peer_assoc)(struct ath10k *ar,
- ++ const struct wmi_peer_assoc_complete_arg *arg);
- ++ struct sk_buff *(*gen_set_psmode)(struct ath10k *ar, u32 vdev_id,
- ++ enum wmi_sta_ps_mode psmode);
- ++ struct sk_buff *(*gen_set_sta_ps)(struct ath10k *ar, u32 vdev_id,
- ++ enum wmi_sta_powersave_param param_id,
- ++ u32 value);
- ++ struct sk_buff *(*gen_set_ap_ps)(struct ath10k *ar, u32 vdev_id,
- ++ const u8 *mac,
- ++ enum wmi_ap_ps_peer_param param_id,
- ++ u32 value);
- ++ struct sk_buff *(*gen_scan_chan_list)(struct ath10k *ar,
- ++ const struct wmi_scan_chan_list_arg *arg);
- ++ struct sk_buff *(*gen_beacon_dma)(struct ath10k *ar, u32 vdev_id,
- ++ const void *bcn, size_t bcn_len,
- ++ u32 bcn_paddr, bool dtim_zero,
- ++ bool deliver_cab);
- ++ struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar,
- ++ const struct wmi_wmm_params_all_arg *arg);
- ++ struct sk_buff *(*gen_request_stats)(struct ath10k *ar, u32 stats_mask);
- ++ struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar,
- ++ enum wmi_force_fw_hang_type type,
- ++ u32 delay_ms);
- ++ struct sk_buff *(*gen_mgmt_tx)(struct ath10k *ar, struct sk_buff *skb);
- ++ struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u32 module_enable,
- ++ u32 log_level);
- ++ struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter);
- ++ struct sk_buff *(*gen_pktlog_disable)(struct ath10k *ar);
- ++ struct sk_buff *(*gen_pdev_set_quiet_mode)(struct ath10k *ar,
- ++ u32 period, u32 duration,
- ++ u32 next_offset,
- ++ u32 enabled);
- ++ struct sk_buff *(*gen_pdev_get_temperature)(struct ath10k *ar);
- ++ struct sk_buff *(*gen_addba_clear_resp)(struct ath10k *ar, u32 vdev_id,
- ++ const u8 *mac);
- ++ struct sk_buff *(*gen_addba_send)(struct ath10k *ar, u32 vdev_id,
- ++ const u8 *mac, u32 tid, u32 buf_size);
- ++ struct sk_buff *(*gen_addba_set_resp)(struct ath10k *ar, u32 vdev_id,
- ++ const u8 *mac, u32 tid,
- ++ u32 status);
- ++ struct sk_buff *(*gen_delba_send)(struct ath10k *ar, u32 vdev_id,
- ++ const u8 *mac, u32 tid, u32 initiator,
- ++ u32 reason);
- ++ struct sk_buff *(*gen_bcn_tmpl)(struct ath10k *ar, u32 vdev_id,
- ++ u32 tim_ie_offset, struct sk_buff *bcn,
- ++ u32 prb_caps, u32 prb_erp,
- ++ void *prb_ies, size_t prb_ies_len);
- ++ struct sk_buff *(*gen_prb_tmpl)(struct ath10k *ar, u32 vdev_id,
- ++ struct sk_buff *bcn);
- ++ struct sk_buff *(*gen_p2p_go_bcn_ie)(struct ath10k *ar, u32 vdev_id,
- ++ const u8 *p2p_ie);
- ++ struct sk_buff *(*gen_vdev_sta_uapsd)(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN],
- ++ const struct wmi_sta_uapsd_auto_trig_arg *args,
- ++ u32 num_ac);
- ++ struct sk_buff *(*gen_sta_keepalive)(struct ath10k *ar,
- ++ const struct wmi_sta_keepalive_arg *arg);
- ++};
- ++
- ++int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
- ++
- ++static inline int
- ++ath10k_wmi_rx(struct ath10k *ar, struct sk_buff *skb)
- ++{
- ++ if (WARN_ON_ONCE(!ar->wmi.ops->rx))
- ++ return -EOPNOTSUPP;
- ++
- ++ ar->wmi.ops->rx(ar, skb);
- ++ return 0;
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_map_svc(struct ath10k *ar, const __le32 *in, unsigned long *out,
- ++ size_t len)
- ++{
- ++ if (!ar->wmi.ops->map_svc)
- ++ return -EOPNOTSUPP;
- ++
- ++ ar->wmi.ops->map_svc(in, out, len);
- ++ return 0;
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pull_scan(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_scan_ev_arg *arg)
- ++{
- ++ if (!ar->wmi.ops->pull_scan)
- ++ return -EOPNOTSUPP;
- ++
- ++ return ar->wmi.ops->pull_scan(ar, skb, arg);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pull_mgmt_rx(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_mgmt_rx_ev_arg *arg)
- ++{
- ++ if (!ar->wmi.ops->pull_mgmt_rx)
- ++ return -EOPNOTSUPP;
- ++
- ++ return ar->wmi.ops->pull_mgmt_rx(ar, skb, arg);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pull_ch_info(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_ch_info_ev_arg *arg)
- ++{
- ++ if (!ar->wmi.ops->pull_ch_info)
- ++ return -EOPNOTSUPP;
- ++
- ++ return ar->wmi.ops->pull_ch_info(ar, skb, arg);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pull_vdev_start(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_vdev_start_ev_arg *arg)
- ++{
- ++ if (!ar->wmi.ops->pull_vdev_start)
- ++ return -EOPNOTSUPP;
- ++
- ++ return ar->wmi.ops->pull_vdev_start(ar, skb, arg);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pull_peer_kick(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_peer_kick_ev_arg *arg)
- ++{
- ++ if (!ar->wmi.ops->pull_peer_kick)
- ++ return -EOPNOTSUPP;
- ++
- ++ return ar->wmi.ops->pull_peer_kick(ar, skb, arg);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pull_swba(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_swba_ev_arg *arg)
- ++{
- ++ if (!ar->wmi.ops->pull_swba)
- ++ return -EOPNOTSUPP;
- ++
- ++ return ar->wmi.ops->pull_swba(ar, skb, arg);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pull_phyerr(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_phyerr_ev_arg *arg)
- ++{
- ++ if (!ar->wmi.ops->pull_phyerr)
- ++ return -EOPNOTSUPP;
- ++
- ++ return ar->wmi.ops->pull_phyerr(ar, skb, arg);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pull_svc_rdy(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_svc_rdy_ev_arg *arg)
- ++{
- ++ if (!ar->wmi.ops->pull_svc_rdy)
- ++ return -EOPNOTSUPP;
- ++
- ++ return ar->wmi.ops->pull_svc_rdy(ar, skb, arg);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pull_rdy(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_rdy_ev_arg *arg)
- ++{
- ++ if (!ar->wmi.ops->pull_rdy)
- ++ return -EOPNOTSUPP;
- ++
- ++ return ar->wmi.ops->pull_rdy(ar, skb, arg);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
- ++ struct ath10k_fw_stats *stats)
- ++{
- ++ if (!ar->wmi.ops->pull_fw_stats)
- ++ return -EOPNOTSUPP;
- ++
- ++ return ar->wmi.ops->pull_fw_stats(ar, skb, stats);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
- ++{
- ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
- ++ struct sk_buff *skb;
- ++ int ret;
- ++
- ++ if (!ar->wmi.ops->gen_mgmt_tx)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_mgmt_tx(ar, msdu);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ ret = ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->mgmt_tx_cmdid);
- ++ if (ret)
- ++ return ret;
- ++
- ++ /* FIXME There's no ACK event for Management Tx. This probably
- ++ * shouldn't be called here either. */
- ++ info->flags |= IEEE80211_TX_STAT_ACK;
- ++ ieee80211_tx_status_irqsafe(ar->hw, msdu);
- ++
- ++ return 0;
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, u16 rd5g,
- ++ u16 ctl2g, u16 ctl5g,
- ++ enum wmi_dfs_region dfs_reg)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_pdev_set_rd)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_pdev_set_rd(ar, rd, rd2g, rd5g, ctl2g, ctl5g,
- ++ dfs_reg);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->pdev_set_regdomain_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_pdev_suspend)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_pdev_suspend(ar, suspend_opt);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pdev_resume_target(struct ath10k *ar)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_pdev_resume)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_pdev_resume(ar);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_resume_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_pdev_set_param)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_pdev_set_param(ar, id, value);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_cmd_init(struct ath10k *ar)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_init)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_init(ar);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->init_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_start_scan(struct ath10k *ar,
- ++ const struct wmi_start_scan_arg *arg)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_start_scan)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_start_scan(ar, arg);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_stop_scan)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_stop_scan(ar, arg);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
- ++ enum wmi_vdev_type type,
- ++ enum wmi_vdev_subtype subtype,
- ++ const u8 macaddr[ETH_ALEN])
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_vdev_create)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_vdev_create(ar, vdev_id, type, subtype, macaddr);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_create_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_vdev_delete)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_vdev_delete(ar, vdev_id);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_vdev_start(struct ath10k *ar,
- ++ const struct wmi_vdev_start_request_arg *arg)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_vdev_start)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_vdev_start(ar, arg, false);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->vdev_start_request_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_vdev_restart(struct ath10k *ar,
- ++ const struct wmi_vdev_start_request_arg *arg)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_vdev_start)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_vdev_start(ar, arg, true);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->vdev_restart_request_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_vdev_stop)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_vdev_stop(ar, vdev_id);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_vdev_up)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_vdev_up(ar, vdev_id, aid, bssid);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_up_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_vdev_down)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_vdev_down(ar, vdev_id);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, u32 param_id,
- ++ u32 param_value)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_vdev_set_param)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_vdev_set_param(ar, vdev_id, param_id,
- ++ param_value);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_set_param_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_vdev_install_key(struct ath10k *ar,
- ++ const struct wmi_vdev_install_key_arg *arg)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_vdev_install_key)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_vdev_install_key(ar, arg);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->vdev_install_key_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
- ++ const struct wmi_vdev_spectral_conf_arg *arg)
- ++{
- ++ struct sk_buff *skb;
- ++ u32 cmd_id;
- ++
- ++ skb = ar->wmi.ops->gen_vdev_spectral_conf(ar, arg);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ cmd_id = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid;
- ++ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
- ++ u32 enable)
- ++{
- ++ struct sk_buff *skb;
- ++ u32 cmd_id;
- ++
- ++ skb = ar->wmi.ops->gen_vdev_spectral_enable(ar, vdev_id, trigger,
- ++ enable);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ cmd_id = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid;
- ++ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_vdev_sta_uapsd(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN],
- ++ const struct wmi_sta_uapsd_auto_trig_arg *args,
- ++ u32 num_ac)
- ++{
- ++ struct sk_buff *skb;
- ++ u32 cmd_id;
- ++
- ++ if (!ar->wmi.ops->gen_vdev_sta_uapsd)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_vdev_sta_uapsd(ar, vdev_id, peer_addr, args,
- ++ num_ac);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ cmd_id = ar->wmi.cmd->sta_uapsd_auto_trig_cmdid;
- ++ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id,
- ++ const struct wmi_wmm_params_all_arg *arg)
- ++{
- ++ struct sk_buff *skb;
- ++ u32 cmd_id;
- ++
- ++ skb = ar->wmi.ops->gen_vdev_wmm_conf(ar, vdev_id, arg);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ cmd_id = ar->wmi.cmd->vdev_set_wmm_params_cmdid;
- ++ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN])
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_peer_create)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN])
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_peer_delete)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_peer_delete(ar, vdev_id, peer_addr);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN], u32 tid_bitmap)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_peer_flush)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_peer_flush(ar, vdev_id, peer_addr, tid_bitmap);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, const u8 *peer_addr,
- ++ enum wmi_peer_param param_id, u32 param_value)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_peer_set_param)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_peer_set_param(ar, vdev_id, peer_addr, param_id,
- ++ param_value);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_set_param_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
- ++ enum wmi_sta_ps_mode psmode)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_set_psmode)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_set_psmode(ar, vdev_id, psmode);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->sta_powersave_mode_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
- ++ enum wmi_sta_powersave_param param_id, u32 value)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_set_sta_ps)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_set_sta_ps(ar, vdev_id, param_id, value);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->sta_powersave_param_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
- ++ enum wmi_ap_ps_peer_param param_id, u32 value)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_set_ap_ps)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_set_ap_ps(ar, vdev_id, mac, param_id, value);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->ap_ps_peer_param_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_scan_chan_list(struct ath10k *ar,
- ++ const struct wmi_scan_chan_list_arg *arg)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_scan_chan_list)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_scan_chan_list(ar, arg);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_peer_assoc(struct ath10k *ar,
- ++ const struct wmi_peer_assoc_complete_arg *arg)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_peer_assoc)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_peer_assoc(ar, arg);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_beacon_send_ref_nowait(struct ath10k *ar, u32 vdev_id,
- ++ const void *bcn, size_t bcn_len,
- ++ u32 bcn_paddr, bool dtim_zero,
- ++ bool deliver_cab)
- ++{
- ++ struct sk_buff *skb;
- ++ int ret;
- ++
- ++ if (!ar->wmi.ops->gen_beacon_dma)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_beacon_dma(ar, vdev_id, bcn, bcn_len, bcn_paddr,
- ++ dtim_zero, deliver_cab);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ ret = ath10k_wmi_cmd_send_nowait(ar, skb,
- ++ ar->wmi.cmd->pdev_send_bcn_cmdid);
- ++ if (ret) {
- ++ dev_kfree_skb(skb);
- ++ return ret;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
- ++ const struct wmi_wmm_params_all_arg *arg)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_pdev_set_wmm)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_pdev_set_wmm(ar, arg);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->pdev_set_wmm_params_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_request_stats(struct ath10k *ar, u32 stats_mask)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_request_stats)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_request_stats(ar, stats_mask);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_force_fw_hang(struct ath10k *ar,
- ++ enum wmi_force_fw_hang_type type, u32 delay_ms)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_force_fw_hang)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_force_fw_hang(ar, type, delay_ms);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable, u32 log_level)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_dbglog_cfg)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_dbglog_cfg(ar, module_enable, log_level);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 filter)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_pktlog_enable)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_pktlog_enable(ar, filter);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_pktlog_enable_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_pktlog_disable)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_pktlog_disable(ar);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->pdev_pktlog_disable_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pdev_set_quiet_mode(struct ath10k *ar, u32 period, u32 duration,
- ++ u32 next_offset, u32 enabled)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_pdev_set_quiet_mode)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_pdev_set_quiet_mode(ar, period, duration,
- ++ next_offset, enabled);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->pdev_set_quiet_mode_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_pdev_get_temperature(struct ath10k *ar)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_pdev_get_temperature)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_pdev_get_temperature(ar);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->pdev_get_temperature_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_addba_clear_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_addba_clear_resp)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_addba_clear_resp(ar, vdev_id, mac);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->addba_clear_resp_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_addba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac,
- ++ u32 tid, u32 buf_size)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_addba_send)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_addba_send(ar, vdev_id, mac, tid, buf_size);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->addba_send_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_addba_set_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac,
- ++ u32 tid, u32 status)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_addba_set_resp)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_addba_set_resp(ar, vdev_id, mac, tid, status);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->addba_set_resp_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac,
- ++ u32 tid, u32 initiator, u32 reason)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_delba_send)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_delba_send(ar, vdev_id, mac, tid, initiator,
- ++ reason);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb,
- ++ ar->wmi.cmd->delba_send_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_bcn_tmpl(struct ath10k *ar, u32 vdev_id, u32 tim_ie_offset,
- ++ struct sk_buff *bcn, u32 prb_caps, u32 prb_erp,
- ++ void *prb_ies, size_t prb_ies_len)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_bcn_tmpl)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_bcn_tmpl(ar, vdev_id, tim_ie_offset, bcn,
- ++ prb_caps, prb_erp, prb_ies,
- ++ prb_ies_len);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->bcn_tmpl_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_prb_tmpl(struct ath10k *ar, u32 vdev_id, struct sk_buff *prb)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_prb_tmpl)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_prb_tmpl(ar, vdev_id, prb);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->prb_tmpl_cmdid);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id, const u8 *p2p_ie)
- ++{
- ++ struct sk_buff *skb;
- ++
- ++ if (!ar->wmi.ops->gen_p2p_go_bcn_ie)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_p2p_go_bcn_ie(ar, vdev_id, p2p_ie);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->p2p_go_set_beacon_ie);
- ++}
- ++
- ++static inline int
- ++ath10k_wmi_sta_keepalive(struct ath10k *ar,
- ++ const struct wmi_sta_keepalive_arg *arg)
- ++{
- ++ struct sk_buff *skb;
- ++ u32 cmd_id;
- ++
- ++ if (!ar->wmi.ops->gen_sta_keepalive)
- ++ return -EOPNOTSUPP;
- ++
- ++ skb = ar->wmi.ops->gen_sta_keepalive(ar, arg);
- ++ if (IS_ERR(skb))
- ++ return PTR_ERR(skb);
- ++
- ++ cmd_id = ar->wmi.cmd->sta_keepalive_cmd;
- ++ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
- ++}
- ++
- ++#endif
- +--- /dev/null
- ++++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
- +@@ -0,0 +1,2796 @@
- ++/*
- ++ * Copyright (c) 2005-2011 Atheros Communications Inc.
- ++ * Copyright (c) 2011-2014 Qualcomm Atheros, Inc.
- ++ *
- ++ * Permission to use, copy, modify, and/or distribute this software for any
- ++ * purpose with or without fee is hereby granted, provided that the above
- ++ * copyright notice and this permission notice appear in all copies.
- ++ *
- ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ++ */
- ++#include "core.h"
- ++#include "debug.h"
- ++#include "hw.h"
- ++#include "wmi.h"
- ++#include "wmi-ops.h"
- ++#include "wmi-tlv.h"
- ++
- ++/***************/
- ++/* TLV helpers */
- ++/**************/
- ++
- ++struct wmi_tlv_policy {
- ++ size_t min_len;
- ++};
- ++
- ++static const struct wmi_tlv_policy wmi_tlv_policies[] = {
- ++ [WMI_TLV_TAG_ARRAY_BYTE]
- ++ = { .min_len = sizeof(u8) },
- ++ [WMI_TLV_TAG_ARRAY_UINT32]
- ++ = { .min_len = sizeof(u32) },
- ++ [WMI_TLV_TAG_STRUCT_SCAN_EVENT]
- ++ = { .min_len = sizeof(struct wmi_scan_event) },
- ++ [WMI_TLV_TAG_STRUCT_MGMT_RX_HDR]
- ++ = { .min_len = sizeof(struct wmi_tlv_mgmt_rx_ev) },
- ++ [WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT]
- ++ = { .min_len = sizeof(struct wmi_chan_info_event) },
- ++ [WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT]
- ++ = { .min_len = sizeof(struct wmi_vdev_start_response_event) },
- ++ [WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT]
- ++ = { .min_len = sizeof(struct wmi_peer_sta_kickout_event) },
- ++ [WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT]
- ++ = { .min_len = sizeof(struct wmi_host_swba_event) },
- ++ [WMI_TLV_TAG_STRUCT_TIM_INFO]
- ++ = { .min_len = sizeof(struct wmi_tim_info) },
- ++ [WMI_TLV_TAG_STRUCT_P2P_NOA_INFO]
- ++ = { .min_len = sizeof(struct wmi_p2p_noa_info) },
- ++ [WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT]
- ++ = { .min_len = sizeof(struct wmi_tlv_svc_rdy_ev) },
- ++ [WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES]
- ++ = { .min_len = sizeof(struct hal_reg_capabilities) },
- ++ [WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ]
- ++ = { .min_len = sizeof(struct wlan_host_mem_req) },
- ++ [WMI_TLV_TAG_STRUCT_READY_EVENT]
- ++ = { .min_len = sizeof(struct wmi_tlv_rdy_ev) },
- ++ [WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT]
- ++ = { .min_len = sizeof(struct wmi_tlv_bcn_tx_status_ev) },
- ++ [WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT]
- ++ = { .min_len = sizeof(struct wmi_tlv_diag_data_ev) },
- ++};
- ++
- ++static int
- ++ath10k_wmi_tlv_iter(struct ath10k *ar, const void *ptr, size_t len,
- ++ int (*iter)(struct ath10k *ar, u16 tag, u16 len,
- ++ const void *ptr, void *data),
- ++ void *data)
- ++{
- ++ const void *begin = ptr;
- ++ const struct wmi_tlv *tlv;
- ++ u16 tlv_tag, tlv_len;
- ++ int ret;
- ++
- ++ while (len > 0) {
- ++ if (len < sizeof(*tlv)) {
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n",
- ++ ptr - begin, len, sizeof(*tlv));
- ++ return -EINVAL;
- ++ }
- ++
- ++ tlv = ptr;
- ++ tlv_tag = __le16_to_cpu(tlv->tag);
- ++ tlv_len = __le16_to_cpu(tlv->len);
- ++ ptr += sizeof(*tlv);
- ++ len -= sizeof(*tlv);
- ++
- ++ if (tlv_len > len) {
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi tlv parse failure of tag %hhu at byte %zd (%zu bytes left, %hhu expected)\n",
- ++ tlv_tag, ptr - begin, len, tlv_len);
- ++ return -EINVAL;
- ++ }
- ++
- ++ if (tlv_tag < ARRAY_SIZE(wmi_tlv_policies) &&
- ++ wmi_tlv_policies[tlv_tag].min_len &&
- ++ wmi_tlv_policies[tlv_tag].min_len > tlv_len) {
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi tlv parse failure of tag %hhu at byte %zd (%hhu bytes is less than min length %zu)\n",
- ++ tlv_tag, ptr - begin, tlv_len,
- ++ wmi_tlv_policies[tlv_tag].min_len);
- ++ return -EINVAL;
- ++ }
- ++
- ++ ret = iter(ar, tlv_tag, tlv_len, ptr, data);
- ++ if (ret)
- ++ return ret;
- ++
- ++ ptr += tlv_len;
- ++ len -= tlv_len;
- ++ }
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_wmi_tlv_iter_parse(struct ath10k *ar, u16 tag, u16 len,
- ++ const void *ptr, void *data)
- ++{
- ++ const void **tb = data;
- ++
- ++ if (tag < WMI_TLV_TAG_MAX)
- ++ tb[tag] = ptr;
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_wmi_tlv_parse(struct ath10k *ar, const void **tb,
- ++ const void *ptr, size_t len)
- ++{
- ++ return ath10k_wmi_tlv_iter(ar, ptr, len, ath10k_wmi_tlv_iter_parse,
- ++ (void *)tb);
- ++}
- ++
- ++static const void **
- ++ath10k_wmi_tlv_parse_alloc(struct ath10k *ar, const void *ptr,
- ++ size_t len, gfp_t gfp)
- ++{
- ++ const void **tb;
- ++ int ret;
- ++
- ++ tb = kzalloc(sizeof(*tb) * WMI_TLV_TAG_MAX, gfp);
- ++ if (!tb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ret = ath10k_wmi_tlv_parse(ar, tb, ptr, len);
- ++ if (ret) {
- ++ kfree(tb);
- ++ return ERR_PTR(ret);
- ++ }
- ++
- ++ return tb;
- ++}
- ++
- ++static u16 ath10k_wmi_tlv_len(const void *ptr)
- ++{
- ++ return __le16_to_cpu((((const struct wmi_tlv *)ptr) - 1)->len);
- ++}
- ++
- ++/**************/
- ++/* TLV events */
- ++/**************/
- ++static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar,
- ++ struct sk_buff *skb)
- ++{
- ++ const void **tb;
- ++ const struct wmi_tlv_bcn_tx_status_ev *ev;
- ++ u32 vdev_id, tx_status;
- ++ int ret;
- ++
- ++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
- ++ if (IS_ERR(tb)) {
- ++ ret = PTR_ERR(tb);
- ++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ev = tb[WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT];
- ++ if (!ev) {
- ++ kfree(tb);
- ++ return -EPROTO;
- ++ }
- ++
- ++ tx_status = __le32_to_cpu(ev->tx_status);
- ++ vdev_id = __le32_to_cpu(ev->vdev_id);
- ++
- ++ switch (tx_status) {
- ++ case WMI_TLV_BCN_TX_STATUS_OK:
- ++ break;
- ++ case WMI_TLV_BCN_TX_STATUS_XRETRY:
- ++ case WMI_TLV_BCN_TX_STATUS_DROP:
- ++ case WMI_TLV_BCN_TX_STATUS_FILTERED:
- ++ /* FIXME: It's probably worth telling mac80211 to stop the
- ++ * interface as it is crippled.
- ++ */
- ++ ath10k_warn(ar, "received bcn tmpl tx status on vdev %i: %d",
- ++ vdev_id, tx_status);
- ++ break;
- ++ }
- ++
- ++ kfree(tb);
- ++ return 0;
- ++}
- ++
- ++static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar,
- ++ struct sk_buff *skb)
- ++{
- ++ const void **tb;
- ++ const struct wmi_tlv_diag_data_ev *ev;
- ++ const struct wmi_tlv_diag_item *item;
- ++ const void *data;
- ++ int ret, num_items, len;
- ++
- ++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
- ++ if (IS_ERR(tb)) {
- ++ ret = PTR_ERR(tb);
- ++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ev = tb[WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT];
- ++ data = tb[WMI_TLV_TAG_ARRAY_BYTE];
- ++ if (!ev || !data) {
- ++ kfree(tb);
- ++ return -EPROTO;
- ++ }
- ++
- ++ num_items = __le32_to_cpu(ev->num_items);
- ++ len = ath10k_wmi_tlv_len(data);
- ++
- ++ while (num_items--) {
- ++ if (len == 0)
- ++ break;
- ++ if (len < sizeof(*item)) {
- ++ ath10k_warn(ar, "failed to parse diag data: can't fit item header\n");
- ++ break;
- ++ }
- ++
- ++ item = data;
- ++
- ++ if (len < sizeof(*item) + __le16_to_cpu(item->len)) {
- ++ ath10k_warn(ar, "failed to parse diag data: item is too long\n");
- ++ break;
- ++ }
- ++
- ++ trace_ath10k_wmi_diag_container(ar,
- ++ item->type,
- ++ __le32_to_cpu(item->timestamp),
- ++ __le32_to_cpu(item->code),
- ++ __le16_to_cpu(item->len),
- ++ item->payload);
- ++
- ++ len -= sizeof(*item);
- ++ len -= roundup(__le16_to_cpu(item->len), 4);
- ++
- ++ data += sizeof(*item);
- ++ data += roundup(__le16_to_cpu(item->len), 4);
- ++ }
- ++
- ++ if (num_items != -1 || len != 0)
- ++ ath10k_warn(ar, "failed to parse diag data event: num_items %d len %d\n",
- ++ num_items, len);
- ++
- ++ kfree(tb);
- ++ return 0;
- ++}
- ++
- ++static int ath10k_wmi_tlv_event_diag(struct ath10k *ar,
- ++ struct sk_buff *skb)
- ++{
- ++ const void **tb;
- ++ const void *data;
- ++ int ret, len;
- ++
- ++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
- ++ if (IS_ERR(tb)) {
- ++ ret = PTR_ERR(tb);
- ++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ data = tb[WMI_TLV_TAG_ARRAY_BYTE];
- ++ if (!data) {
- ++ kfree(tb);
- ++ return -EPROTO;
- ++ }
- ++ len = ath10k_wmi_tlv_len(data);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv diag event len %d\n", len);
- ++ trace_ath10k_wmi_diag(ar, data, len);
- ++
- ++ kfree(tb);
- ++ return 0;
- ++}
- ++
- ++/***********/
- ++/* TLV ops */
- ++/***********/
- ++
- ++static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
- ++{
- ++ struct wmi_cmd_hdr *cmd_hdr;
- ++ enum wmi_tlv_event_id id;
- ++
- ++ cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
- ++ id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
- ++
- ++ if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
- ++ return;
- ++
- ++ trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
- ++
- ++ switch (id) {
- ++ case WMI_TLV_MGMT_RX_EVENTID:
- ++ ath10k_wmi_event_mgmt_rx(ar, skb);
- ++ /* mgmt_rx() owns the skb now! */
- ++ return;
- ++ case WMI_TLV_SCAN_EVENTID:
- ++ ath10k_wmi_event_scan(ar, skb);
- ++ break;
- ++ case WMI_TLV_CHAN_INFO_EVENTID:
- ++ ath10k_wmi_event_chan_info(ar, skb);
- ++ break;
- ++ case WMI_TLV_ECHO_EVENTID:
- ++ ath10k_wmi_event_echo(ar, skb);
- ++ break;
- ++ case WMI_TLV_DEBUG_MESG_EVENTID:
- ++ ath10k_wmi_event_debug_mesg(ar, skb);
- ++ break;
- ++ case WMI_TLV_UPDATE_STATS_EVENTID:
- ++ ath10k_wmi_event_update_stats(ar, skb);
- ++ break;
- ++ case WMI_TLV_VDEV_START_RESP_EVENTID:
- ++ ath10k_wmi_event_vdev_start_resp(ar, skb);
- ++ break;
- ++ case WMI_TLV_VDEV_STOPPED_EVENTID:
- ++ ath10k_wmi_event_vdev_stopped(ar, skb);
- ++ break;
- ++ case WMI_TLV_PEER_STA_KICKOUT_EVENTID:
- ++ ath10k_wmi_event_peer_sta_kickout(ar, skb);
- ++ break;
- ++ case WMI_TLV_HOST_SWBA_EVENTID:
- ++ ath10k_wmi_event_host_swba(ar, skb);
- ++ break;
- ++ case WMI_TLV_TBTTOFFSET_UPDATE_EVENTID:
- ++ ath10k_wmi_event_tbttoffset_update(ar, skb);
- ++ break;
- ++ case WMI_TLV_PHYERR_EVENTID:
- ++ ath10k_wmi_event_phyerr(ar, skb);
- ++ break;
- ++ case WMI_TLV_ROAM_EVENTID:
- ++ ath10k_wmi_event_roam(ar, skb);
- ++ break;
- ++ case WMI_TLV_PROFILE_MATCH:
- ++ ath10k_wmi_event_profile_match(ar, skb);
- ++ break;
- ++ case WMI_TLV_DEBUG_PRINT_EVENTID:
- ++ ath10k_wmi_event_debug_print(ar, skb);
- ++ break;
- ++ case WMI_TLV_PDEV_QVIT_EVENTID:
- ++ ath10k_wmi_event_pdev_qvit(ar, skb);
- ++ break;
- ++ case WMI_TLV_WLAN_PROFILE_DATA_EVENTID:
- ++ ath10k_wmi_event_wlan_profile_data(ar, skb);
- ++ break;
- ++ case WMI_TLV_RTT_MEASUREMENT_REPORT_EVENTID:
- ++ ath10k_wmi_event_rtt_measurement_report(ar, skb);
- ++ break;
- ++ case WMI_TLV_TSF_MEASUREMENT_REPORT_EVENTID:
- ++ ath10k_wmi_event_tsf_measurement_report(ar, skb);
- ++ break;
- ++ case WMI_TLV_RTT_ERROR_REPORT_EVENTID:
- ++ ath10k_wmi_event_rtt_error_report(ar, skb);
- ++ break;
- ++ case WMI_TLV_WOW_WAKEUP_HOST_EVENTID:
- ++ ath10k_wmi_event_wow_wakeup_host(ar, skb);
- ++ break;
- ++ case WMI_TLV_DCS_INTERFERENCE_EVENTID:
- ++ ath10k_wmi_event_dcs_interference(ar, skb);
- ++ break;
- ++ case WMI_TLV_PDEV_TPC_CONFIG_EVENTID:
- ++ ath10k_wmi_event_pdev_tpc_config(ar, skb);
- ++ break;
- ++ case WMI_TLV_PDEV_FTM_INTG_EVENTID:
- ++ ath10k_wmi_event_pdev_ftm_intg(ar, skb);
- ++ break;
- ++ case WMI_TLV_GTK_OFFLOAD_STATUS_EVENTID:
- ++ ath10k_wmi_event_gtk_offload_status(ar, skb);
- ++ break;
- ++ case WMI_TLV_GTK_REKEY_FAIL_EVENTID:
- ++ ath10k_wmi_event_gtk_rekey_fail(ar, skb);
- ++ break;
- ++ case WMI_TLV_TX_DELBA_COMPLETE_EVENTID:
- ++ ath10k_wmi_event_delba_complete(ar, skb);
- ++ break;
- ++ case WMI_TLV_TX_ADDBA_COMPLETE_EVENTID:
- ++ ath10k_wmi_event_addba_complete(ar, skb);
- ++ break;
- ++ case WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID:
- ++ ath10k_wmi_event_vdev_install_key_complete(ar, skb);
- ++ break;
- ++ case WMI_TLV_SERVICE_READY_EVENTID:
- ++ ath10k_wmi_event_service_ready(ar, skb);
- ++ break;
- ++ case WMI_TLV_READY_EVENTID:
- ++ ath10k_wmi_event_ready(ar, skb);
- ++ break;
- ++ case WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID:
- ++ ath10k_wmi_tlv_event_bcn_tx_status(ar, skb);
- ++ break;
- ++ case WMI_TLV_DIAG_DATA_CONTAINER_EVENTID:
- ++ ath10k_wmi_tlv_event_diag_data(ar, skb);
- ++ break;
- ++ case WMI_TLV_DIAG_EVENTID:
- ++ ath10k_wmi_tlv_event_diag(ar, skb);
- ++ break;
- ++ default:
- ++ ath10k_warn(ar, "Unknown eventid: %d\n", id);
- ++ break;
- ++ }
- ++
- ++ dev_kfree_skb(skb);
- ++}
- ++
- ++static int ath10k_wmi_tlv_op_pull_scan_ev(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct wmi_scan_ev_arg *arg)
- ++{
- ++ const void **tb;
- ++ const struct wmi_scan_event *ev;
- ++ int ret;
- ++
- ++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
- ++ if (IS_ERR(tb)) {
- ++ ret = PTR_ERR(tb);
- ++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ev = tb[WMI_TLV_TAG_STRUCT_SCAN_EVENT];
- ++ if (!ev) {
- ++ kfree(tb);
- ++ return -EPROTO;
- ++ }
- ++
- ++ arg->event_type = ev->event_type;
- ++ arg->reason = ev->reason;
- ++ arg->channel_freq = ev->channel_freq;
- ++ arg->scan_req_id = ev->scan_req_id;
- ++ arg->scan_id = ev->scan_id;
- ++ arg->vdev_id = ev->vdev_id;
- ++
- ++ kfree(tb);
- ++ return 0;
- ++}
- ++
- ++static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct wmi_mgmt_rx_ev_arg *arg)
- ++{
- ++ const void **tb;
- ++ const struct wmi_tlv_mgmt_rx_ev *ev;
- ++ const u8 *frame;
- ++ u32 msdu_len;
- ++ int ret;
- ++
- ++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
- ++ if (IS_ERR(tb)) {
- ++ ret = PTR_ERR(tb);
- ++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ev = tb[WMI_TLV_TAG_STRUCT_MGMT_RX_HDR];
- ++ frame = tb[WMI_TLV_TAG_ARRAY_BYTE];
- ++
- ++ if (!ev || !frame) {
- ++ kfree(tb);
- ++ return -EPROTO;
- ++ }
- ++
- ++ arg->channel = ev->channel;
- ++ arg->buf_len = ev->buf_len;
- ++ arg->status = ev->status;
- ++ arg->snr = ev->snr;
- ++ arg->phy_mode = ev->phy_mode;
- ++ arg->rate = ev->rate;
- ++
- ++ msdu_len = __le32_to_cpu(arg->buf_len);
- ++
- ++ if (skb->len < (frame - skb->data) + msdu_len) {
- ++ kfree(tb);
- ++ return -EPROTO;
- ++ }
- ++
- ++ /* shift the sk_buff to point to `frame` */
- ++ skb_trim(skb, 0);
- ++ skb_put(skb, frame - skb->data);
- ++ skb_pull(skb, frame - skb->data);
- ++ skb_put(skb, msdu_len);
- ++
- ++ kfree(tb);
- ++ return 0;
- ++}
- ++
- ++static int ath10k_wmi_tlv_op_pull_ch_info_ev(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct wmi_ch_info_ev_arg *arg)
- ++{
- ++ const void **tb;
- ++ const struct wmi_chan_info_event *ev;
- ++ int ret;
- ++
- ++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
- ++ if (IS_ERR(tb)) {
- ++ ret = PTR_ERR(tb);
- ++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ev = tb[WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT];
- ++ if (!ev) {
- ++ kfree(tb);
- ++ return -EPROTO;
- ++ }
- ++
- ++ arg->err_code = ev->err_code;
- ++ arg->freq = ev->freq;
- ++ arg->cmd_flags = ev->cmd_flags;
- ++ arg->noise_floor = ev->noise_floor;
- ++ arg->rx_clear_count = ev->rx_clear_count;
- ++ arg->cycle_count = ev->cycle_count;
- ++
- ++ kfree(tb);
- ++ return 0;
- ++}
- ++
- ++static int
- ++ath10k_wmi_tlv_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb,
- ++ struct wmi_vdev_start_ev_arg *arg)
- ++{
- ++ const void **tb;
- ++ const struct wmi_vdev_start_response_event *ev;
- ++ int ret;
- ++
- ++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
- ++ if (IS_ERR(tb)) {
- ++ ret = PTR_ERR(tb);
- ++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ev = tb[WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT];
- ++ if (!ev) {
- ++ kfree(tb);
- ++ return -EPROTO;
- ++ }
- ++
- ++ skb_pull(skb, sizeof(*ev));
- ++ arg->vdev_id = ev->vdev_id;
- ++ arg->req_id = ev->req_id;
- ++ arg->resp_type = ev->resp_type;
- ++ arg->status = ev->status;
- ++
- ++ kfree(tb);
- ++ return 0;
- ++}
- ++
- ++static int ath10k_wmi_tlv_op_pull_peer_kick_ev(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct wmi_peer_kick_ev_arg *arg)
- ++{
- ++ const void **tb;
- ++ const struct wmi_peer_sta_kickout_event *ev;
- ++ int ret;
- ++
- ++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
- ++ if (IS_ERR(tb)) {
- ++ ret = PTR_ERR(tb);
- ++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ev = tb[WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT];
- ++ if (!ev) {
- ++ kfree(tb);
- ++ return -EPROTO;
- ++ }
- ++
- ++ arg->mac_addr = ev->peer_macaddr.addr;
- ++
- ++ kfree(tb);
- ++ return 0;
- ++}
- ++
- ++struct wmi_tlv_swba_parse {
- ++ const struct wmi_host_swba_event *ev;
- ++ bool tim_done;
- ++ bool noa_done;
- ++ size_t n_tim;
- ++ size_t n_noa;
- ++ struct wmi_swba_ev_arg *arg;
- ++};
- ++
- ++static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len,
- ++ const void *ptr, void *data)
- ++{
- ++ struct wmi_tlv_swba_parse *swba = data;
- ++
- ++ if (tag != WMI_TLV_TAG_STRUCT_TIM_INFO)
- ++ return -EPROTO;
- ++
- ++ if (swba->n_tim >= ARRAY_SIZE(swba->arg->tim_info))
- ++ return -ENOBUFS;
- ++
- ++ swba->arg->tim_info[swba->n_tim++] = ptr;
- ++ return 0;
- ++}
- ++
- ++static int ath10k_wmi_tlv_swba_noa_parse(struct ath10k *ar, u16 tag, u16 len,
- ++ const void *ptr, void *data)
- ++{
- ++ struct wmi_tlv_swba_parse *swba = data;
- ++
- ++ if (tag != WMI_TLV_TAG_STRUCT_P2P_NOA_INFO)
- ++ return -EPROTO;
- ++
- ++ if (swba->n_noa >= ARRAY_SIZE(swba->arg->noa_info))
- ++ return -ENOBUFS;
- ++
- ++ swba->arg->noa_info[swba->n_noa++] = ptr;
- ++ return 0;
- ++}
- ++
- ++static int ath10k_wmi_tlv_swba_parse(struct ath10k *ar, u16 tag, u16 len,
- ++ const void *ptr, void *data)
- ++{
- ++ struct wmi_tlv_swba_parse *swba = data;
- ++ int ret;
- ++
- ++ switch (tag) {
- ++ case WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT:
- ++ swba->ev = ptr;
- ++ break;
- ++ case WMI_TLV_TAG_ARRAY_STRUCT:
- ++ if (!swba->tim_done) {
- ++ swba->tim_done = true;
- ++ ret = ath10k_wmi_tlv_iter(ar, ptr, len,
- ++ ath10k_wmi_tlv_swba_tim_parse,
- ++ swba);
- ++ if (ret)
- ++ return ret;
- ++ } else if (!swba->noa_done) {
- ++ swba->noa_done = true;
- ++ ret = ath10k_wmi_tlv_iter(ar, ptr, len,
- ++ ath10k_wmi_tlv_swba_noa_parse,
- ++ swba);
- ++ if (ret)
- ++ return ret;
- ++ }
- ++ break;
- ++ default:
- ++ break;
- ++ }
- ++ return 0;
- ++}
- ++
- ++static int ath10k_wmi_tlv_op_pull_swba_ev(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct wmi_swba_ev_arg *arg)
- ++{
- ++ struct wmi_tlv_swba_parse swba = { .arg = arg };
- ++ u32 map;
- ++ size_t n_vdevs;
- ++ int ret;
- ++
- ++ ret = ath10k_wmi_tlv_iter(ar, skb->data, skb->len,
- ++ ath10k_wmi_tlv_swba_parse, &swba);
- ++ if (ret) {
- ++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ if (!swba.ev)
- ++ return -EPROTO;
- ++
- ++ arg->vdev_map = swba.ev->vdev_map;
- ++
- ++ for (map = __le32_to_cpu(arg->vdev_map), n_vdevs = 0; map; map >>= 1)
- ++ if (map & BIT(0))
- ++ n_vdevs++;
- ++
- ++ if (n_vdevs != swba.n_tim ||
- ++ n_vdevs != swba.n_noa)
- ++ return -EPROTO;
- ++
- ++ return 0;
- ++}
- ++
- ++static int ath10k_wmi_tlv_op_pull_phyerr_ev(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct wmi_phyerr_ev_arg *arg)
- ++{
- ++ const void **tb;
- ++ const struct wmi_tlv_phyerr_ev *ev;
- ++ const void *phyerrs;
- ++ int ret;
- ++
- ++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
- ++ if (IS_ERR(tb)) {
- ++ ret = PTR_ERR(tb);
- ++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ev = tb[WMI_TLV_TAG_STRUCT_COMB_PHYERR_RX_HDR];
- ++ phyerrs = tb[WMI_TLV_TAG_ARRAY_BYTE];
- ++
- ++ if (!ev || !phyerrs) {
- ++ kfree(tb);
- ++ return -EPROTO;
- ++ }
- ++
- ++ arg->num_phyerrs = ev->num_phyerrs;
- ++ arg->tsf_l32 = ev->tsf_l32;
- ++ arg->tsf_u32 = ev->tsf_u32;
- ++ arg->buf_len = ev->buf_len;
- ++ arg->phyerrs = phyerrs;
- ++
- ++ kfree(tb);
- ++ return 0;
- ++}
- ++
- ++#define WMI_TLV_ABI_VER_NS0 0x5F414351
- ++#define WMI_TLV_ABI_VER_NS1 0x00004C4D
- ++#define WMI_TLV_ABI_VER_NS2 0x00000000
- ++#define WMI_TLV_ABI_VER_NS3 0x00000000
- ++
- ++#define WMI_TLV_ABI_VER0_MAJOR 1
- ++#define WMI_TLV_ABI_VER0_MINOR 0
- ++#define WMI_TLV_ABI_VER0 ((((WMI_TLV_ABI_VER0_MAJOR) << 24) & 0xFF000000) | \
- ++ (((WMI_TLV_ABI_VER0_MINOR) << 0) & 0x00FFFFFF))
- ++#define WMI_TLV_ABI_VER1 53
- ++
- ++static int
- ++ath10k_wmi_tlv_parse_mem_reqs(struct ath10k *ar, u16 tag, u16 len,
- ++ const void *ptr, void *data)
- ++{
- ++ struct wmi_svc_rdy_ev_arg *arg = data;
- ++ int i;
- ++
- ++ if (tag != WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ)
- ++ return -EPROTO;
- ++
- ++ for (i = 0; i < ARRAY_SIZE(arg->mem_reqs); i++) {
- ++ if (!arg->mem_reqs[i]) {
- ++ arg->mem_reqs[i] = ptr;
- ++ return 0;
- ++ }
- ++ }
- ++
- ++ return -ENOMEM;
- ++}
- ++
- ++static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct wmi_svc_rdy_ev_arg *arg)
- ++{
- ++ const void **tb;
- ++ const struct hal_reg_capabilities *reg;
- ++ const struct wmi_tlv_svc_rdy_ev *ev;
- ++ const __le32 *svc_bmap;
- ++ const struct wlan_host_mem_req *mem_reqs;
- ++ int ret;
- ++
- ++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
- ++ if (IS_ERR(tb)) {
- ++ ret = PTR_ERR(tb);
- ++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ev = tb[WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT];
- ++ reg = tb[WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES];
- ++ svc_bmap = tb[WMI_TLV_TAG_ARRAY_UINT32];
- ++ mem_reqs = tb[WMI_TLV_TAG_ARRAY_STRUCT];
- ++
- ++ if (!ev || !reg || !svc_bmap || !mem_reqs) {
- ++ kfree(tb);
- ++ return -EPROTO;
- ++ }
- ++
- ++ /* This is an internal ABI compatibility check for WMI TLV so check it
- ++ * here instead of the generic WMI code.
- ++ */
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi tlv abi 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x\n",
- ++ __le32_to_cpu(ev->abi.abi_ver0), WMI_TLV_ABI_VER0,
- ++ __le32_to_cpu(ev->abi.abi_ver_ns0), WMI_TLV_ABI_VER_NS0,
- ++ __le32_to_cpu(ev->abi.abi_ver_ns1), WMI_TLV_ABI_VER_NS1,
- ++ __le32_to_cpu(ev->abi.abi_ver_ns2), WMI_TLV_ABI_VER_NS2,
- ++ __le32_to_cpu(ev->abi.abi_ver_ns3), WMI_TLV_ABI_VER_NS3);
- ++
- ++ if (__le32_to_cpu(ev->abi.abi_ver0) != WMI_TLV_ABI_VER0 ||
- ++ __le32_to_cpu(ev->abi.abi_ver_ns0) != WMI_TLV_ABI_VER_NS0 ||
- ++ __le32_to_cpu(ev->abi.abi_ver_ns1) != WMI_TLV_ABI_VER_NS1 ||
- ++ __le32_to_cpu(ev->abi.abi_ver_ns2) != WMI_TLV_ABI_VER_NS2 ||
- ++ __le32_to_cpu(ev->abi.abi_ver_ns3) != WMI_TLV_ABI_VER_NS3) {
- ++ kfree(tb);
- ++ return -ENOTSUPP;
- ++ }
- ++
- ++ arg->min_tx_power = ev->hw_min_tx_power;
- ++ arg->max_tx_power = ev->hw_max_tx_power;
- ++ arg->ht_cap = ev->ht_cap_info;
- ++ arg->vht_cap = ev->vht_cap_info;
- ++ arg->sw_ver0 = ev->abi.abi_ver0;
- ++ arg->sw_ver1 = ev->abi.abi_ver1;
- ++ arg->fw_build = ev->fw_build_vers;
- ++ arg->phy_capab = ev->phy_capability;
- ++ arg->num_rf_chains = ev->num_rf_chains;
- ++ arg->eeprom_rd = reg->eeprom_rd;
- ++ arg->num_mem_reqs = ev->num_mem_reqs;
- ++ arg->service_map = svc_bmap;
- ++ arg->service_map_len = ath10k_wmi_tlv_len(svc_bmap);
- ++
- ++ ret = ath10k_wmi_tlv_iter(ar, mem_reqs, ath10k_wmi_tlv_len(mem_reqs),
- ++ ath10k_wmi_tlv_parse_mem_reqs, arg);
- ++ if (ret) {
- ++ kfree(tb);
- ++ ath10k_warn(ar, "failed to parse mem_reqs tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ kfree(tb);
- ++ return 0;
- ++}
- ++
- ++static int ath10k_wmi_tlv_op_pull_rdy_ev(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct wmi_rdy_ev_arg *arg)
- ++{
- ++ const void **tb;
- ++ const struct wmi_tlv_rdy_ev *ev;
- ++ int ret;
- ++
- ++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
- ++ if (IS_ERR(tb)) {
- ++ ret = PTR_ERR(tb);
- ++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ev = tb[WMI_TLV_TAG_STRUCT_READY_EVENT];
- ++ if (!ev) {
- ++ kfree(tb);
- ++ return -EPROTO;
- ++ }
- ++
- ++ arg->sw_version = ev->abi.abi_ver0;
- ++ arg->abi_version = ev->abi.abi_ver1;
- ++ arg->status = ev->status;
- ++ arg->mac_addr = ev->mac_addr.addr;
- ++
- ++ kfree(tb);
- ++ return 0;
- ++}
- ++
- ++static void ath10k_wmi_tlv_pull_vdev_stats(const struct wmi_tlv_vdev_stats *src,
- ++ struct ath10k_fw_stats_vdev *dst)
- ++{
- ++ int i;
- ++
- ++ dst->vdev_id = __le32_to_cpu(src->vdev_id);
- ++ dst->beacon_snr = __le32_to_cpu(src->beacon_snr);
- ++ dst->data_snr = __le32_to_cpu(src->data_snr);
- ++ dst->num_rx_frames = __le32_to_cpu(src->num_rx_frames);
- ++ dst->num_rts_fail = __le32_to_cpu(src->num_rts_fail);
- ++ dst->num_rts_success = __le32_to_cpu(src->num_rts_success);
- ++ dst->num_rx_err = __le32_to_cpu(src->num_rx_err);
- ++ dst->num_rx_discard = __le32_to_cpu(src->num_rx_discard);
- ++ dst->num_tx_not_acked = __le32_to_cpu(src->num_tx_not_acked);
- ++
- ++ for (i = 0; i < ARRAY_SIZE(src->num_tx_frames); i++)
- ++ dst->num_tx_frames[i] =
- ++ __le32_to_cpu(src->num_tx_frames[i]);
- ++
- ++ for (i = 0; i < ARRAY_SIZE(src->num_tx_frames_retries); i++)
- ++ dst->num_tx_frames_retries[i] =
- ++ __le32_to_cpu(src->num_tx_frames_retries[i]);
- ++
- ++ for (i = 0; i < ARRAY_SIZE(src->num_tx_frames_failures); i++)
- ++ dst->num_tx_frames_failures[i] =
- ++ __le32_to_cpu(src->num_tx_frames_failures[i]);
- ++
- ++ for (i = 0; i < ARRAY_SIZE(src->tx_rate_history); i++)
- ++ dst->tx_rate_history[i] =
- ++ __le32_to_cpu(src->tx_rate_history[i]);
- ++
- ++ for (i = 0; i < ARRAY_SIZE(src->beacon_rssi_history); i++)
- ++ dst->beacon_rssi_history[i] =
- ++ __le32_to_cpu(src->beacon_rssi_history[i]);
- ++}
- ++
- ++static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar,
- ++ struct sk_buff *skb,
- ++ struct ath10k_fw_stats *stats)
- ++{
- ++ const void **tb;
- ++ const struct wmi_tlv_stats_ev *ev;
- ++ const void *data;
- ++ u32 num_pdev_stats;
- ++ u32 num_vdev_stats;
- ++ u32 num_peer_stats;
- ++ u32 num_bcnflt_stats;
- ++ u32 num_chan_stats;
- ++ size_t data_len;
- ++ int ret;
- ++ int i;
- ++
- ++ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
- ++ if (IS_ERR(tb)) {
- ++ ret = PTR_ERR(tb);
- ++ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
- ++ return ret;
- ++ }
- ++
- ++ ev = tb[WMI_TLV_TAG_STRUCT_STATS_EVENT];
- ++ data = tb[WMI_TLV_TAG_ARRAY_BYTE];
- ++
- ++ if (!ev || !data) {
- ++ kfree(tb);
- ++ return -EPROTO;
- ++ }
- ++
- ++ data_len = ath10k_wmi_tlv_len(data);
- ++ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
- ++ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
- ++ num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
- ++ num_bcnflt_stats = __le32_to_cpu(ev->num_bcnflt_stats);
- ++ num_chan_stats = __le32_to_cpu(ev->num_chan_stats);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi tlv stats update pdev %i vdev %i peer %i bcnflt %i chan %i\n",
- ++ num_pdev_stats, num_vdev_stats, num_peer_stats,
- ++ num_bcnflt_stats, num_chan_stats);
- ++
- ++ for (i = 0; i < num_pdev_stats; i++) {
- ++ const struct wmi_pdev_stats *src;
- ++ struct ath10k_fw_stats_pdev *dst;
- ++
- ++ src = data;
- ++ if (data_len < sizeof(*src))
- ++ return -EPROTO;
- ++
- ++ data += sizeof(*src);
- ++ data_len -= sizeof(*src);
- ++
- ++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
- ++ if (!dst)
- ++ continue;
- ++
- ++ ath10k_wmi_pull_pdev_stats_base(&src->base, dst);
- ++ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst);
- ++ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst);
- ++ list_add_tail(&dst->list, &stats->pdevs);
- ++ }
- ++
- ++ for (i = 0; i < num_vdev_stats; i++) {
- ++ const struct wmi_tlv_vdev_stats *src;
- ++ struct ath10k_fw_stats_vdev *dst;
- ++
- ++ src = data;
- ++ if (data_len < sizeof(*src))
- ++ return -EPROTO;
- ++
- ++ data += sizeof(*src);
- ++ data_len -= sizeof(*src);
- ++
- ++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
- ++ if (!dst)
- ++ continue;
- ++
- ++ ath10k_wmi_tlv_pull_vdev_stats(src, dst);
- ++ list_add_tail(&dst->list, &stats->vdevs);
- ++ }
- ++
- ++ for (i = 0; i < num_peer_stats; i++) {
- ++ const struct wmi_10x_peer_stats *src;
- ++ struct ath10k_fw_stats_peer *dst;
- ++
- ++ src = data;
- ++ if (data_len < sizeof(*src))
- ++ return -EPROTO;
- ++
- ++ data += sizeof(*src);
- ++ data_len -= sizeof(*src);
- ++
- ++ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
- ++ if (!dst)
- ++ continue;
- ++
- ++ ath10k_wmi_pull_peer_stats(&src->old, dst);
- ++ dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate);
- ++ list_add_tail(&dst->list, &stats->peers);
- ++ }
- ++
- ++ kfree(tb);
- ++ return 0;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_pdev_suspend(struct ath10k *ar, u32 opt)
- ++{
- ++ struct wmi_tlv_pdev_suspend *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SUSPEND_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->opt = __cpu_to_le32(opt);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev suspend\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_pdev_resume(struct ath10k *ar)
- ++{
- ++ struct wmi_tlv_resume_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_RESUME_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->reserved = __cpu_to_le32(0);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev resume\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_pdev_set_rd(struct ath10k *ar,
- ++ u16 rd, u16 rd2g, u16 rd5g,
- ++ u16 ctl2g, u16 ctl5g,
- ++ enum wmi_dfs_region dfs_reg)
- ++{
- ++ struct wmi_tlv_pdev_set_rd_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_REGDOMAIN_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->regd = __cpu_to_le32(rd);
- ++ cmd->regd_2ghz = __cpu_to_le32(rd2g);
- ++ cmd->regd_5ghz = __cpu_to_le32(rd5g);
- ++ cmd->conform_limit_2ghz = __cpu_to_le32(rd2g);
- ++ cmd->conform_limit_5ghz = __cpu_to_le32(rd5g);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set rd\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_pdev_set_param(struct ath10k *ar, u32 param_id,
- ++ u32 param_value)
- ++{
- ++ struct wmi_tlv_pdev_set_param_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_PARAM_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->param_id = __cpu_to_le32(param_id);
- ++ cmd->param_value = __cpu_to_le32(param_value);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set param\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
- ++{
- ++ struct sk_buff *skb;
- ++ struct wmi_tlv *tlv;
- ++ struct wmi_tlv_init_cmd *cmd;
- ++ struct wmi_tlv_resource_config *cfg;
- ++ struct wmi_host_mem_chunks *chunks;
- ++ size_t len, chunks_len;
- ++ void *ptr;
- ++
- ++ chunks_len = ar->wmi.num_mem_chunks * sizeof(struct host_memory_chunk);
- ++ len = (sizeof(*tlv) + sizeof(*cmd)) +
- ++ (sizeof(*tlv) + sizeof(*cfg)) +
- ++ (sizeof(*tlv) + chunks_len);
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = skb->data;
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_INIT_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_RESOURCE_CONFIG);
- ++ tlv->len = __cpu_to_le16(sizeof(*cfg));
- ++ cfg = (void *)tlv->value;
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cfg);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
- ++ tlv->len = __cpu_to_le16(chunks_len);
- ++ chunks = (void *)tlv->value;
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += chunks_len;
- ++
- ++ cmd->abi.abi_ver0 = __cpu_to_le32(WMI_TLV_ABI_VER0);
- ++ cmd->abi.abi_ver1 = __cpu_to_le32(WMI_TLV_ABI_VER1);
- ++ cmd->abi.abi_ver_ns0 = __cpu_to_le32(WMI_TLV_ABI_VER_NS0);
- ++ cmd->abi.abi_ver_ns1 = __cpu_to_le32(WMI_TLV_ABI_VER_NS1);
- ++ cmd->abi.abi_ver_ns2 = __cpu_to_le32(WMI_TLV_ABI_VER_NS2);
- ++ cmd->abi.abi_ver_ns3 = __cpu_to_le32(WMI_TLV_ABI_VER_NS3);
- ++ cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
- ++
- ++ cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
- ++ cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS);
- ++
- ++ if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) {
- ++ cfg->num_offload_peers = __cpu_to_le32(3);
- ++ cfg->num_offload_reorder_bufs = __cpu_to_le32(3);
- ++ } else {
- ++ cfg->num_offload_peers = __cpu_to_le32(0);
- ++ cfg->num_offload_reorder_bufs = __cpu_to_le32(0);
- ++ }
- ++
- ++ cfg->num_peer_keys = __cpu_to_le32(2);
- ++ cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS);
- ++ cfg->ast_skid_limit = __cpu_to_le32(0x10);
- ++ cfg->tx_chain_mask = __cpu_to_le32(0x7);
- ++ cfg->rx_chain_mask = __cpu_to_le32(0x7);
- ++ cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64);
- ++ cfg->rx_timeout_pri[1] = __cpu_to_le32(0x64);
- ++ cfg->rx_timeout_pri[2] = __cpu_to_le32(0x64);
- ++ cfg->rx_timeout_pri[3] = __cpu_to_le32(0x28);
- ++ cfg->rx_decap_mode = __cpu_to_le32(1);
- ++ cfg->scan_max_pending_reqs = __cpu_to_le32(4);
- ++ cfg->bmiss_offload_max_vdev = __cpu_to_le32(3);
- ++ cfg->roam_offload_max_vdev = __cpu_to_le32(3);
- ++ cfg->roam_offload_max_ap_profiles = __cpu_to_le32(8);
- ++ cfg->num_mcast_groups = __cpu_to_le32(0);
- ++ cfg->num_mcast_table_elems = __cpu_to_le32(0);
- ++ cfg->mcast2ucast_mode = __cpu_to_le32(0);
- ++ cfg->tx_dbg_log_size = __cpu_to_le32(0x400);
- ++ cfg->num_wds_entries = __cpu_to_le32(0x20);
- ++ cfg->dma_burst_size = __cpu_to_le32(0);
- ++ cfg->mac_aggr_delim = __cpu_to_le32(0);
- ++ cfg->rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(0);
- ++ cfg->vow_config = __cpu_to_le32(0);
- ++ cfg->gtk_offload_max_vdev = __cpu_to_le32(2);
- ++ cfg->num_msdu_desc = __cpu_to_le32(TARGET_TLV_NUM_MSDU_DESC);
- ++ cfg->max_frag_entries = __cpu_to_le32(2);
- ++ cfg->num_tdls_vdevs = __cpu_to_le32(1);
- ++ cfg->num_tdls_conn_table_entries = __cpu_to_le32(0x20);
- ++ cfg->beacon_tx_offload_max_vdev = __cpu_to_le32(2);
- ++ cfg->num_multicast_filter_entries = __cpu_to_le32(5);
- ++ cfg->num_wow_filters = __cpu_to_le32(0x16);
- ++ cfg->num_keep_alive_pattern = __cpu_to_le32(6);
- ++ cfg->keep_alive_pattern_size = __cpu_to_le32(0);
- ++ cfg->max_tdls_concurrent_sleep_sta = __cpu_to_le32(1);
- ++ cfg->max_tdls_concurrent_buffer_sta = __cpu_to_le32(1);
- ++
- ++ ath10k_wmi_put_host_mem_chunks(ar, chunks);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv init\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar,
- ++ const struct wmi_start_scan_arg *arg)
- ++{
- ++ struct wmi_tlv_start_scan_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ size_t len, chan_len, ssid_len, bssid_len, ie_len;
- ++ __le32 *chans;
- ++ struct wmi_ssid *ssids;
- ++ struct wmi_mac_addr *addrs;
- ++ void *ptr;
- ++ int i, ret;
- ++
- ++ ret = ath10k_wmi_start_scan_verify(arg);
- ++ if (ret)
- ++ return ERR_PTR(ret);
- ++
- ++ chan_len = arg->n_channels * sizeof(__le32);
- ++ ssid_len = arg->n_ssids * sizeof(struct wmi_ssid);
- ++ bssid_len = arg->n_bssids * sizeof(struct wmi_mac_addr);
- ++ ie_len = roundup(arg->ie_len, 4);
- ++ len = (sizeof(*tlv) + sizeof(*cmd)) +
- ++ (arg->n_channels ? sizeof(*tlv) + chan_len : 0) +
- ++ (arg->n_ssids ? sizeof(*tlv) + ssid_len : 0) +
- ++ (arg->n_bssids ? sizeof(*tlv) + bssid_len : 0) +
- ++ (arg->ie_len ? sizeof(*tlv) + ie_len : 0);
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_START_SCAN_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++
- ++ ath10k_wmi_put_start_scan_common(&cmd->common, arg);
- ++ cmd->burst_duration_ms = __cpu_to_le32(0);
- ++ cmd->num_channels = __cpu_to_le32(arg->n_channels);
- ++ cmd->num_ssids = __cpu_to_le32(arg->n_ssids);
- ++ cmd->num_bssids = __cpu_to_le32(arg->n_bssids);
- ++ cmd->ie_len = __cpu_to_le32(arg->ie_len);
- ++ cmd->num_probes = __cpu_to_le32(3);
- ++
- ++ /* FIXME: There are some scan flag inconsistencies across firmwares,
- ++ * e.g. WMI-TLV inverts the logic behind the following flag.
- ++ */
- ++ cmd->common.scan_ctrl_flags ^= __cpu_to_le32(WMI_SCAN_FILTER_PROBE_REQ);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32);
- ++ tlv->len = __cpu_to_le16(chan_len);
- ++ chans = (void *)tlv->value;
- ++ for (i = 0; i < arg->n_channels; i++)
- ++ chans[i] = __cpu_to_le32(arg->channels[i]);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += chan_len;
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_FIXED_STRUCT);
- ++ tlv->len = __cpu_to_le16(ssid_len);
- ++ ssids = (void *)tlv->value;
- ++ for (i = 0; i < arg->n_ssids; i++) {
- ++ ssids[i].ssid_len = __cpu_to_le32(arg->ssids[i].len);
- ++ memcpy(ssids[i].ssid, arg->ssids[i].ssid, arg->ssids[i].len);
- ++ }
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += ssid_len;
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_FIXED_STRUCT);
- ++ tlv->len = __cpu_to_le16(bssid_len);
- ++ addrs = (void *)tlv->value;
- ++ for (i = 0; i < arg->n_bssids; i++)
- ++ ether_addr_copy(addrs[i].addr, arg->bssids[i].bssid);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += bssid_len;
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
- ++ tlv->len = __cpu_to_le16(ie_len);
- ++ memcpy(tlv->value, arg->ie, arg->ie_len);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += ie_len;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv start scan\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_stop_scan(struct ath10k *ar,
- ++ const struct wmi_stop_scan_arg *arg)
- ++{
- ++ struct wmi_stop_scan_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ u32 scan_id;
- ++ u32 req_id;
- ++
- ++ if (arg->req_id > 0xFFF)
- ++ return ERR_PTR(-EINVAL);
- ++ if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF)
- ++ return ERR_PTR(-EINVAL);
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ scan_id = arg->u.scan_id;
- ++ scan_id |= WMI_HOST_SCAN_REQ_ID_PREFIX;
- ++
- ++ req_id = arg->req_id;
- ++ req_id |= WMI_HOST_SCAN_REQUESTOR_ID_PREFIX;
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STOP_SCAN_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->req_type = __cpu_to_le32(arg->req_type);
- ++ cmd->vdev_id = __cpu_to_le32(arg->u.vdev_id);
- ++ cmd->scan_id = __cpu_to_le32(scan_id);
- ++ cmd->scan_req_id = __cpu_to_le32(req_id);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv stop scan\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_vdev_create(struct ath10k *ar,
- ++ u32 vdev_id,
- ++ enum wmi_vdev_type vdev_type,
- ++ enum wmi_vdev_subtype vdev_subtype,
- ++ const u8 mac_addr[ETH_ALEN])
- ++{
- ++ struct wmi_vdev_create_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_CREATE_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->vdev_type = __cpu_to_le32(vdev_type);
- ++ cmd->vdev_subtype = __cpu_to_le32(vdev_subtype);
- ++ ether_addr_copy(cmd->vdev_macaddr.addr, mac_addr);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev create\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_vdev_delete(struct ath10k *ar, u32 vdev_id)
- ++{
- ++ struct wmi_vdev_delete_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_DELETE_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev delete\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar,
- ++ const struct wmi_vdev_start_request_arg *arg,
- ++ bool restart)
- ++{
- ++ struct wmi_tlv_vdev_start_cmd *cmd;
- ++ struct wmi_channel *ch;
- ++ struct wmi_p2p_noa_descriptor *noa;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ size_t len;
- ++ void *ptr;
- ++ u32 flags = 0;
- ++
- ++ if (WARN_ON(arg->ssid && arg->ssid_len == 0))
- ++ return ERR_PTR(-EINVAL);
- ++ if (WARN_ON(arg->hidden_ssid && !arg->ssid))
- ++ return ERR_PTR(-EINVAL);
- ++ if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))
- ++ return ERR_PTR(-EINVAL);
- ++
- ++ len = (sizeof(*tlv) + sizeof(*cmd)) +
- ++ (sizeof(*tlv) + sizeof(*ch)) +
- ++ (sizeof(*tlv) + 0);
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ if (arg->hidden_ssid)
- ++ flags |= WMI_VDEV_START_HIDDEN_SSID;
- ++ if (arg->pmf_enabled)
- ++ flags |= WMI_VDEV_START_PMF_ENABLED;
- ++
- ++ ptr = (void *)skb->data;
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_START_REQUEST_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
- ++ cmd->bcn_intval = __cpu_to_le32(arg->bcn_intval);
- ++ cmd->dtim_period = __cpu_to_le32(arg->dtim_period);
- ++ cmd->flags = __cpu_to_le32(flags);
- ++ cmd->bcn_tx_rate = __cpu_to_le32(arg->bcn_tx_rate);
- ++ cmd->bcn_tx_power = __cpu_to_le32(arg->bcn_tx_power);
- ++ cmd->disable_hw_ack = __cpu_to_le32(arg->disable_hw_ack);
- ++
- ++ if (arg->ssid) {
- ++ cmd->ssid.ssid_len = __cpu_to_le32(arg->ssid_len);
- ++ memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len);
- ++ }
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
- ++ tlv->len = __cpu_to_le16(sizeof(*ch));
- ++ ch = (void *)tlv->value;
- ++ ath10k_wmi_put_wmi_channel(ch, &arg->channel);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*ch);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
- ++ tlv->len = 0;
- ++ noa = (void *)tlv->value;
- ++
- ++ /* Note: This is a nested TLV containing:
- ++ * [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv]..
- ++ */
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += 0;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev start\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_vdev_stop(struct ath10k *ar, u32 vdev_id)
- ++{
- ++ struct wmi_vdev_stop_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_STOP_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev stop\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid,
- ++ const u8 *bssid)
- ++
- ++{
- ++ struct wmi_vdev_up_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_UP_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->vdev_assoc_id = __cpu_to_le32(aid);
- ++ ether_addr_copy(cmd->vdev_bssid.addr, bssid);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev up\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_vdev_down(struct ath10k *ar, u32 vdev_id)
- ++{
- ++ struct wmi_vdev_down_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_DOWN_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev down\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_vdev_set_param(struct ath10k *ar, u32 vdev_id,
- ++ u32 param_id, u32 param_value)
- ++{
- ++ struct wmi_vdev_set_param_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_SET_PARAM_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->param_id = __cpu_to_le32(param_id);
- ++ cmd->param_value = __cpu_to_le32(param_value);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev set param\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_vdev_install_key(struct ath10k *ar,
- ++ const struct wmi_vdev_install_key_arg *arg)
- ++{
- ++ struct wmi_vdev_install_key_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ size_t len;
- ++ void *ptr;
- ++
- ++ if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL)
- ++ return ERR_PTR(-EINVAL);
- ++ if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL)
- ++ return ERR_PTR(-EINVAL);
- ++
- ++ len = sizeof(*tlv) + sizeof(*cmd) +
- ++ sizeof(*tlv) + roundup(arg->key_len, sizeof(__le32));
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
- ++ cmd->key_idx = __cpu_to_le32(arg->key_idx);
- ++ cmd->key_flags = __cpu_to_le32(arg->key_flags);
- ++ cmd->key_cipher = __cpu_to_le32(arg->key_cipher);
- ++ cmd->key_len = __cpu_to_le32(arg->key_len);
- ++ cmd->key_txmic_len = __cpu_to_le32(arg->key_txmic_len);
- ++ cmd->key_rxmic_len = __cpu_to_le32(arg->key_rxmic_len);
- ++
- ++ if (arg->macaddr)
- ++ ether_addr_copy(cmd->peer_macaddr.addr, arg->macaddr);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
- ++ tlv->len = __cpu_to_le16(roundup(arg->key_len, sizeof(__le32)));
- ++ if (arg->key_data)
- ++ memcpy(tlv->value, arg->key_data, arg->key_len);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += roundup(arg->key_len, sizeof(__le32));
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev install key\n");
- ++ return skb;
- ++}
- ++
- ++static void *ath10k_wmi_tlv_put_uapsd_ac(struct ath10k *ar, void *ptr,
- ++ const struct wmi_sta_uapsd_auto_trig_arg *arg)
- ++{
- ++ struct wmi_sta_uapsd_auto_trig_param *ac;
- ++ struct wmi_tlv *tlv;
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_PARAM);
- ++ tlv->len = __cpu_to_le16(sizeof(*ac));
- ++ ac = (void *)tlv->value;
- ++
- ++ ac->wmm_ac = __cpu_to_le32(arg->wmm_ac);
- ++ ac->user_priority = __cpu_to_le32(arg->user_priority);
- ++ ac->service_interval = __cpu_to_le32(arg->service_interval);
- ++ ac->suspend_interval = __cpu_to_le32(arg->suspend_interval);
- ++ ac->delay_interval = __cpu_to_le32(arg->delay_interval);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI,
- ++ "wmi tlv vdev sta uapsd auto trigger ac %d prio %d svc int %d susp int %d delay int %d\n",
- ++ ac->wmm_ac, ac->user_priority, ac->service_interval,
- ++ ac->suspend_interval, ac->delay_interval);
- ++
- ++ return ptr + sizeof(*tlv) + sizeof(*ac);
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_vdev_sta_uapsd(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN],
- ++ const struct wmi_sta_uapsd_auto_trig_arg *args,
- ++ u32 num_ac)
- ++{
- ++ struct wmi_sta_uapsd_auto_trig_cmd_fixed_param *cmd;
- ++ struct wmi_sta_uapsd_auto_trig_param *ac;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ size_t len;
- ++ size_t ac_tlv_len;
- ++ void *ptr;
- ++ int i;
- ++
- ++ ac_tlv_len = num_ac * (sizeof(*tlv) + sizeof(*ac));
- ++ len = sizeof(*tlv) + sizeof(*cmd) +
- ++ sizeof(*tlv) + ac_tlv_len;
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->num_ac = __cpu_to_le32(num_ac);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
- ++ tlv->len = __cpu_to_le16(ac_tlv_len);
- ++ ac = (void *)tlv->value;
- ++
- ++ ptr += sizeof(*tlv);
- ++ for (i = 0; i < num_ac; i++)
- ++ ptr = ath10k_wmi_tlv_put_uapsd_ac(ar, ptr, &args[i]);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev sta uapsd auto trigger\n");
- ++ return skb;
- ++}
- ++
- ++static void *ath10k_wmi_tlv_put_wmm(void *ptr,
- ++ const struct wmi_wmm_params_arg *arg)
- ++{
- ++ struct wmi_wmm_params *wmm;
- ++ struct wmi_tlv *tlv;
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WMM_PARAMS);
- ++ tlv->len = __cpu_to_le16(sizeof(*wmm));
- ++ wmm = (void *)tlv->value;
- ++ ath10k_wmi_set_wmm_param(wmm, arg);
- ++
- ++ return ptr + sizeof(*tlv) + sizeof(*wmm);
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id,
- ++ const struct wmi_wmm_params_all_arg *arg)
- ++{
- ++ struct wmi_tlv_vdev_set_wmm_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ size_t len;
- ++ void *ptr;
- ++
- ++ len = sizeof(*tlv) + sizeof(*cmd);
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_SET_WMM_PARAMS_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++
- ++ ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[0].params, &arg->ac_be);
- ++ ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[1].params, &arg->ac_bk);
- ++ ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[2].params, &arg->ac_vi);
- ++ ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[3].params, &arg->ac_vo);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev wmm conf\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_sta_keepalive(struct ath10k *ar,
- ++ const struct wmi_sta_keepalive_arg *arg)
- ++{
- ++ struct wmi_tlv_sta_keepalive_cmd *cmd;
- ++ struct wmi_sta_keepalive_arp_resp *arp;
- ++ struct sk_buff *skb;
- ++ struct wmi_tlv *tlv;
- ++ void *ptr;
- ++ size_t len;
- ++
- ++ len = sizeof(*tlv) + sizeof(*cmd) +
- ++ sizeof(*tlv) + sizeof(*arp);
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_KEEPALIVE_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
- ++ cmd->enabled = __cpu_to_le32(arg->enabled);
- ++ cmd->method = __cpu_to_le32(arg->method);
- ++ cmd->interval = __cpu_to_le32(arg->interval);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_KEEPALVE_ARP_RESPONSE);
- ++ tlv->len = __cpu_to_le16(sizeof(*arp));
- ++ arp = (void *)tlv->value;
- ++
- ++ arp->src_ip4_addr = arg->src_ip4_addr;
- ++ arp->dest_ip4_addr = arg->dest_ip4_addr;
- ++ ether_addr_copy(arp->dest_mac_addr.addr, arg->dest_mac_addr);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv sta keepalive vdev %d enabled %d method %d inverval %d\n",
- ++ arg->vdev_id, arg->enabled, arg->method, arg->interval);
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN])
- ++{
- ++ struct wmi_tlv_peer_create_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_CREATE_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->peer_type = __cpu_to_le32(WMI_TLV_PEER_TYPE_DEFAULT); /* FIXME */
- ++ ether_addr_copy(cmd->peer_addr.addr, peer_addr);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer create\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_peer_delete(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN])
- ++{
- ++ struct wmi_peer_delete_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_DELETE_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer delete\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_peer_flush(struct ath10k *ar, u32 vdev_id,
- ++ const u8 peer_addr[ETH_ALEN], u32 tid_bitmap)
- ++{
- ++ struct wmi_peer_flush_tids_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_FLUSH_TIDS_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer flush\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id,
- ++ const u8 *peer_addr,
- ++ enum wmi_peer_param param_id,
- ++ u32 param_value)
- ++{
- ++ struct wmi_peer_set_param_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_SET_PARAM_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->param_id = __cpu_to_le32(param_id);
- ++ cmd->param_value = __cpu_to_le32(param_value);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer set param\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_peer_assoc(struct ath10k *ar,
- ++ const struct wmi_peer_assoc_complete_arg *arg)
- ++{
- ++ struct wmi_tlv_peer_assoc_cmd *cmd;
- ++ struct wmi_vht_rate_set *vht_rate;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ size_t len, legacy_rate_len, ht_rate_len;
- ++ void *ptr;
- ++
- ++ if (arg->peer_mpdu_density > 16)
- ++ return ERR_PTR(-EINVAL);
- ++ if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
- ++ return ERR_PTR(-EINVAL);
- ++ if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
- ++ return ERR_PTR(-EINVAL);
- ++
- ++ legacy_rate_len = roundup(arg->peer_legacy_rates.num_rates,
- ++ sizeof(__le32));
- ++ ht_rate_len = roundup(arg->peer_ht_rates.num_rates, sizeof(__le32));
- ++ len = (sizeof(*tlv) + sizeof(*cmd)) +
- ++ (sizeof(*tlv) + legacy_rate_len) +
- ++ (sizeof(*tlv) + ht_rate_len) +
- ++ (sizeof(*tlv) + sizeof(*vht_rate));
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_ASSOC_COMPLETE_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++
- ++ cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
- ++ cmd->new_assoc = __cpu_to_le32(arg->peer_reassoc ? 0 : 1);
- ++ cmd->assoc_id = __cpu_to_le32(arg->peer_aid);
- ++ cmd->flags = __cpu_to_le32(arg->peer_flags);
- ++ cmd->caps = __cpu_to_le32(arg->peer_caps);
- ++ cmd->listen_intval = __cpu_to_le32(arg->peer_listen_intval);
- ++ cmd->ht_caps = __cpu_to_le32(arg->peer_ht_caps);
- ++ cmd->max_mpdu = __cpu_to_le32(arg->peer_max_mpdu);
- ++ cmd->mpdu_density = __cpu_to_le32(arg->peer_mpdu_density);
- ++ cmd->rate_caps = __cpu_to_le32(arg->peer_rate_caps);
- ++ cmd->nss = __cpu_to_le32(arg->peer_num_spatial_streams);
- ++ cmd->vht_caps = __cpu_to_le32(arg->peer_vht_caps);
- ++ cmd->phy_mode = __cpu_to_le32(arg->peer_phymode);
- ++ cmd->num_legacy_rates = __cpu_to_le32(arg->peer_legacy_rates.num_rates);
- ++ cmd->num_ht_rates = __cpu_to_le32(arg->peer_ht_rates.num_rates);
- ++ ether_addr_copy(cmd->mac_addr.addr, arg->addr);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
- ++ tlv->len = __cpu_to_le16(legacy_rate_len);
- ++ memcpy(tlv->value, arg->peer_legacy_rates.rates,
- ++ arg->peer_legacy_rates.num_rates);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += legacy_rate_len;
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
- ++ tlv->len = __cpu_to_le16(ht_rate_len);
- ++ memcpy(tlv->value, arg->peer_ht_rates.rates,
- ++ arg->peer_ht_rates.num_rates);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += ht_rate_len;
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VHT_RATE_SET);
- ++ tlv->len = __cpu_to_le16(sizeof(*vht_rate));
- ++ vht_rate = (void *)tlv->value;
- ++
- ++ vht_rate->rx_max_rate = __cpu_to_le32(arg->peer_vht_rates.rx_max_rate);
- ++ vht_rate->rx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.rx_mcs_set);
- ++ vht_rate->tx_max_rate = __cpu_to_le32(arg->peer_vht_rates.tx_max_rate);
- ++ vht_rate->tx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*vht_rate);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer assoc\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id,
- ++ enum wmi_sta_ps_mode psmode)
- ++{
- ++ struct wmi_sta_powersave_mode_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_POWERSAVE_MODE_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->sta_ps_mode = __cpu_to_le32(psmode);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set psmode\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_set_sta_ps(struct ath10k *ar, u32 vdev_id,
- ++ enum wmi_sta_powersave_param param_id,
- ++ u32 param_value)
- ++{
- ++ struct wmi_sta_powersave_param_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_POWERSAVE_PARAM_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->param_id = __cpu_to_le32(param_id);
- ++ cmd->param_value = __cpu_to_le32(param_value);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set sta ps\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac,
- ++ enum wmi_ap_ps_peer_param param_id, u32 value)
- ++{
- ++ struct wmi_ap_ps_peer_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ if (!mac)
- ++ return ERR_PTR(-EINVAL);
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_AP_PS_PEER_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->param_id = __cpu_to_le32(param_id);
- ++ cmd->param_value = __cpu_to_le32(value);
- ++ ether_addr_copy(cmd->peer_macaddr.addr, mac);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv ap ps param\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_scan_chan_list(struct ath10k *ar,
- ++ const struct wmi_scan_chan_list_arg *arg)
- ++{
- ++ struct wmi_tlv_scan_chan_list_cmd *cmd;
- ++ struct wmi_channel *ci;
- ++ struct wmi_channel_arg *ch;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ size_t chans_len, len;
- ++ int i;
- ++ void *ptr, *chans;
- ++
- ++ chans_len = arg->n_channels * (sizeof(*tlv) + sizeof(*ci));
- ++ len = (sizeof(*tlv) + sizeof(*cmd)) +
- ++ (sizeof(*tlv) + chans_len);
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_SCAN_CHAN_LIST_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->num_scan_chans = __cpu_to_le32(arg->n_channels);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
- ++ tlv->len = __cpu_to_le16(chans_len);
- ++ chans = (void *)tlv->value;
- ++
- ++ for (i = 0; i < arg->n_channels; i++) {
- ++ ch = &arg->channels[i];
- ++
- ++ tlv = chans;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
- ++ tlv->len = __cpu_to_le16(sizeof(*ci));
- ++ ci = (void *)tlv->value;
- ++
- ++ ath10k_wmi_put_wmi_channel(ci, ch);
- ++
- ++ chans += sizeof(*tlv);
- ++ chans += sizeof(*ci);
- ++ }
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += chans_len;
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv scan chan list\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_beacon_dma(struct ath10k *ar, u32 vdev_id,
- ++ const void *bcn, size_t bcn_len,
- ++ u32 bcn_paddr, bool dtim_zero,
- ++ bool deliver_cab)
- ++
- ++{
- ++ struct wmi_bcn_tx_ref_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ struct ieee80211_hdr *hdr;
- ++ u16 fc;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ hdr = (struct ieee80211_hdr *)bcn;
- ++ fc = le16_to_cpu(hdr->frame_control);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_SEND_FROM_HOST_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->data_len = __cpu_to_le32(bcn_len);
- ++ cmd->data_ptr = __cpu_to_le32(bcn_paddr);
- ++ cmd->msdu_id = 0;
- ++ cmd->frame_control = __cpu_to_le32(fc);
- ++ cmd->flags = 0;
- ++
- ++ if (dtim_zero)
- ++ cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
- ++
- ++ if (deliver_cab)
- ++ cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv beacon dma\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_pdev_set_wmm(struct ath10k *ar,
- ++ const struct wmi_wmm_params_all_arg *arg)
- ++{
- ++ struct wmi_tlv_pdev_set_wmm_cmd *cmd;
- ++ struct wmi_wmm_params *wmm;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ size_t len;
- ++ void *ptr;
- ++
- ++ len = (sizeof(*tlv) + sizeof(*cmd)) +
- ++ (4 * (sizeof(*tlv) + sizeof(*wmm)));
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_WMM_PARAMS_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++
- ++ /* nothing to set here */
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_be);
- ++ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_bk);
- ++ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vi);
- ++ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vo);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set wmm\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
- ++{
- ++ struct wmi_request_stats_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->stats_id = __cpu_to_le32(stats_mask);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv request stats\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_force_fw_hang(struct ath10k *ar,
- ++ enum wmi_force_fw_hang_type type,
- ++ u32 delay_ms)
- ++{
- ++ struct wmi_force_fw_hang_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++
- ++ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ tlv = (void *)skb->data;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_FORCE_FW_HANG_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->type = __cpu_to_le32(type);
- ++ cmd->delay_ms = __cpu_to_le32(delay_ms);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv force fw hang\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable,
- ++ u32 log_level) {
- ++ struct wmi_tlv_dbglog_cmd *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ size_t len, bmap_len;
- ++ u32 value;
- ++ void *ptr;
- ++
- ++ if (module_enable) {
- ++ value = WMI_TLV_DBGLOG_LOG_LEVEL_VALUE(
- ++ module_enable,
- ++ WMI_TLV_DBGLOG_LOG_LEVEL_VERBOSE);
- ++ } else {
- ++ value = WMI_TLV_DBGLOG_LOG_LEVEL_VALUE(
- ++ WMI_TLV_DBGLOG_ALL_MODULES,
- ++ WMI_TLV_DBGLOG_LOG_LEVEL_WARN);
- ++ }
- ++
- ++ bmap_len = 0;
- ++ len = sizeof(*tlv) + sizeof(*cmd) + sizeof(*tlv) + bmap_len;
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_DEBUG_LOG_CONFIG_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->param = __cpu_to_le32(WMI_TLV_DBGLOG_PARAM_LOG_LEVEL);
- ++ cmd->value = __cpu_to_le32(value);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32);
- ++ tlv->len = __cpu_to_le16(bmap_len);
- ++
- ++ /* nothing to do here */
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(bmap_len);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv dbglog value 0x%08x\n", value);
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_pktlog_enable(struct ath10k *ar, u32 filter)
- ++{
- ++ struct wmi_tlv_pktlog_enable *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ void *ptr;
- ++ size_t len;
- ++
- ++ len = sizeof(*tlv) + sizeof(*cmd);
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_ENABLE_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->filter = __cpu_to_le32(filter);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pktlog enable filter 0x%08x\n",
- ++ filter);
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_pktlog_disable(struct ath10k *ar)
- ++{
- ++ struct wmi_tlv_pktlog_disable *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ void *ptr;
- ++ size_t len;
- ++
- ++ len = sizeof(*tlv) + sizeof(*cmd);
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_DISABLE_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pktlog disable\n");
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_bcn_tmpl(struct ath10k *ar, u32 vdev_id,
- ++ u32 tim_ie_offset, struct sk_buff *bcn,
- ++ u32 prb_caps, u32 prb_erp, void *prb_ies,
- ++ size_t prb_ies_len)
- ++{
- ++ struct wmi_tlv_bcn_tmpl_cmd *cmd;
- ++ struct wmi_tlv_bcn_prb_info *info;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ void *ptr;
- ++ size_t len;
- ++
- ++ if (WARN_ON(prb_ies_len > 0 && !prb_ies))
- ++ return ERR_PTR(-EINVAL);
- ++
- ++ len = sizeof(*tlv) + sizeof(*cmd) +
- ++ sizeof(*tlv) + sizeof(*info) + prb_ies_len +
- ++ sizeof(*tlv) + roundup(bcn->len, 4);
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_TMPL_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->tim_ie_offset = __cpu_to_le32(tim_ie_offset);
- ++ cmd->buf_len = __cpu_to_le32(bcn->len);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ /* FIXME: prb_ies_len should be probably aligned to 4byte boundary but
- ++ * then it is then impossible to pass original ie len.
- ++ * This chunk is not used yet so if setting probe resp template yields
- ++ * problems with beaconing or crashes firmware look here.
- ++ */
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_PRB_INFO);
- ++ tlv->len = __cpu_to_le16(sizeof(*info) + prb_ies_len);
- ++ info = (void *)tlv->value;
- ++ info->caps = __cpu_to_le32(prb_caps);
- ++ info->erp = __cpu_to_le32(prb_erp);
- ++ memcpy(info->ies, prb_ies, prb_ies_len);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*info);
- ++ ptr += prb_ies_len;
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
- ++ tlv->len = __cpu_to_le16(roundup(bcn->len, 4));
- ++ memcpy(tlv->value, bcn->data, bcn->len);
- ++
- ++ /* FIXME: Adjust TSF? */
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv bcn tmpl vdev_id %i\n",
- ++ vdev_id);
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_prb_tmpl(struct ath10k *ar, u32 vdev_id,
- ++ struct sk_buff *prb)
- ++{
- ++ struct wmi_tlv_prb_tmpl_cmd *cmd;
- ++ struct wmi_tlv_bcn_prb_info *info;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ void *ptr;
- ++ size_t len;
- ++
- ++ len = sizeof(*tlv) + sizeof(*cmd) +
- ++ sizeof(*tlv) + sizeof(*info) +
- ++ sizeof(*tlv) + roundup(prb->len, 4);
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PRB_TMPL_CMD);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->buf_len = __cpu_to_le32(prb->len);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_PRB_INFO);
- ++ tlv->len = __cpu_to_le16(sizeof(*info));
- ++ info = (void *)tlv->value;
- ++ info->caps = 0;
- ++ info->erp = 0;
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*info);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
- ++ tlv->len = __cpu_to_le16(roundup(prb->len, 4));
- ++ memcpy(tlv->value, prb->data, prb->len);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv prb tmpl vdev_id %i\n",
- ++ vdev_id);
- ++ return skb;
- ++}
- ++
- ++static struct sk_buff *
- ++ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id,
- ++ const u8 *p2p_ie)
- ++{
- ++ struct wmi_tlv_p2p_go_bcn_ie *cmd;
- ++ struct wmi_tlv *tlv;
- ++ struct sk_buff *skb;
- ++ void *ptr;
- ++ size_t len;
- ++
- ++ len = sizeof(*tlv) + sizeof(*cmd) +
- ++ sizeof(*tlv) + roundup(p2p_ie[1] + 2, 4);
- ++ skb = ath10k_wmi_alloc_skb(ar, len);
- ++ if (!skb)
- ++ return ERR_PTR(-ENOMEM);
- ++
- ++ ptr = (void *)skb->data;
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_P2P_GO_SET_BEACON_IE);
- ++ tlv->len = __cpu_to_le16(sizeof(*cmd));
- ++ cmd = (void *)tlv->value;
- ++ cmd->vdev_id = __cpu_to_le32(vdev_id);
- ++ cmd->ie_len = __cpu_to_le32(p2p_ie[1] + 2);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += sizeof(*cmd);
- ++
- ++ tlv = ptr;
- ++ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
- ++ tlv->len = __cpu_to_le16(roundup(p2p_ie[1] + 2, 4));
- ++ memcpy(tlv->value, p2p_ie, p2p_ie[1] + 2);
- ++
- ++ ptr += sizeof(*tlv);
- ++ ptr += roundup(p2p_ie[1] + 2, 4);
- ++
- ++ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv p2p go bcn ie for vdev %i\n",
- ++ vdev_id);
- ++ return skb;
- ++}
- ++
- ++/****************/
- ++/* TLV mappings */
- ++/****************/
- ++
- ++static struct wmi_cmd_map wmi_tlv_cmd_map = {
- ++ .init_cmdid = WMI_TLV_INIT_CMDID,
- ++ .start_scan_cmdid = WMI_TLV_START_SCAN_CMDID,
- ++ .stop_scan_cmdid = WMI_TLV_STOP_SCAN_CMDID,
- ++ .scan_chan_list_cmdid = WMI_TLV_SCAN_CHAN_LIST_CMDID,
- ++ .scan_sch_prio_tbl_cmdid = WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID,
- ++ .pdev_set_regdomain_cmdid = WMI_TLV_PDEV_SET_REGDOMAIN_CMDID,
- ++ .pdev_set_channel_cmdid = WMI_TLV_PDEV_SET_CHANNEL_CMDID,
- ++ .pdev_set_param_cmdid = WMI_TLV_PDEV_SET_PARAM_CMDID,
- ++ .pdev_pktlog_enable_cmdid = WMI_TLV_PDEV_PKTLOG_ENABLE_CMDID,
- ++ .pdev_pktlog_disable_cmdid = WMI_TLV_PDEV_PKTLOG_DISABLE_CMDID,
- ++ .pdev_set_wmm_params_cmdid = WMI_TLV_PDEV_SET_WMM_PARAMS_CMDID,
- ++ .pdev_set_ht_cap_ie_cmdid = WMI_TLV_PDEV_SET_HT_CAP_IE_CMDID,
- ++ .pdev_set_vht_cap_ie_cmdid = WMI_TLV_PDEV_SET_VHT_CAP_IE_CMDID,
- ++ .pdev_set_dscp_tid_map_cmdid = WMI_TLV_PDEV_SET_DSCP_TID_MAP_CMDID,
- ++ .pdev_set_quiet_mode_cmdid = WMI_TLV_PDEV_SET_QUIET_MODE_CMDID,
- ++ .pdev_green_ap_ps_enable_cmdid = WMI_TLV_PDEV_GREEN_AP_PS_ENABLE_CMDID,
- ++ .pdev_get_tpc_config_cmdid = WMI_TLV_PDEV_GET_TPC_CONFIG_CMDID,
- ++ .pdev_set_base_macaddr_cmdid = WMI_TLV_PDEV_SET_BASE_MACADDR_CMDID,
- ++ .vdev_create_cmdid = WMI_TLV_VDEV_CREATE_CMDID,
- ++ .vdev_delete_cmdid = WMI_TLV_VDEV_DELETE_CMDID,
- ++ .vdev_start_request_cmdid = WMI_TLV_VDEV_START_REQUEST_CMDID,
- ++ .vdev_restart_request_cmdid = WMI_TLV_VDEV_RESTART_REQUEST_CMDID,
- ++ .vdev_up_cmdid = WMI_TLV_VDEV_UP_CMDID,
- ++ .vdev_stop_cmdid = WMI_TLV_VDEV_STOP_CMDID,
- ++ .vdev_down_cmdid = WMI_TLV_VDEV_DOWN_CMDID,
- ++ .vdev_set_param_cmdid = WMI_TLV_VDEV_SET_PARAM_CMDID,
- ++ .vdev_install_key_cmdid = WMI_TLV_VDEV_INSTALL_KEY_CMDID,
- ++ .peer_create_cmdid = WMI_TLV_PEER_CREATE_CMDID,
- ++ .peer_delete_cmdid = WMI_TLV_PEER_DELETE_CMDID,
- ++ .peer_flush_tids_cmdid = WMI_TLV_PEER_FLUSH_TIDS_CMDID,
- ++ .peer_set_param_cmdid = WMI_TLV_PEER_SET_PARAM_CMDID,
- ++ .peer_assoc_cmdid = WMI_TLV_PEER_ASSOC_CMDID,
- ++ .peer_add_wds_entry_cmdid = WMI_TLV_PEER_ADD_WDS_ENTRY_CMDID,
- ++ .peer_remove_wds_entry_cmdid = WMI_TLV_PEER_REMOVE_WDS_ENTRY_CMDID,
- ++ .peer_mcast_group_cmdid = WMI_TLV_PEER_MCAST_GROUP_CMDID,
- ++ .bcn_tx_cmdid = WMI_TLV_BCN_TX_CMDID,
- ++ .pdev_send_bcn_cmdid = WMI_TLV_PDEV_SEND_BCN_CMDID,
- ++ .bcn_tmpl_cmdid = WMI_TLV_BCN_TMPL_CMDID,
- ++ .bcn_filter_rx_cmdid = WMI_TLV_BCN_FILTER_RX_CMDID,
- ++ .prb_req_filter_rx_cmdid = WMI_TLV_PRB_REQ_FILTER_RX_CMDID,
- ++ .mgmt_tx_cmdid = WMI_TLV_MGMT_TX_CMDID,
- ++ .prb_tmpl_cmdid = WMI_TLV_PRB_TMPL_CMDID,
- ++ .addba_clear_resp_cmdid = WMI_TLV_ADDBA_CLEAR_RESP_CMDID,
- ++ .addba_send_cmdid = WMI_TLV_ADDBA_SEND_CMDID,
- ++ .addba_status_cmdid = WMI_TLV_ADDBA_STATUS_CMDID,
- ++ .delba_send_cmdid = WMI_TLV_DELBA_SEND_CMDID,
- ++ .addba_set_resp_cmdid = WMI_TLV_ADDBA_SET_RESP_CMDID,
- ++ .send_singleamsdu_cmdid = WMI_TLV_SEND_SINGLEAMSDU_CMDID,
- ++ .sta_powersave_mode_cmdid = WMI_TLV_STA_POWERSAVE_MODE_CMDID,
- ++ .sta_powersave_param_cmdid = WMI_TLV_STA_POWERSAVE_PARAM_CMDID,
- ++ .sta_mimo_ps_mode_cmdid = WMI_TLV_STA_MIMO_PS_MODE_CMDID,
- ++ .pdev_dfs_enable_cmdid = WMI_TLV_PDEV_DFS_ENABLE_CMDID,
- ++ .pdev_dfs_disable_cmdid = WMI_TLV_PDEV_DFS_DISABLE_CMDID,
- ++ .roam_scan_mode = WMI_TLV_ROAM_SCAN_MODE,
- ++ .roam_scan_rssi_threshold = WMI_TLV_ROAM_SCAN_RSSI_THRESHOLD,
- ++ .roam_scan_period = WMI_TLV_ROAM_SCAN_PERIOD,
- ++ .roam_scan_rssi_change_threshold =
- ++ WMI_TLV_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
- ++ .roam_ap_profile = WMI_TLV_ROAM_AP_PROFILE,
- ++ .ofl_scan_add_ap_profile = WMI_TLV_ROAM_AP_PROFILE,
- ++ .ofl_scan_remove_ap_profile = WMI_TLV_OFL_SCAN_REMOVE_AP_PROFILE,
- ++ .ofl_scan_period = WMI_TLV_OFL_SCAN_PERIOD,
- ++ .p2p_dev_set_device_info = WMI_TLV_P2P_DEV_SET_DEVICE_INFO,
- ++ .p2p_dev_set_discoverability = WMI_TLV_P2P_DEV_SET_DISCOVERABILITY,
- ++ .p2p_go_set_beacon_ie = WMI_TLV_P2P_GO_SET_BEACON_IE,
- ++ .p2p_go_set_probe_resp_ie = WMI_TLV_P2P_GO_SET_PROBE_RESP_IE,
- ++ .p2p_set_vendor_ie_data_cmdid = WMI_TLV_P2P_SET_VENDOR_IE_DATA_CMDID,
- ++ .ap_ps_peer_param_cmdid = WMI_TLV_AP_PS_PEER_PARAM_CMDID,
- ++ .ap_ps_peer_uapsd_coex_cmdid = WMI_TLV_AP_PS_PEER_UAPSD_COEX_CMDID,
- ++ .peer_rate_retry_sched_cmdid = WMI_TLV_PEER_RATE_RETRY_SCHED_CMDID,
- ++ .wlan_profile_trigger_cmdid = WMI_TLV_WLAN_PROFILE_TRIGGER_CMDID,
- ++ .wlan_profile_set_hist_intvl_cmdid =
- ++ WMI_TLV_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
- ++ .wlan_profile_get_profile_data_cmdid =
- ++ WMI_TLV_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
- ++ .wlan_profile_enable_profile_id_cmdid =
- ++ WMI_TLV_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
- ++ .wlan_profile_list_profile_id_cmdid =
- ++ WMI_TLV_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
- ++ .pdev_suspend_cmdid = WMI_TLV_PDEV_SUSPEND_CMDID,
- ++ .pdev_resume_cmdid = WMI_TLV_PDEV_RESUME_CMDID,
- ++ .add_bcn_filter_cmdid = WMI_TLV_ADD_BCN_FILTER_CMDID,
- ++ .rmv_bcn_filter_cmdid = WMI_TLV_RMV_BCN_FILTER_CMDID,
- ++ .wow_add_wake_pattern_cmdid = WMI_TLV_WOW_ADD_WAKE_PATTERN_CMDID,
- ++ .wow_del_wake_pattern_cmdid = WMI_TLV_WOW_DEL_WAKE_PATTERN_CMDID,
- ++ .wow_enable_disable_wake_event_cmdid =
- ++ WMI_TLV_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
- ++ .wow_enable_cmdid = WMI_TLV_WOW_ENABLE_CMDID,
- ++ .wow_hostwakeup_from_sleep_cmdid =
- ++ WMI_TLV_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
- ++ .rtt_measreq_cmdid = WMI_TLV_RTT_MEASREQ_CMDID,
- ++ .rtt_tsf_cmdid = WMI_TLV_RTT_TSF_CMDID,
- ++ .vdev_spectral_scan_configure_cmdid = WMI_TLV_SPECTRAL_SCAN_CONF_CMDID,
- ++ .vdev_spectral_scan_enable_cmdid = WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID,
- ++ .request_stats_cmdid = WMI_TLV_REQUEST_STATS_CMDID,
- ++ .set_arp_ns_offload_cmdid = WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID,
- ++ .network_list_offload_config_cmdid =
- ++ WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID,
- ++ .gtk_offload_cmdid = WMI_TLV_GTK_OFFLOAD_CMDID,
- ++ .csa_offload_enable_cmdid = WMI_TLV_CSA_OFFLOAD_ENABLE_CMDID,
- ++ .csa_offload_chanswitch_cmdid = WMI_TLV_CSA_OFFLOAD_CHANSWITCH_CMDID,
- ++ .chatter_set_mode_cmdid = WMI_TLV_CHATTER_SET_MODE_CMDID,
- ++ .peer_tid_addba_cmdid = WMI_TLV_PEER_TID_ADDBA_CMDID,
- ++ .peer_tid_delba_cmdid = WMI_TLV_PEER_TID_DELBA_CMDID,
- ++ .sta_dtim_ps_method_cmdid = WMI_TLV_STA_DTIM_PS_METHOD_CMDID,
- ++ .sta_uapsd_auto_trig_cmdid = WMI_TLV_STA_UAPSD_AUTO_TRIG_CMDID,
- ++ .sta_keepalive_cmd = WMI_TLV_STA_KEEPALIVE_CMDID,
- ++ .echo_cmdid = WMI_TLV_ECHO_CMDID,
- ++ .pdev_utf_cmdid = WMI_TLV_PDEV_UTF_CMDID,
- ++ .dbglog_cfg_cmdid = WMI_TLV_DBGLOG_CFG_CMDID,
- ++ .pdev_qvit_cmdid = WMI_TLV_PDEV_QVIT_CMDID,
- ++ .pdev_ftm_intg_cmdid = WMI_TLV_PDEV_FTM_INTG_CMDID,
- ++ .vdev_set_keepalive_cmdid = WMI_TLV_VDEV_SET_KEEPALIVE_CMDID,
- ++ .vdev_get_keepalive_cmdid = WMI_TLV_VDEV_GET_KEEPALIVE_CMDID,
- ++ .force_fw_hang_cmdid = WMI_TLV_FORCE_FW_HANG_CMDID,
- ++ .gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID,
- ++ .gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID,
- ++ .pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED,
- ++ .vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID,
- ++};
- ++
- ++static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = {
- ++ .tx_chain_mask = WMI_TLV_PDEV_PARAM_TX_CHAIN_MASK,
- ++ .rx_chain_mask = WMI_TLV_PDEV_PARAM_RX_CHAIN_MASK,
- ++ .txpower_limit2g = WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT2G,
- ++ .txpower_limit5g = WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT5G,
- ++ .txpower_scale = WMI_TLV_PDEV_PARAM_TXPOWER_SCALE,
- ++ .beacon_gen_mode = WMI_TLV_PDEV_PARAM_BEACON_GEN_MODE,
- ++ .beacon_tx_mode = WMI_TLV_PDEV_PARAM_BEACON_TX_MODE,
- ++ .resmgr_offchan_mode = WMI_TLV_PDEV_PARAM_RESMGR_OFFCHAN_MODE,
- ++ .protection_mode = WMI_TLV_PDEV_PARAM_PROTECTION_MODE,
- ++ .dynamic_bw = WMI_TLV_PDEV_PARAM_DYNAMIC_BW,
- ++ .non_agg_sw_retry_th = WMI_TLV_PDEV_PARAM_NON_AGG_SW_RETRY_TH,
- ++ .agg_sw_retry_th = WMI_TLV_PDEV_PARAM_AGG_SW_RETRY_TH,
- ++ .sta_kickout_th = WMI_TLV_PDEV_PARAM_STA_KICKOUT_TH,
- ++ .ac_aggrsize_scaling = WMI_TLV_PDEV_PARAM_AC_AGGRSIZE_SCALING,
- ++ .ltr_enable = WMI_TLV_PDEV_PARAM_LTR_ENABLE,
- ++ .ltr_ac_latency_be = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BE,
- ++ .ltr_ac_latency_bk = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BK,
- ++ .ltr_ac_latency_vi = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VI,
- ++ .ltr_ac_latency_vo = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VO,
- ++ .ltr_ac_latency_timeout = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT,
- ++ .ltr_sleep_override = WMI_TLV_PDEV_PARAM_LTR_SLEEP_OVERRIDE,
- ++ .ltr_rx_override = WMI_TLV_PDEV_PARAM_LTR_RX_OVERRIDE,
- ++ .ltr_tx_activity_timeout = WMI_TLV_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT,
- ++ .l1ss_enable = WMI_TLV_PDEV_PARAM_L1SS_ENABLE,
- ++ .dsleep_enable = WMI_TLV_PDEV_PARAM_DSLEEP_ENABLE,
- ++ .pcielp_txbuf_flush = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_FLUSH,
- ++ .pcielp_txbuf_watermark = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN,
- ++ .pcielp_txbuf_tmo_en = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN,
- ++ .pcielp_txbuf_tmo_value = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE,
- ++ .pdev_stats_update_period = WMI_TLV_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD,
- ++ .vdev_stats_update_period = WMI_TLV_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD,
- ++ .peer_stats_update_period = WMI_TLV_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD,
- ++ .bcnflt_stats_update_period =
- ++ WMI_TLV_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
- ++ .pmf_qos = WMI_TLV_PDEV_PARAM_PMF_QOS,
- ++ .arp_ac_override = WMI_TLV_PDEV_PARAM_ARP_AC_OVERRIDE,
- ++ .dcs = WMI_TLV_PDEV_PARAM_DCS,
- ++ .ani_enable = WMI_TLV_PDEV_PARAM_ANI_ENABLE,
- ++ .ani_poll_period = WMI_TLV_PDEV_PARAM_ANI_POLL_PERIOD,
- ++ .ani_listen_period = WMI_TLV_PDEV_PARAM_ANI_LISTEN_PERIOD,
- ++ .ani_ofdm_level = WMI_TLV_PDEV_PARAM_ANI_OFDM_LEVEL,
- ++ .ani_cck_level = WMI_TLV_PDEV_PARAM_ANI_CCK_LEVEL,
- ++ .dyntxchain = WMI_TLV_PDEV_PARAM_DYNTXCHAIN,
- ++ .proxy_sta = WMI_TLV_PDEV_PARAM_PROXY_STA,
- ++ .idle_ps_config = WMI_TLV_PDEV_PARAM_IDLE_PS_CONFIG,
- ++ .power_gating_sleep = WMI_TLV_PDEV_PARAM_POWER_GATING_SLEEP,
- ++ .fast_channel_reset = WMI_TLV_PDEV_PARAM_UNSUPPORTED,
- ++ .burst_dur = WMI_TLV_PDEV_PARAM_BURST_DUR,
- ++ .burst_enable = WMI_TLV_PDEV_PARAM_BURST_ENABLE,
- ++ .cal_period = WMI_PDEV_PARAM_UNSUPPORTED,
- ++};
- ++
- ++static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = {
- ++ .rts_threshold = WMI_TLV_VDEV_PARAM_RTS_THRESHOLD,
- ++ .fragmentation_threshold = WMI_TLV_VDEV_PARAM_FRAGMENTATION_THRESHOLD,
- ++ .beacon_interval = WMI_TLV_VDEV_PARAM_BEACON_INTERVAL,
- ++ .listen_interval = WMI_TLV_VDEV_PARAM_LISTEN_INTERVAL,
- ++ .multicast_rate = WMI_TLV_VDEV_PARAM_MULTICAST_RATE,
- ++ .mgmt_tx_rate = WMI_TLV_VDEV_PARAM_MGMT_TX_RATE,
- ++ .slot_time = WMI_TLV_VDEV_PARAM_SLOT_TIME,
- ++ .preamble = WMI_TLV_VDEV_PARAM_PREAMBLE,
- ++ .swba_time = WMI_TLV_VDEV_PARAM_SWBA_TIME,
- ++ .wmi_vdev_stats_update_period = WMI_TLV_VDEV_STATS_UPDATE_PERIOD,
- ++ .wmi_vdev_pwrsave_ageout_time = WMI_TLV_VDEV_PWRSAVE_AGEOUT_TIME,
- ++ .wmi_vdev_host_swba_interval = WMI_TLV_VDEV_HOST_SWBA_INTERVAL,
- ++ .dtim_period = WMI_TLV_VDEV_PARAM_DTIM_PERIOD,
- ++ .wmi_vdev_oc_scheduler_air_time_limit =
- ++ WMI_TLV_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT,
- ++ .wds = WMI_TLV_VDEV_PARAM_WDS,
- ++ .atim_window = WMI_TLV_VDEV_PARAM_ATIM_WINDOW,
- ++ .bmiss_count_max = WMI_TLV_VDEV_PARAM_BMISS_COUNT_MAX,
- ++ .bmiss_first_bcnt = WMI_TLV_VDEV_PARAM_BMISS_FIRST_BCNT,
- ++ .bmiss_final_bcnt = WMI_TLV_VDEV_PARAM_BMISS_FINAL_BCNT,
- ++ .feature_wmm = WMI_TLV_VDEV_PARAM_FEATURE_WMM,
- ++ .chwidth = WMI_TLV_VDEV_PARAM_CHWIDTH,
- ++ .chextoffset = WMI_TLV_VDEV_PARAM_CHEXTOFFSET,
- ++ .disable_htprotection = WMI_TLV_VDEV_PARAM_DISABLE_HTPROTECTION,
- ++ .sta_quickkickout = WMI_TLV_VDEV_PARAM_STA_QUICKKICKOUT,
- ++ .mgmt_rate = WMI_TLV_VDEV_PARAM_MGMT_RATE,
- ++ .protection_mode = WMI_TLV_VDEV_PARAM_PROTECTION_MODE,
- ++ .fixed_rate = WMI_TLV_VDEV_PARAM_FIXED_RATE,
- ++ .sgi = WMI_TLV_VDEV_PARAM_SGI,
- ++ .ldpc = WMI_TLV_VDEV_PARAM_LDPC,
- ++ .tx_stbc = WMI_TLV_VDEV_PARAM_TX_STBC,
- ++ .rx_stbc = WMI_TLV_VDEV_PARAM_RX_STBC,
- ++ .intra_bss_fwd = WMI_TLV_VDEV_PARAM_INTRA_BSS_FWD,
- ++ .def_keyid = WMI_TLV_VDEV_PARAM_DEF_KEYID,
- ++ .nss = WMI_TLV_VDEV_PARAM_NSS,
- ++ .bcast_data_rate = WMI_TLV_VDEV_PARAM_BCAST_DATA_RATE,
- ++ .mcast_data_rate = WMI_TLV_VDEV_PARAM_MCAST_DATA_RATE,
- ++ .mcast_indicate = WMI_TLV_VDEV_PARAM_MCAST_INDICATE,
- ++ .dhcp_indicate = WMI_TLV_VDEV_PARAM_DHCP_INDICATE,
- ++ .unknown_dest_indicate = WMI_TLV_VDEV_PARAM_UNKNOWN_DEST_INDICATE,
- ++ .ap_keepalive_min_idle_inactive_time_secs =
- ++ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS,
- ++ .ap_keepalive_max_idle_inactive_time_secs =
- ++ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS,
- ++ .ap_keepalive_max_unresponsive_time_secs =
- ++ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS,
- ++ .ap_enable_nawds = WMI_TLV_VDEV_PARAM_AP_ENABLE_NAWDS,
- ++ .mcast2ucast_set = WMI_TLV_VDEV_PARAM_UNSUPPORTED,
- ++ .enable_rtscts = WMI_TLV_VDEV_PARAM_ENABLE_RTSCTS,
- ++ .txbf = WMI_TLV_VDEV_PARAM_TXBF,
- ++ .packet_powersave = WMI_TLV_VDEV_PARAM_PACKET_POWERSAVE,
- ++ .drop_unencry = WMI_TLV_VDEV_PARAM_DROP_UNENCRY,
- ++ .tx_encap_type = WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE,
- ++ .ap_detect_out_of_sync_sleeping_sta_time_secs =
- ++ WMI_TLV_VDEV_PARAM_UNSUPPORTED,
- ++};
- ++
- ++static const struct wmi_ops wmi_tlv_ops = {
- ++ .rx = ath10k_wmi_tlv_op_rx,
- ++ .map_svc = wmi_tlv_svc_map,
- ++
- ++ .pull_scan = ath10k_wmi_tlv_op_pull_scan_ev,
- ++ .pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev,
- ++ .pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev,
- ++ .pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev,
- ++ .pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev,
- ++ .pull_swba = ath10k_wmi_tlv_op_pull_swba_ev,
- ++ .pull_phyerr = ath10k_wmi_tlv_op_pull_phyerr_ev,
- ++ .pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev,
- ++ .pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev,
- ++ .pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats,
- ++
- ++ .gen_pdev_suspend = ath10k_wmi_tlv_op_gen_pdev_suspend,
- ++ .gen_pdev_resume = ath10k_wmi_tlv_op_gen_pdev_resume,
- ++ .gen_pdev_set_rd = ath10k_wmi_tlv_op_gen_pdev_set_rd,
- ++ .gen_pdev_set_param = ath10k_wmi_tlv_op_gen_pdev_set_param,
- ++ .gen_init = ath10k_wmi_tlv_op_gen_init,
- ++ .gen_start_scan = ath10k_wmi_tlv_op_gen_start_scan,
- ++ .gen_stop_scan = ath10k_wmi_tlv_op_gen_stop_scan,
- ++ .gen_vdev_create = ath10k_wmi_tlv_op_gen_vdev_create,
- ++ .gen_vdev_delete = ath10k_wmi_tlv_op_gen_vdev_delete,
- ++ .gen_vdev_start = ath10k_wmi_tlv_op_gen_vdev_start,
- ++ .gen_vdev_stop = ath10k_wmi_tlv_op_gen_vdev_stop,
- ++ .gen_vdev_up = ath10k_wmi_tlv_op_gen_vdev_up,
- ++ .gen_vdev_down = ath10k_wmi_tlv_op_gen_vdev_down,
- ++ .gen_vdev_set_param = ath10k_wmi_tlv_op_gen_vdev_set_param,
- ++ .gen_vdev_install_key = ath10k_wmi_tlv_op_gen_vdev_install_key,
- ++ .gen_vdev_wmm_conf = ath10k_wmi_tlv_op_gen_vdev_wmm_conf,
- ++ .gen_peer_create = ath10k_wmi_tlv_op_gen_peer_create,
- ++ .gen_peer_delete = ath10k_wmi_tlv_op_gen_peer_delete,
- ++ .gen_peer_flush = ath10k_wmi_tlv_op_gen_peer_flush,
- ++ .gen_peer_set_param = ath10k_wmi_tlv_op_gen_peer_set_param,
- ++ .gen_peer_assoc = ath10k_wmi_tlv_op_gen_peer_assoc,
- ++ .gen_set_psmode = ath10k_wmi_tlv_op_gen_set_psmode,
- ++ .gen_set_sta_ps = ath10k_wmi_tlv_op_gen_set_sta_ps,
- ++ .gen_set_ap_ps = ath10k_wmi_tlv_op_gen_set_ap_ps,
- ++ .gen_scan_chan_list = ath10k_wmi_tlv_op_gen_scan_chan_list,
- ++ .gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma,
- ++ .gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm,
- ++ .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
- ++ .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
- ++ /* .gen_mgmt_tx = not implemented; HTT is used */
- ++ .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
- ++ .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
- ++ .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
- ++ /* .gen_pdev_set_quiet_mode not implemented */
- ++ /* .gen_pdev_get_temperature not implemented */
- ++ /* .gen_addba_clear_resp not implemented */
- ++ /* .gen_addba_send not implemented */
- ++ /* .gen_addba_set_resp not implemented */
- ++ /* .gen_delba_send not implemented */
- ++ .gen_bcn_tmpl = ath10k_wmi_tlv_op_gen_bcn_tmpl,
- ++ .gen_prb_tmpl = ath10k_wmi_tlv_op_gen_prb_tmpl,
- ++ .gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie,
- ++ .gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd,
- ++ .gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive,
- ++};
- ++
- ++/************/
- ++/* TLV init */
- ++/************/
- ++
- ++void ath10k_wmi_tlv_attach(struct ath10k *ar)
- ++{
- ++ ar->wmi.cmd = &wmi_tlv_cmd_map;
- ++ ar->wmi.vdev_param = &wmi_tlv_vdev_param_map;
- ++ ar->wmi.pdev_param = &wmi_tlv_pdev_param_map;
- ++ ar->wmi.ops = &wmi_tlv_ops;
- ++}
- +--- /dev/null
- ++++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
- +@@ -0,0 +1,1459 @@
- ++/*
- ++ * Copyright (c) 2005-2011 Atheros Communications Inc.
- ++ * Copyright (c) 2011-2014 Qualcomm Atheros, Inc.
- ++ *
- ++ * Permission to use, copy, modify, and/or distribute this software for any
- ++ * purpose with or without fee is hereby granted, provided that the above
- ++ * copyright notice and this permission notice appear in all copies.
- ++ *
- ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- ++ */
- ++#ifndef _WMI_TLV_H
- ++#define _WMI_TLV_H
- ++
- ++#define WMI_TLV_CMD(grp_id) (((grp_id) << 12) | 0x1)
- ++#define WMI_TLV_EV(grp_id) (((grp_id) << 12) | 0x1)
- ++#define WMI_TLV_CMD_UNSUPPORTED 0
- ++#define WMI_TLV_PDEV_PARAM_UNSUPPORTED 0
- ++#define WMI_TLV_VDEV_PARAM_UNSUPPORTED 0
- ++
- ++enum wmi_tlv_grp_id {
- ++ WMI_TLV_GRP_START = 0x3,
- ++ WMI_TLV_GRP_SCAN = WMI_TLV_GRP_START,
- ++ WMI_TLV_GRP_PDEV,
- ++ WMI_TLV_GRP_VDEV,
- ++ WMI_TLV_GRP_PEER,
- ++ WMI_TLV_GRP_MGMT,
- ++ WMI_TLV_GRP_BA_NEG,
- ++ WMI_TLV_GRP_STA_PS,
- ++ WMI_TLV_GRP_DFS,
- ++ WMI_TLV_GRP_ROAM,
- ++ WMI_TLV_GRP_OFL_SCAN,
- ++ WMI_TLV_GRP_P2P,
- ++ WMI_TLV_GRP_AP_PS,
- ++ WMI_TLV_GRP_RATECTL,
- ++ WMI_TLV_GRP_PROFILE,
- ++ WMI_TLV_GRP_SUSPEND,
- ++ WMI_TLV_GRP_BCN_FILTER,
- ++ WMI_TLV_GRP_WOW,
- ++ WMI_TLV_GRP_RTT,
- ++ WMI_TLV_GRP_SPECTRAL,
- ++ WMI_TLV_GRP_STATS,
- ++ WMI_TLV_GRP_ARP_NS_OFL,
- ++ WMI_TLV_GRP_NLO_OFL,
- ++ WMI_TLV_GRP_GTK_OFL,
- ++ WMI_TLV_GRP_CSA_OFL,
- ++ WMI_TLV_GRP_CHATTER,
- ++ WMI_TLV_GRP_TID_ADDBA,
- ++ WMI_TLV_GRP_MISC,
- ++ WMI_TLV_GRP_GPIO,
- ++ WMI_TLV_GRP_FWTEST,
- ++ WMI_TLV_GRP_TDLS,
- ++ WMI_TLV_GRP_RESMGR,
- ++ WMI_TLV_GRP_STA_SMPS,
- ++ WMI_TLV_GRP_WLAN_HB,
- ++ WMI_TLV_GRP_RMC,
- ++ WMI_TLV_GRP_MHF_OFL,
- ++ WMI_TLV_GRP_LOCATION_SCAN,
- ++ WMI_TLV_GRP_OEM,
- ++ WMI_TLV_GRP_NAN,
- ++ WMI_TLV_GRP_COEX,
- ++ WMI_TLV_GRP_OBSS_OFL,
- ++ WMI_TLV_GRP_LPI,
- ++ WMI_TLV_GRP_EXTSCAN,
- ++ WMI_TLV_GRP_DHCP_OFL,
- ++ WMI_TLV_GRP_IPA,
- ++ WMI_TLV_GRP_MDNS_OFL,
- ++ WMI_TLV_GRP_SAP_OFL,
- ++};
- ++
- ++enum wmi_tlv_cmd_id {
- ++ WMI_TLV_INIT_CMDID = 0x1,
- ++ WMI_TLV_START_SCAN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SCAN),
- ++ WMI_TLV_STOP_SCAN_CMDID,
- ++ WMI_TLV_SCAN_CHAN_LIST_CMDID,
- ++ WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID,
- ++ WMI_TLV_SCAN_UPDATE_REQUEST_CMDID,
- ++ WMI_TLV_SCAN_PROB_REQ_OUI_CMDID,
- ++ WMI_TLV_PDEV_SET_REGDOMAIN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PDEV),
- ++ WMI_TLV_PDEV_SET_CHANNEL_CMDID,
- ++ WMI_TLV_PDEV_SET_PARAM_CMDID,
- ++ WMI_TLV_PDEV_PKTLOG_ENABLE_CMDID,
- ++ WMI_TLV_PDEV_PKTLOG_DISABLE_CMDID,
- ++ WMI_TLV_PDEV_SET_WMM_PARAMS_CMDID,
- ++ WMI_TLV_PDEV_SET_HT_CAP_IE_CMDID,
- ++ WMI_TLV_PDEV_SET_VHT_CAP_IE_CMDID,
- ++ WMI_TLV_PDEV_SET_DSCP_TID_MAP_CMDID,
- ++ WMI_TLV_PDEV_SET_QUIET_MODE_CMDID,
- ++ WMI_TLV_PDEV_GREEN_AP_PS_ENABLE_CMDID,
- ++ WMI_TLV_PDEV_GET_TPC_CONFIG_CMDID,
- ++ WMI_TLV_PDEV_SET_BASE_MACADDR_CMDID,
- ++ WMI_TLV_PDEV_DUMP_CMDID,
- ++ WMI_TLV_PDEV_SET_LED_CONFIG_CMDID,
- ++ WMI_TLV_PDEV_GET_TEMPERATURE_CMDID,
- ++ WMI_TLV_PDEV_SET_LED_FLASHING_CMDID,
- ++ WMI_TLV_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_VDEV),
- ++ WMI_TLV_VDEV_DELETE_CMDID,
- ++ WMI_TLV_VDEV_START_REQUEST_CMDID,
- ++ WMI_TLV_VDEV_RESTART_REQUEST_CMDID,
- ++ WMI_TLV_VDEV_UP_CMDID,
- ++ WMI_TLV_VDEV_STOP_CMDID,
- ++ WMI_TLV_VDEV_DOWN_CMDID,
- ++ WMI_TLV_VDEV_SET_PARAM_CMDID,
- ++ WMI_TLV_VDEV_INSTALL_KEY_CMDID,
- ++ WMI_TLV_VDEV_WNM_SLEEPMODE_CMDID,
- ++ WMI_TLV_VDEV_WMM_ADDTS_CMDID,
- ++ WMI_TLV_VDEV_WMM_DELTS_CMDID,
- ++ WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID,
- ++ WMI_TLV_VDEV_SET_GTX_PARAMS_CMDID,
- ++ WMI_TLV_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID,
- ++ WMI_TLV_VDEV_PLMREQ_START_CMDID,
- ++ WMI_TLV_VDEV_PLMREQ_STOP_CMDID,
- ++ WMI_TLV_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PEER),
- ++ WMI_TLV_PEER_DELETE_CMDID,
- ++ WMI_TLV_PEER_FLUSH_TIDS_CMDID,
- ++ WMI_TLV_PEER_SET_PARAM_CMDID,
- ++ WMI_TLV_PEER_ASSOC_CMDID,
- ++ WMI_TLV_PEER_ADD_WDS_ENTRY_CMDID,
- ++ WMI_TLV_PEER_REMOVE_WDS_ENTRY_CMDID,
- ++ WMI_TLV_PEER_MCAST_GROUP_CMDID,
- ++ WMI_TLV_PEER_INFO_REQ_CMDID,
- ++ WMI_TLV_PEER_GET_ESTIMATED_LINKSPEED_CMDID,
- ++ WMI_TLV_BCN_TX_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MGMT),
- ++ WMI_TLV_PDEV_SEND_BCN_CMDID,
- ++ WMI_TLV_BCN_TMPL_CMDID,
- ++ WMI_TLV_BCN_FILTER_RX_CMDID,
- ++ WMI_TLV_PRB_REQ_FILTER_RX_CMDID,
- ++ WMI_TLV_MGMT_TX_CMDID,
- ++ WMI_TLV_PRB_TMPL_CMDID,
- ++ WMI_TLV_ADDBA_CLEAR_RESP_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BA_NEG),
- ++ WMI_TLV_ADDBA_SEND_CMDID,
- ++ WMI_TLV_ADDBA_STATUS_CMDID,
- ++ WMI_TLV_DELBA_SEND_CMDID,
- ++ WMI_TLV_ADDBA_SET_RESP_CMDID,
- ++ WMI_TLV_SEND_SINGLEAMSDU_CMDID,
- ++ WMI_TLV_STA_POWERSAVE_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STA_PS),
- ++ WMI_TLV_STA_POWERSAVE_PARAM_CMDID,
- ++ WMI_TLV_STA_MIMO_PS_MODE_CMDID,
- ++ WMI_TLV_PDEV_DFS_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_DFS),
- ++ WMI_TLV_PDEV_DFS_DISABLE_CMDID,
- ++ WMI_TLV_DFS_PHYERR_FILTER_ENA_CMDID,
- ++ WMI_TLV_DFS_PHYERR_FILTER_DIS_CMDID,
- ++ WMI_TLV_ROAM_SCAN_MODE = WMI_TLV_CMD(WMI_TLV_GRP_ROAM),
- ++ WMI_TLV_ROAM_SCAN_RSSI_THRESHOLD,
- ++ WMI_TLV_ROAM_SCAN_PERIOD,
- ++ WMI_TLV_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
- ++ WMI_TLV_ROAM_AP_PROFILE,
- ++ WMI_TLV_ROAM_CHAN_LIST,
- ++ WMI_TLV_ROAM_SCAN_CMD,
- ++ WMI_TLV_ROAM_SYNCH_COMPLETE,
- ++ WMI_TLV_ROAM_SET_RIC_REQUEST_CMDID,
- ++ WMI_TLV_ROAM_INVOKE_CMDID,
- ++ WMI_TLV_OFL_SCAN_ADD_AP_PROFILE = WMI_TLV_CMD(WMI_TLV_GRP_OFL_SCAN),
- ++ WMI_TLV_OFL_SCAN_REMOVE_AP_PROFILE,
- ++ WMI_TLV_OFL_SCAN_PERIOD,
- ++ WMI_TLV_P2P_DEV_SET_DEVICE_INFO = WMI_TLV_CMD(WMI_TLV_GRP_P2P),
- ++ WMI_TLV_P2P_DEV_SET_DISCOVERABILITY,
- ++ WMI_TLV_P2P_GO_SET_BEACON_IE,
- ++ WMI_TLV_P2P_GO_SET_PROBE_RESP_IE,
- ++ WMI_TLV_P2P_SET_VENDOR_IE_DATA_CMDID,
- ++ WMI_TLV_P2P_DISC_OFFLOAD_CONFIG_CMDID,
- ++ WMI_TLV_P2P_DISC_OFFLOAD_APPIE_CMDID,
- ++ WMI_TLV_P2P_DISC_OFFLOAD_PATTERN_CMDID,
- ++ WMI_TLV_P2P_SET_OPPPS_PARAM_CMDID,
- ++ WMI_TLV_AP_PS_PEER_PARAM_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_AP_PS),
- ++ WMI_TLV_AP_PS_PEER_UAPSD_COEX_CMDID,
- ++ WMI_TLV_PEER_RATE_RETRY_SCHED_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RATECTL),
- ++ WMI_TLV_WLAN_PROFILE_TRIGGER_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PROFILE),
- ++ WMI_TLV_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
- ++ WMI_TLV_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
- ++ WMI_TLV_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
- ++ WMI_TLV_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
- ++ WMI_TLV_PDEV_SUSPEND_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SUSPEND),
- ++ WMI_TLV_PDEV_RESUME_CMDID,
- ++ WMI_TLV_ADD_BCN_FILTER_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BCN_FILTER),
- ++ WMI_TLV_RMV_BCN_FILTER_CMDID,
- ++ WMI_TLV_WOW_ADD_WAKE_PATTERN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_WOW),
- ++ WMI_TLV_WOW_DEL_WAKE_PATTERN_CMDID,
- ++ WMI_TLV_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
- ++ WMI_TLV_WOW_ENABLE_CMDID,
- ++ WMI_TLV_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
- ++ WMI_TLV_WOW_ACER_IOAC_ADD_KEEPALIVE_CMDID,
- ++ WMI_TLV_WOW_ACER_IOAC_DEL_KEEPALIVE_CMDID,
- ++ WMI_TLV_WOW_ACER_IOAC_ADD_WAKE_PATTERN_CMDID,
- ++ WMI_TLV_WOW_ACER_IOAC_DEL_WAKE_PATTERN_CMDID,
- ++ WMI_TLV_D0_WOW_ENABLE_DISABLE_CMDID,
- ++ WMI_TLV_EXTWOW_ENABLE_CMDID,
- ++ WMI_TLV_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID,
- ++ WMI_TLV_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID,
- ++ WMI_TLV_RTT_MEASREQ_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RTT),
- ++ WMI_TLV_RTT_TSF_CMDID,
- ++ WMI_TLV_SPECTRAL_SCAN_CONF_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SPECTRAL),
- ++ WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID,
- ++ WMI_TLV_REQUEST_STATS_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STATS),
- ++ WMI_TLV_MCC_SCHED_TRAFFIC_STATS_CMDID,
- ++ WMI_TLV_REQUEST_STATS_EXT_CMDID,
- ++ WMI_TLV_REQUEST_LINK_STATS_CMDID,
- ++ WMI_TLV_START_LINK_STATS_CMDID,
- ++ WMI_TLV_CLEAR_LINK_STATS_CMDID,
- ++ WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_ARP_NS_OFL),
- ++ WMI_TLV_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID,
- ++ WMI_TLV_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID,
- ++ WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID =
- ++ WMI_TLV_CMD(WMI_TLV_GRP_NLO_OFL),
- ++ WMI_TLV_APFIND_CMDID,
- ++ WMI_TLV_GTK_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_GTK_OFL),
- ++ WMI_TLV_CSA_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_CSA_OFL),
- ++ WMI_TLV_CSA_OFFLOAD_CHANSWITCH_CMDID,
- ++ WMI_TLV_CHATTER_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_CHATTER),
- ++ WMI_TLV_CHATTER_ADD_COALESCING_FILTER_CMDID,
- ++ WMI_TLV_CHATTER_DELETE_COALESCING_FILTER_CMDID,
- ++ WMI_TLV_CHATTER_COALESCING_QUERY_CMDID,
- ++ WMI_TLV_PEER_TID_ADDBA_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_TID_ADDBA),
- ++ WMI_TLV_PEER_TID_DELBA_CMDID,
- ++ WMI_TLV_STA_DTIM_PS_METHOD_CMDID,
- ++ WMI_TLV_STA_UAPSD_AUTO_TRIG_CMDID,
- ++ WMI_TLV_STA_KEEPALIVE_CMDID,
- ++ WMI_TLV_BA_REQ_SSN_CMDID,
- ++ WMI_TLV_ECHO_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MISC),
- ++ WMI_TLV_PDEV_UTF_CMDID,
- ++ WMI_TLV_DBGLOG_CFG_CMDID,
- ++ WMI_TLV_PDEV_QVIT_CMDID,
- ++ WMI_TLV_PDEV_FTM_INTG_CMDID,
- ++ WMI_TLV_VDEV_SET_KEEPALIVE_CMDID,
- ++ WMI_TLV_VDEV_GET_KEEPALIVE_CMDID,
- ++ WMI_TLV_FORCE_FW_HANG_CMDID,
- ++ WMI_TLV_SET_MCASTBCAST_FILTER_CMDID,
- ++ WMI_TLV_THERMAL_MGMT_CMDID,
- ++ WMI_TLV_HOST_AUTO_SHUTDOWN_CFG_CMDID,
- ++ WMI_TLV_TPC_CHAINMASK_CONFIG_CMDID,
- ++ WMI_TLV_SET_ANTENNA_DIVERSITY_CMDID,
- ++ WMI_TLV_GPIO_CONFIG_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_GPIO),
- ++ WMI_TLV_GPIO_OUTPUT_CMDID,
- ++ WMI_TLV_TXBF_CMDID,
- ++ WMI_TLV_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID =
- ++ WMI_TLV_CMD(WMI_TLV_GRP_FWTEST),
- ++ WMI_TLV_FWTEST_P2P_SET_NOA_PARAM_CMDID,
- ++ WMI_TLV_UNIT_TEST_CMDID,
- ++ WMI_TLV_TDLS_SET_STATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_TDLS),
- ++ WMI_TLV_TDLS_PEER_UPDATE_CMDID,
- ++ WMI_TLV_TDLS_SET_OFFCHAN_MODE_CMDID,
- ++ WMI_TLV_RESMGR_ADAPTIVE_OCS_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RESMGR),
- ++ WMI_TLV_RESMGR_SET_CHAN_TIME_QUOTA_CMDID,
- ++ WMI_TLV_RESMGR_SET_CHAN_LATENCY_CMDID,
- ++ WMI_TLV_STA_SMPS_FORCE_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STA_SMPS),
- ++ WMI_TLV_STA_SMPS_PARAM_CMDID,
- ++ WMI_TLV_HB_SET_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_WLAN_HB),
- ++ WMI_TLV_HB_SET_TCP_PARAMS_CMDID,
- ++ WMI_TLV_HB_SET_TCP_PKT_FILTER_CMDID,
- ++ WMI_TLV_HB_SET_UDP_PARAMS_CMDID,
- ++ WMI_TLV_HB_SET_UDP_PKT_FILTER_CMDID,
- ++ WMI_TLV_RMC_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RMC),
- ++ WMI_TLV_RMC_SET_ACTION_PERIOD_CMDID,
- ++ WMI_TLV_RMC_CONFIG_CMDID,
- ++ WMI_TLV_MHF_OFFLOAD_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MHF_OFL),
- ++ WMI_TLV_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID,
- ++ WMI_TLV_BATCH_SCAN_ENABLE_CMDID =
- ++ WMI_TLV_CMD(WMI_TLV_GRP_LOCATION_SCAN),
- ++ WMI_TLV_BATCH_SCAN_DISABLE_CMDID,
- ++ WMI_TLV_BATCH_SCAN_TRIGGER_RESULT_CMDID,
- ++ WMI_TLV_OEM_REQ_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_OEM),
- ++ WMI_TLV_NAN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_NAN),
- ++ WMI_TLV_MODEM_POWER_STATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_COEX),
- ++ WMI_TLV_CHAN_AVOID_UPDATE_CMDID,
- ++ WMI_TLV_OBSS_SCAN_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_OBSS_OFL),
- ++ WMI_TLV_OBSS_SCAN_DISABLE_CMDID,
- ++ WMI_TLV_LPI_MGMT_SNOOPING_CONFIG_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_LPI),
- ++ WMI_TLV_LPI_START_SCAN_CMDID,
- ++ WMI_TLV_LPI_STOP_SCAN_CMDID,
- ++ WMI_TLV_EXTSCAN_START_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_EXTSCAN),
- ++ WMI_TLV_EXTSCAN_STOP_CMDID,
- ++ WMI_TLV_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID,
- ++ WMI_TLV_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID,
- ++ WMI_TLV_EXTSCAN_GET_CACHED_RESULTS_CMDID,
- ++ WMI_TLV_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID,
- ++ WMI_TLV_EXTSCAN_SET_CAPABILITIES_CMDID,
- ++ WMI_TLV_EXTSCAN_GET_CAPABILITIES_CMDID,
- ++ WMI_TLV_SET_DHCP_SERVER_OFFLOAD_CMDID =
- ++ WMI_TLV_CMD(WMI_TLV_GRP_DHCP_OFL),
- ++ WMI_TLV_IPA_OFFLOAD_ENABLE_DISABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_IPA),
- ++ WMI_TLV_MDNS_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MDNS_OFL),
- ++ WMI_TLV_MDNS_SET_FQDN_CMDID,
- ++ WMI_TLV_MDNS_SET_RESPONSE_CMDID,
- ++ WMI_TLV_MDNS_GET_STATS_CMDID,
- ++ WMI_TLV_SAP_OFL_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SAP_OFL),
- ++};
- ++
- ++enum wmi_tlv_event_id {
- ++ WMI_TLV_SERVICE_READY_EVENTID = 0x1,
- ++ WMI_TLV_READY_EVENTID,
- ++ WMI_TLV_SCAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SCAN),
- ++ WMI_TLV_PDEV_TPC_CONFIG_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PDEV),
- ++ WMI_TLV_CHAN_INFO_EVENTID,
- ++ WMI_TLV_PHYERR_EVENTID,
- ++ WMI_TLV_PDEV_DUMP_EVENTID,
- ++ WMI_TLV_TX_PAUSE_EVENTID,
- ++ WMI_TLV_DFS_RADAR_EVENTID,
- ++ WMI_TLV_PDEV_L1SS_TRACK_EVENTID,
- ++ WMI_TLV_PDEV_TEMPERATURE_EVENTID,
- ++ WMI_TLV_VDEV_START_RESP_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_VDEV),
- ++ WMI_TLV_VDEV_STOPPED_EVENTID,
- ++ WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID,
- ++ WMI_TLV_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID,
- ++ WMI_TLV_PEER_STA_KICKOUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PEER),
- ++ WMI_TLV_PEER_INFO_EVENTID,
- ++ WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID,
- ++ WMI_TLV_PEER_ESTIMATED_LINKSPEED_EVENTID,
- ++ WMI_TLV_PEER_STATE_EVENTID,
- ++ WMI_TLV_MGMT_RX_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MGMT),
- ++ WMI_TLV_HOST_SWBA_EVENTID,
- ++ WMI_TLV_TBTTOFFSET_UPDATE_EVENTID,
- ++ WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID,
- ++ WMI_TLV_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID,
- ++ WMI_TLV_TX_DELBA_COMPLETE_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_BA_NEG),
- ++ WMI_TLV_TX_ADDBA_COMPLETE_EVENTID,
- ++ WMI_TLV_BA_RSP_SSN_EVENTID,
- ++ WMI_TLV_AGGR_STATE_TRIG_EVENTID,
- ++ WMI_TLV_ROAM_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_ROAM),
- ++ WMI_TLV_PROFILE_MATCH,
- ++ WMI_TLV_ROAM_SYNCH_EVENTID,
- ++ WMI_TLV_P2P_DISC_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_P2P),
- ++ WMI_TLV_P2P_NOA_EVENTID,
- ++ WMI_TLV_PDEV_RESUME_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SUSPEND),
- ++ WMI_TLV_WOW_WAKEUP_HOST_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_WOW),
- ++ WMI_TLV_D0_WOW_DISABLE_ACK_EVENTID,
- ++ WMI_TLV_RTT_MEASUREMENT_REPORT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_RTT),
- ++ WMI_TLV_TSF_MEASUREMENT_REPORT_EVENTID,
- ++ WMI_TLV_RTT_ERROR_REPORT_EVENTID,
- ++ WMI_TLV_STATS_EXT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_STATS),
- ++ WMI_TLV_IFACE_LINK_STATS_EVENTID,
- ++ WMI_TLV_PEER_LINK_STATS_EVENTID,
- ++ WMI_TLV_RADIO_LINK_STATS_EVENTID,
- ++ WMI_TLV_NLO_MATCH_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_NLO_OFL),
- ++ WMI_TLV_NLO_SCAN_COMPLETE_EVENTID,
- ++ WMI_TLV_APFIND_EVENTID,
- ++ WMI_TLV_GTK_OFFLOAD_STATUS_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_GTK_OFL),
- ++ WMI_TLV_GTK_REKEY_FAIL_EVENTID,
- ++ WMI_TLV_CSA_HANDLING_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_CSA_OFL),
- ++ WMI_TLV_CHATTER_PC_QUERY_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_CHATTER),
- ++ WMI_TLV_ECHO_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MISC),
- ++ WMI_TLV_PDEV_UTF_EVENTID,
- ++ WMI_TLV_DEBUG_MESG_EVENTID,
- ++ WMI_TLV_UPDATE_STATS_EVENTID,
- ++ WMI_TLV_DEBUG_PRINT_EVENTID,
- ++ WMI_TLV_DCS_INTERFERENCE_EVENTID,
- ++ WMI_TLV_PDEV_QVIT_EVENTID,
- ++ WMI_TLV_WLAN_PROFILE_DATA_EVENTID,
- ++ WMI_TLV_PDEV_FTM_INTG_EVENTID,
- ++ WMI_TLV_WLAN_FREQ_AVOID_EVENTID,
- ++ WMI_TLV_VDEV_GET_KEEPALIVE_EVENTID,
- ++ WMI_TLV_THERMAL_MGMT_EVENTID,
- ++ WMI_TLV_DIAG_DATA_CONTAINER_EVENTID,
- ++ WMI_TLV_HOST_AUTO_SHUTDOWN_EVENTID,
- ++ WMI_TLV_UPDATE_WHAL_MIB_STATS_EVENTID,
- ++ WMI_TLV_UPDATE_VDEV_RATE_STATS_EVENTID,
- ++ WMI_TLV_DIAG_EVENTID,
- ++ WMI_TLV_GPIO_INPUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_GPIO),
- ++ WMI_TLV_UPLOADH_EVENTID,
- ++ WMI_TLV_CAPTUREH_EVENTID,
- ++ WMI_TLV_RFKILL_STATE_CHANGE_EVENTID,
- ++ WMI_TLV_TDLS_PEER_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_TDLS),
- ++ WMI_TLV_BATCH_SCAN_ENABLED_EVENTID =
- ++ WMI_TLV_EV(WMI_TLV_GRP_LOCATION_SCAN),
- ++ WMI_TLV_BATCH_SCAN_RESULT_EVENTID,
- ++ WMI_TLV_OEM_CAPABILITY_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_OEM),
- ++ WMI_TLV_OEM_MEASUREMENT_REPORT_EVENTID,
- ++ WMI_TLV_OEM_ERROR_REPORT_EVENTID,
- ++ WMI_TLV_NAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_NAN),
- ++ WMI_TLV_LPI_RESULT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_LPI),
- ++ WMI_TLV_LPI_STATUS_EVENTID,
- ++ WMI_TLV_LPI_HANDOFF_EVENTID,
- ++ WMI_TLV_EXTSCAN_START_STOP_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_EXTSCAN),
- ++ WMI_TLV_EXTSCAN_OPERATION_EVENTID,
- ++ WMI_TLV_EXTSCAN_TABLE_USAGE_EVENTID,
- ++ WMI_TLV_EXTSCAN_CACHED_RESULTS_EVENTID,
- ++ WMI_TLV_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID,
- ++ WMI_TLV_EXTSCAN_HOTLIST_MATCH_EVENTID,
- ++ WMI_TLV_EXTSCAN_CAPABILITIES_EVENTID,
- ++ WMI_TLV_MDNS_STATS_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MDNS_OFL),
- ++ WMI_TLV_SAP_OFL_ADD_STA_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SAP_OFL),
- ++ WMI_TLV_SAP_OFL_DEL_STA_EVENTID,
- ++};
- ++
- ++enum wmi_tlv_pdev_param {
- ++ WMI_TLV_PDEV_PARAM_TX_CHAIN_MASK = 0x1,
- ++ WMI_TLV_PDEV_PARAM_RX_CHAIN_MASK,
- ++ WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT2G,
- ++ WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT5G,
- ++ WMI_TLV_PDEV_PARAM_TXPOWER_SCALE,
- ++ WMI_TLV_PDEV_PARAM_BEACON_GEN_MODE,
- ++ WMI_TLV_PDEV_PARAM_BEACON_TX_MODE,
- ++ WMI_TLV_PDEV_PARAM_RESMGR_OFFCHAN_MODE,
- ++ WMI_TLV_PDEV_PARAM_PROTECTION_MODE,
- ++ WMI_TLV_PDEV_PARAM_DYNAMIC_BW,
- ++ WMI_TLV_PDEV_PARAM_NON_AGG_SW_RETRY_TH,
- ++ WMI_TLV_PDEV_PARAM_AGG_SW_RETRY_TH,
- ++ WMI_TLV_PDEV_PARAM_STA_KICKOUT_TH,
- ++ WMI_TLV_PDEV_PARAM_AC_AGGRSIZE_SCALING,
- ++ WMI_TLV_PDEV_PARAM_LTR_ENABLE,
- ++ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BE,
- ++ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BK,
- ++ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VI,
- ++ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VO,
- ++ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT,
- ++ WMI_TLV_PDEV_PARAM_LTR_SLEEP_OVERRIDE,
- ++ WMI_TLV_PDEV_PARAM_LTR_RX_OVERRIDE,
- ++ WMI_TLV_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT,
- ++ WMI_TLV_PDEV_PARAM_L1SS_ENABLE,
- ++ WMI_TLV_PDEV_PARAM_DSLEEP_ENABLE,
- ++ WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_FLUSH,
- ++ WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_WATERMARK,
- ++ WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN,
- ++ WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE,
- ++ WMI_TLV_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD,
- ++ WMI_TLV_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD,
- ++ WMI_TLV_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD,
- ++ WMI_TLV_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
- ++ WMI_TLV_PDEV_PARAM_PMF_QOS,
- ++ WMI_TLV_PDEV_PARAM_ARP_AC_OVERRIDE,
- ++ WMI_TLV_PDEV_PARAM_DCS,
- ++ WMI_TLV_PDEV_PARAM_ANI_ENABLE,
- ++ WMI_TLV_PDEV_PARAM_ANI_POLL_PERIOD,
- ++ WMI_TLV_PDEV_PARAM_ANI_LISTEN_PERIOD,
- ++ WMI_TLV_PDEV_PARAM_ANI_OFDM_LEVEL,
- ++ WMI_TLV_PDEV_PARAM_ANI_CCK_LEVEL,
- ++ WMI_TLV_PDEV_PARAM_DYNTXCHAIN,
- ++ WMI_TLV_PDEV_PARAM_PROXY_STA,
- ++ WMI_TLV_PDEV_PARAM_IDLE_PS_CONFIG,
- ++ WMI_TLV_PDEV_PARAM_POWER_GATING_SLEEP,
- ++ WMI_TLV_PDEV_PARAM_RFKILL_ENABLE,
- ++ WMI_TLV_PDEV_PARAM_BURST_DUR,
- ++ WMI_TLV_PDEV_PARAM_BURST_ENABLE,
- ++ WMI_TLV_PDEV_PARAM_HW_RFKILL_CONFIG,
- ++ WMI_TLV_PDEV_PARAM_LOW_POWER_RF_ENABLE,
- ++ WMI_TLV_PDEV_PARAM_L1SS_TRACK,
- ++ WMI_TLV_PDEV_PARAM_HYST_EN,
- ++ WMI_TLV_PDEV_PARAM_POWER_COLLAPSE_ENABLE,
- ++ WMI_TLV_PDEV_PARAM_LED_SYS_STATE,
- ++ WMI_TLV_PDEV_PARAM_LED_ENABLE,
- ++ WMI_TLV_PDEV_PARAM_AUDIO_OVER_WLAN_LATENCY,
- ++ WMI_TLV_PDEV_PARAM_AUDIO_OVER_WLAN_ENABLE,
- ++ WMI_TLV_PDEV_PARAM_WHAL_MIB_STATS_UPDATE_ENABLE,
- ++ WMI_TLV_PDEV_PARAM_VDEV_RATE_STATS_UPDATE_PERIOD,
- ++ WMI_TLV_PDEV_PARAM_TXPOWER_REASON_NONE,
- ++ WMI_TLV_PDEV_PARAM_TXPOWER_REASON_SAR,
- ++ WMI_TLV_PDEV_PARAM_TXPOWER_REASON_MAX,
- ++};
- ++
- ++enum wmi_tlv_vdev_param {
- ++ WMI_TLV_VDEV_PARAM_RTS_THRESHOLD = 0x1,
- ++ WMI_TLV_VDEV_PARAM_FRAGMENTATION_THRESHOLD,
- ++ WMI_TLV_VDEV_PARAM_BEACON_INTERVAL,
- ++ WMI_TLV_VDEV_PARAM_LISTEN_INTERVAL,
- ++ WMI_TLV_VDEV_PARAM_MULTICAST_RATE,
- ++ WMI_TLV_VDEV_PARAM_MGMT_TX_RATE,
- ++ WMI_TLV_VDEV_PARAM_SLOT_TIME,
- ++ WMI_TLV_VDEV_PARAM_PREAMBLE,
- ++ WMI_TLV_VDEV_PARAM_SWBA_TIME,
- ++ WMI_TLV_VDEV_STATS_UPDATE_PERIOD,
- ++ WMI_TLV_VDEV_PWRSAVE_AGEOUT_TIME,
- ++ WMI_TLV_VDEV_HOST_SWBA_INTERVAL,
- ++ WMI_TLV_VDEV_PARAM_DTIM_PERIOD,
- ++ WMI_TLV_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT,
- ++ WMI_TLV_VDEV_PARAM_WDS,
- ++ WMI_TLV_VDEV_PARAM_ATIM_WINDOW,
- ++ WMI_TLV_VDEV_PARAM_BMISS_COUNT_MAX,
- ++ WMI_TLV_VDEV_PARAM_BMISS_FIRST_BCNT,
- ++ WMI_TLV_VDEV_PARAM_BMISS_FINAL_BCNT,
- ++ WMI_TLV_VDEV_PARAM_FEATURE_WMM,
- ++ WMI_TLV_VDEV_PARAM_CHWIDTH,
- ++ WMI_TLV_VDEV_PARAM_CHEXTOFFSET,
- ++ WMI_TLV_VDEV_PARAM_DISABLE_HTPROTECTION,
- ++ WMI_TLV_VDEV_PARAM_STA_QUICKKICKOUT,
- ++ WMI_TLV_VDEV_PARAM_MGMT_RATE,
- ++ WMI_TLV_VDEV_PARAM_PROTECTION_MODE,
- ++ WMI_TLV_VDEV_PARAM_FIXED_RATE,
- ++ WMI_TLV_VDEV_PARAM_SGI,
- ++ WMI_TLV_VDEV_PARAM_LDPC,
- ++ WMI_TLV_VDEV_PARAM_TX_STBC,
- ++ WMI_TLV_VDEV_PARAM_RX_STBC,
- ++ WMI_TLV_VDEV_PARAM_INTRA_BSS_FWD,
- ++ WMI_TLV_VDEV_PARAM_DEF_KEYID,
- ++ WMI_TLV_VDEV_PARAM_NSS,
- ++ WMI_TLV_VDEV_PARAM_BCAST_DATA_RATE,
- ++ WMI_TLV_VDEV_PARAM_MCAST_DATA_RATE,
- ++ WMI_TLV_VDEV_PARAM_MCAST_INDICATE,
- ++ WMI_TLV_VDEV_PARAM_DHCP_INDICATE,
- ++ WMI_TLV_VDEV_PARAM_UNKNOWN_DEST_INDICATE,
- ++ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS,
- ++ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS,
- ++ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS,
- ++ WMI_TLV_VDEV_PARAM_AP_ENABLE_NAWDS,
- ++ WMI_TLV_VDEV_PARAM_ENABLE_RTSCTS,
- ++ WMI_TLV_VDEV_PARAM_TXBF,
- ++ WMI_TLV_VDEV_PARAM_PACKET_POWERSAVE,
- ++ WMI_TLV_VDEV_PARAM_DROP_UNENCRY,
- ++ WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE,
- ++ WMI_TLV_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
- ++ WMI_TLV_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE,
- ++ WMI_TLV_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM,
- ++ WMI_TLV_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE,
- ++ WMI_TLV_VDEV_PARAM_EARLY_RX_SLOP_STEP,
- ++ WMI_TLV_VDEV_PARAM_EARLY_RX_INIT_SLOP,
- ++ WMI_TLV_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE,
- ++ WMI_TLV_VDEV_PARAM_TX_PWRLIMIT,
- ++ WMI_TLV_VDEV_PARAM_SNR_NUM_FOR_CAL,
- ++ WMI_TLV_VDEV_PARAM_ROAM_FW_OFFLOAD,
- ++ WMI_TLV_VDEV_PARAM_ENABLE_RMC,
- ++ WMI_TLV_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS,
- ++ WMI_TLV_VDEV_PARAM_MAX_RATE,
- ++ WMI_TLV_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE,
- ++ WMI_TLV_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR,
- ++ WMI_TLV_VDEV_PARAM_EBT_RESYNC_TIMEOUT,
- ++ WMI_TLV_VDEV_PARAM_AGGR_TRIG_EVENT_ENABLE,
- ++ WMI_TLV_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED,
- ++ WMI_TLV_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED,
- ++ WMI_TLV_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED,
- ++ WMI_TLV_VDEV_PARAM_INACTIVITY_CNT,
- ++ WMI_TLV_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS,
- ++ WMI_TLV_VDEV_PARAM_DTIM_POLICY,
- ++ WMI_TLV_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS,
- ++ WMI_TLV_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE,
- ++};
- ++
- ++enum wmi_tlv_tag {
- ++ WMI_TLV_TAG_LAST_RESERVED = 15,
- ++
- ++ WMI_TLV_TAG_FIRST_ARRAY_ENUM,
- ++ WMI_TLV_TAG_ARRAY_UINT32 = WMI_TLV_TAG_FIRST_ARRAY_ENUM,
- ++ WMI_TLV_TAG_ARRAY_BYTE,
- ++ WMI_TLV_TAG_ARRAY_STRUCT,
- ++ WMI_TLV_TAG_ARRAY_FIXED_STRUCT,
- ++ WMI_TLV_TAG_LAST_ARRAY_ENUM = 31,
- ++
- ++ WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT,
- ++ WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES,
- ++ WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ,
- ++ WMI_TLV_TAG_STRUCT_READY_EVENT,
- ++ WMI_TLV_TAG_STRUCT_SCAN_EVENT,
- ++ WMI_TLV_TAG_STRUCT_PDEV_TPC_CONFIG_EVENT,
- ++ WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT,
- ++ WMI_TLV_TAG_STRUCT_COMB_PHYERR_RX_HDR,
- ++ WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT,
- ++ WMI_TLV_TAG_STRUCT_VDEV_STOPPED_EVENT,
- ++ WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_COMPLETE_EVENT,
- ++ WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT,
- ++ WMI_TLV_TAG_STRUCT_MGMT_RX_HDR,
- ++ WMI_TLV_TAG_STRUCT_TBTT_OFFSET_EVENT,
- ++ WMI_TLV_TAG_STRUCT_TX_DELBA_COMPLETE_EVENT,
- ++ WMI_TLV_TAG_STRUCT_TX_ADDBA_COMPLETE_EVENT,
- ++ WMI_TLV_TAG_STRUCT_ROAM_EVENT,
- ++ WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO,
- ++ WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO_SECTION_BITMAP,
- ++ WMI_TLV_TAG_STRUCT_RTT_EVENT_HEADER,
- ++ WMI_TLV_TAG_STRUCT_RTT_ERROR_REPORT_EVENT,
- ++ WMI_TLV_TAG_STRUCT_RTT_MEAS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_ECHO_EVENT,
- ++ WMI_TLV_TAG_STRUCT_FTM_INTG_EVENT,
- ++ WMI_TLV_TAG_STRUCT_VDEV_GET_KEEPALIVE_EVENT,
- ++ WMI_TLV_TAG_STRUCT_GPIO_INPUT_EVENT,
- ++ WMI_TLV_TAG_STRUCT_CSA_EVENT,
- ++ WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_STATUS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_IGTK_INFO,
- ++ WMI_TLV_TAG_STRUCT_DCS_INTERFERENCE_EVENT,
- ++ WMI_TLV_TAG_STRUCT_ATH_DCS_CW_INT,
- ++ WMI_TLV_TAG_STRUCT_ATH_DCS_WLAN_INT_STAT,
- ++ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_CTX_T,
- ++ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_T,
- ++ WMI_TLV_TAG_STRUCT_PDEV_QVIT_EVENT,
- ++ WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT,
- ++ WMI_TLV_TAG_STRUCT_TIM_INFO,
- ++ WMI_TLV_TAG_STRUCT_P2P_NOA_INFO,
- ++ WMI_TLV_TAG_STRUCT_STATS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_AVOID_FREQ_RANGES_EVENT,
- ++ WMI_TLV_TAG_STRUCT_AVOID_FREQ_RANGE_DESC,
- ++ WMI_TLV_TAG_STRUCT_GTK_REKEY_FAIL_EVENT,
- ++ WMI_TLV_TAG_STRUCT_INIT_CMD,
- ++ WMI_TLV_TAG_STRUCT_RESOURCE_CONFIG,
- ++ WMI_TLV_TAG_STRUCT_WLAN_HOST_MEMORY_CHUNK,
- ++ WMI_TLV_TAG_STRUCT_START_SCAN_CMD,
- ++ WMI_TLV_TAG_STRUCT_STOP_SCAN_CMD,
- ++ WMI_TLV_TAG_STRUCT_SCAN_CHAN_LIST_CMD,
- ++ WMI_TLV_TAG_STRUCT_CHANNEL,
- ++ WMI_TLV_TAG_STRUCT_PDEV_SET_REGDOMAIN_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_SET_PARAM_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_SET_WMM_PARAMS_CMD,
- ++ WMI_TLV_TAG_STRUCT_WMM_PARAMS,
- ++ WMI_TLV_TAG_STRUCT_PDEV_SET_QUIET_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_CREATE_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_DELETE_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_START_REQUEST_CMD,
- ++ WMI_TLV_TAG_STRUCT_P2P_NOA_DESCRIPTOR,
- ++ WMI_TLV_TAG_STRUCT_P2P_GO_SET_BEACON_IE,
- ++ WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_UP_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_STOP_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_DOWN_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_SET_PARAM_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_CMD,
- ++ WMI_TLV_TAG_STRUCT_PEER_CREATE_CMD,
- ++ WMI_TLV_TAG_STRUCT_PEER_DELETE_CMD,
- ++ WMI_TLV_TAG_STRUCT_PEER_FLUSH_TIDS_CMD,
- ++ WMI_TLV_TAG_STRUCT_PEER_SET_PARAM_CMD,
- ++ WMI_TLV_TAG_STRUCT_PEER_ASSOC_COMPLETE_CMD,
- ++ WMI_TLV_TAG_STRUCT_VHT_RATE_SET,
- ++ WMI_TLV_TAG_STRUCT_BCN_TMPL_CMD,
- ++ WMI_TLV_TAG_STRUCT_PRB_TMPL_CMD,
- ++ WMI_TLV_TAG_STRUCT_BCN_PRB_INFO,
- ++ WMI_TLV_TAG_STRUCT_PEER_TID_ADDBA_CMD,
- ++ WMI_TLV_TAG_STRUCT_PEER_TID_DELBA_CMD,
- ++ WMI_TLV_TAG_STRUCT_STA_POWERSAVE_MODE_CMD,
- ++ WMI_TLV_TAG_STRUCT_STA_POWERSAVE_PARAM_CMD,
- ++ WMI_TLV_TAG_STRUCT_STA_DTIM_PS_METHOD_CMD,
- ++ WMI_TLV_TAG_STRUCT_ROAM_SCAN_MODE,
- ++ WMI_TLV_TAG_STRUCT_ROAM_SCAN_RSSI_THRESHOLD,
- ++ WMI_TLV_TAG_STRUCT_ROAM_SCAN_PERIOD,
- ++ WMI_TLV_TAG_STRUCT_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_SUSPEND_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_RESUME_CMD,
- ++ WMI_TLV_TAG_STRUCT_ADD_BCN_FILTER_CMD,
- ++ WMI_TLV_TAG_STRUCT_RMV_BCN_FILTER_CMD,
- ++ WMI_TLV_TAG_STRUCT_WOW_ENABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_WOW_HOSTWAKEUP_FROM_SLEEP_CMD,
- ++ WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_CMD,
- ++ WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_PARAM,
- ++ WMI_TLV_TAG_STRUCT_SET_ARP_NS_OFFLOAD_CMD,
- ++ WMI_TLV_TAG_STRUCT_ARP_OFFLOAD_TUPLE,
- ++ WMI_TLV_TAG_STRUCT_NS_OFFLOAD_TUPLE,
- ++ WMI_TLV_TAG_STRUCT_FTM_INTG_CMD,
- ++ WMI_TLV_TAG_STRUCT_STA_KEEPALIVE_CMD,
- ++ WMI_TLV_TAG_STRUCT_STA_KEEPALVE_ARP_RESPONSE,
- ++ WMI_TLV_TAG_STRUCT_P2P_SET_VENDOR_IE_DATA_CMD,
- ++ WMI_TLV_TAG_STRUCT_AP_PS_PEER_CMD,
- ++ WMI_TLV_TAG_STRUCT_PEER_RATE_RETRY_SCHED_CMD,
- ++ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_TRIGGER_CMD,
- ++ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_SET_HIST_INTVL_CMD,
- ++ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_GET_PROF_DATA_CMD,
- ++ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_ENABLE_PROFILE_ID_CMD,
- ++ WMI_TLV_TAG_STRUCT_WOW_DEL_PATTERN_CMD,
- ++ WMI_TLV_TAG_STRUCT_WOW_ADD_DEL_EVT_CMD,
- ++ WMI_TLV_TAG_STRUCT_RTT_MEASREQ_HEAD,
- ++ WMI_TLV_TAG_STRUCT_RTT_MEASREQ_BODY,
- ++ WMI_TLV_TAG_STRUCT_RTT_TSF_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_CONFIGURE_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_ENABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD,
- ++ WMI_TLV_TAG_STRUCT_NLO_CONFIG_CMD,
- ++ WMI_TLV_TAG_STRUCT_NLO_CONFIGURED_PARAMETERS,
- ++ WMI_TLV_TAG_STRUCT_CSA_OFFLOAD_ENABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_CSA_OFFLOAD_CHANSWITCH_CMD,
- ++ WMI_TLV_TAG_STRUCT_CHATTER_SET_MODE_CMD,
- ++ WMI_TLV_TAG_STRUCT_ECHO_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_SET_KEEPALIVE_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_GET_KEEPALIVE_CMD,
- ++ WMI_TLV_TAG_STRUCT_FORCE_FW_HANG_CMD,
- ++ WMI_TLV_TAG_STRUCT_GPIO_CONFIG_CMD,
- ++ WMI_TLV_TAG_STRUCT_GPIO_OUTPUT_CMD,
- ++ WMI_TLV_TAG_STRUCT_PEER_ADD_WDS_ENTRY_CMD,
- ++ WMI_TLV_TAG_STRUCT_PEER_REMOVE_WDS_ENTRY_CMD,
- ++ WMI_TLV_TAG_STRUCT_BCN_TX_HDR,
- ++ WMI_TLV_TAG_STRUCT_BCN_SEND_FROM_HOST_CMD,
- ++ WMI_TLV_TAG_STRUCT_MGMT_TX_HDR,
- ++ WMI_TLV_TAG_STRUCT_ADDBA_CLEAR_RESP_CMD,
- ++ WMI_TLV_TAG_STRUCT_ADDBA_SEND_CMD,
- ++ WMI_TLV_TAG_STRUCT_DELBA_SEND_CMD,
- ++ WMI_TLV_TAG_STRUCT_ADDBA_SETRESPONSE_CMD,
- ++ WMI_TLV_TAG_STRUCT_SEND_SINGLEAMSDU_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_ENABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_DISABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_SET_HT_IE_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_SET_VHT_IE_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_SET_DSCP_TID_MAP_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_GREEN_AP_PS_ENABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_GET_TPC_CONFIG_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_SET_BASE_MACADDR_CMD,
- ++ WMI_TLV_TAG_STRUCT_PEER_MCAST_GROUP_CMD,
- ++ WMI_TLV_TAG_STRUCT_ROAM_AP_PROFILE,
- ++ WMI_TLV_TAG_STRUCT_AP_PROFILE,
- ++ WMI_TLV_TAG_STRUCT_SCAN_SCH_PRIORITY_TABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_DFS_ENABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_DFS_DISABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_WOW_ADD_PATTERN_CMD,
- ++ WMI_TLV_TAG_STRUCT_WOW_BITMAP_PATTERN_T,
- ++ WMI_TLV_TAG_STRUCT_WOW_IPV4_SYNC_PATTERN_T,
- ++ WMI_TLV_TAG_STRUCT_WOW_IPV6_SYNC_PATTERN_T,
- ++ WMI_TLV_TAG_STRUCT_WOW_MAGIC_PATTERN_CMD,
- ++ WMI_TLV_TAG_STRUCT_SCAN_UPDATE_REQUEST_CMD,
- ++ WMI_TLV_TAG_STRUCT_CHATTER_PKT_COALESCING_FILTER,
- ++ WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_ADD_FILTER_CMD,
- ++ WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_DELETE_FILTER_CMD,
- ++ WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_QUERY_CMD,
- ++ WMI_TLV_TAG_STRUCT_TXBF_CMD,
- ++ WMI_TLV_TAG_STRUCT_DEBUG_LOG_CONFIG_CMD,
- ++ WMI_TLV_TAG_STRUCT_NLO_EVENT,
- ++ WMI_TLV_TAG_STRUCT_CHATTER_QUERY_REPLY_EVENT,
- ++ WMI_TLV_TAG_STRUCT_UPLOAD_H_HDR,
- ++ WMI_TLV_TAG_STRUCT_CAPTURE_H_EVENT_HDR,
- ++ WMI_TLV_TAG_STRUCT_VDEV_WNM_SLEEPMODE_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_WMM_ADDTS_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_WMM_DELTS_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_SET_WMM_PARAMS_CMD,
- ++ WMI_TLV_TAG_STRUCT_TDLS_SET_STATE_CMD,
- ++ WMI_TLV_TAG_STRUCT_TDLS_PEER_UPDATE_CMD,
- ++ WMI_TLV_TAG_STRUCT_TDLS_PEER_EVENT,
- ++ WMI_TLV_TAG_STRUCT_TDLS_PEER_CAPABILITIES,
- ++ WMI_TLV_TAG_STRUCT_VDEV_MCC_SET_TBTT_MODE_CMD,
- ++ WMI_TLV_TAG_STRUCT_ROAM_CHAN_LIST,
- ++ WMI_TLV_TAG_STRUCT_VDEV_MCC_BCN_INTVL_CHANGE_EVENT,
- ++ WMI_TLV_TAG_STRUCT_RESMGR_ADAPTIVE_OCS_CMD,
- ++ WMI_TLV_TAG_STRUCT_RESMGR_SET_CHAN_TIME_QUOTA_CMD,
- ++ WMI_TLV_TAG_STRUCT_RESMGR_SET_CHAN_LATENCY_CMD,
- ++ WMI_TLV_TAG_STRUCT_BA_REQ_SSN_CMD,
- ++ WMI_TLV_TAG_STRUCT_BA_RSP_SSN_EVENT,
- ++ WMI_TLV_TAG_STRUCT_STA_SMPS_FORCE_MODE_CMD,
- ++ WMI_TLV_TAG_STRUCT_SET_MCASTBCAST_FILTER_CMD,
- ++ WMI_TLV_TAG_STRUCT_P2P_SET_OPPPS_CMD,
- ++ WMI_TLV_TAG_STRUCT_P2P_SET_NOA_CMD,
- ++ WMI_TLV_TAG_STRUCT_BA_REQ_SSN_CMD_SUB_STRUCT_PARAM,
- ++ WMI_TLV_TAG_STRUCT_BA_REQ_SSN_EVENT_SUB_STRUCT_PARAM,
- ++ WMI_TLV_TAG_STRUCT_STA_SMPS_PARAM_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_SET_GTX_PARAMS_CMD,
- ++ WMI_TLV_TAG_STRUCT_MCC_SCHED_TRAFFIC_STATS_CMD,
- ++ WMI_TLV_TAG_STRUCT_MCC_SCHED_STA_TRAFFIC_STATS,
- ++ WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_P2P_NOA_EVENT,
- ++ WMI_TLV_TAG_STRUCT_HB_SET_ENABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_HB_SET_TCP_PARAMS_CMD,
- ++ WMI_TLV_TAG_STRUCT_HB_SET_TCP_PKT_FILTER_CMD,
- ++ WMI_TLV_TAG_STRUCT_HB_SET_UDP_PARAMS_CMD,
- ++ WMI_TLV_TAG_STRUCT_HB_SET_UDP_PKT_FILTER_CMD,
- ++ WMI_TLV_TAG_STRUCT_HB_IND_EVENT,
- ++ WMI_TLV_TAG_STRUCT_TX_PAUSE_EVENT,
- ++ WMI_TLV_TAG_STRUCT_RFKILL_EVENT,
- ++ WMI_TLV_TAG_STRUCT_DFS_RADAR_EVENT,
- ++ WMI_TLV_TAG_STRUCT_DFS_PHYERR_FILTER_ENA_CMD,
- ++ WMI_TLV_TAG_STRUCT_DFS_PHYERR_FILTER_DIS_CMD,
- ++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_SCAN_LIST,
- ++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_NETWORK_INFO,
- ++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_ENABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_DISABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_TRIGGER_RESULT_CMD,
- ++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_ENABLED_EVENT,
- ++ WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_EVENT,
- ++ WMI_TLV_TAG_STRUCT_VDEV_PLMREQ_START_CMD,
- ++ WMI_TLV_TAG_STRUCT_VDEV_PLMREQ_STOP_CMD,
- ++ WMI_TLV_TAG_STRUCT_THERMAL_MGMT_CMD,
- ++ WMI_TLV_TAG_STRUCT_THERMAL_MGMT_EVENT,
- ++ WMI_TLV_TAG_STRUCT_PEER_INFO_REQ_CMD,
- ++ WMI_TLV_TAG_STRUCT_PEER_INFO_EVENT,
- ++ WMI_TLV_TAG_STRUCT_PEER_INFO,
- ++ WMI_TLV_TAG_STRUCT_PEER_TX_FAIL_CNT_THR_EVENT,
- ++ WMI_TLV_TAG_STRUCT_RMC_SET_MODE_CMD,
- ++ WMI_TLV_TAG_STRUCT_RMC_SET_ACTION_PERIOD_CMD,
- ++ WMI_TLV_TAG_STRUCT_RMC_CONFIG_CMD,
- ++ WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_SET_MODE_CMD,
- ++ WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_PLUMB_ROUTING_TABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD,
- ++ WMI_TLV_TAG_STRUCT_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD,
- ++ WMI_TLV_TAG_STRUCT_NAN_CMD_PARAM,
- ++ WMI_TLV_TAG_STRUCT_NAN_EVENT_HDR,
- ++ WMI_TLV_TAG_STRUCT_PDEV_L1SS_TRACK_EVENT,
- ++ WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT,
- ++ WMI_TLV_TAG_STRUCT_MODEM_POWER_STATE_CMD_PARAM,
- ++ WMI_TLV_TAG_STRUCT_PEER_GET_ESTIMATED_LINKSPEED_CMD,
- ++ WMI_TLV_TAG_STRUCT_PEER_ESTIMATED_LINKSPEED_EVENT,
- ++ WMI_TLV_TAG_STRUCT_AGGR_STATE_TRIG_EVENT,
- ++ WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_ROUTING_TABLE_ENTRY,
- ++ WMI_TLV_TAG_STRUCT_ROAM_SCAN_CMD,
- ++ WMI_TLV_TAG_STRUCT_REQ_STATS_EXT_CMD,
- ++ WMI_TLV_TAG_STRUCT_STATS_EXT_EVENT,
- ++ WMI_TLV_TAG_STRUCT_OBSS_SCAN_ENABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_OBSS_SCAN_DISABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_OFFLOAD_PRB_RSP_TX_STATUS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_PDEV_SET_LED_CONFIG_CMD,
- ++ WMI_TLV_TAG_STRUCT_HOST_AUTO_SHUTDOWN_CFG_CMD,
- ++ WMI_TLV_TAG_STRUCT_HOST_AUTO_SHUTDOWN_EVENT,
- ++ WMI_TLV_TAG_STRUCT_UPDATE_WHAL_MIB_STATS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_CHAN_AVOID_UPDATE_CMD_PARAM,
- ++ WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_PKT_PATTERN_T,
- ++ WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_TMR_PATTERN_T,
- ++ WMI_TLV_TAG_STRUCT_WOW_IOAC_ADD_KEEPALIVE_CMD,
- ++ WMI_TLV_TAG_STRUCT_WOW_IOAC_DEL_KEEPALIVE_CMD,
- ++ WMI_TLV_TAG_STRUCT_WOW_IOAC_KEEPALIVE_T,
- ++ WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_ADD_PATTERN_CMD,
- ++ WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_DEL_PATTERN_CMD,
- ++ WMI_TLV_TAG_STRUCT_START_LINK_STATS_CMD,
- ++ WMI_TLV_TAG_STRUCT_CLEAR_LINK_STATS_CMD,
- ++ WMI_TLV_TAG_STRUCT_REQUEST_LINK_STATS_CMD,
- ++ WMI_TLV_TAG_STRUCT_IFACE_LINK_STATS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_RADIO_LINK_STATS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_PEER_STATS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_CHANNEL_STATS,
- ++ WMI_TLV_TAG_STRUCT_RADIO_LINK_STATS,
- ++ WMI_TLV_TAG_STRUCT_RATE_STATS,
- ++ WMI_TLV_TAG_STRUCT_PEER_LINK_STATS,
- ++ WMI_TLV_TAG_STRUCT_WMM_AC_STATS,
- ++ WMI_TLV_TAG_STRUCT_IFACE_LINK_STATS,
- ++ WMI_TLV_TAG_STRUCT_LPI_MGMT_SNOOPING_CONFIG_CMD,
- ++ WMI_TLV_TAG_STRUCT_LPI_START_SCAN_CMD,
- ++ WMI_TLV_TAG_STRUCT_LPI_STOP_SCAN_CMD,
- ++ WMI_TLV_TAG_STRUCT_LPI_RESULT_EVENT,
- ++ WMI_TLV_TAG_STRUCT_PEER_STATE_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_BUCKET_CMD,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_BUCKET_CHANNEL_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_START_CMD,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_STOP_CMD,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMD,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_BSSID_PARAM_CMD,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMD,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_GET_CACHED_RESULTS_CMD,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMD,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_SET_CAPABILITIES_CMD,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_GET_CAPABILITIES_CMD,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_OPERATION_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_START_STOP_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_TABLE_USAGE_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_DESCRIPTOR_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_RSSI_INFO_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_CACHED_RESULTS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_RESULTS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_RESULT_BSSID_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_MATCH_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_CAPABILITIES_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_CACHE_CAPABILITIES_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_MONITOR_CAPABILITIES_EVENT,
- ++ WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_MONITOR_CAPABILITIES_EVENT,
- ++ WMI_TLV_TAG_STRUCT_D0_WOW_ENABLE_DISABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_D0_WOW_DISABLE_ACK_EVENT,
- ++ WMI_TLV_TAG_STRUCT_UNIT_TEST_CMD,
- ++ WMI_TLV_TAG_STRUCT_ROAM_OFFLOAD_TLV_PARAM,
- ++ WMI_TLV_TAG_STRUCT_ROAM_11I_OFFLOAD_TLV_PARAM,
- ++ WMI_TLV_TAG_STRUCT_ROAM_11R_OFFLOAD_TLV_PARAM,
- ++ WMI_TLV_TAG_STRUCT_ROAM_ESE_OFFLOAD_TLV_PARAM,
- ++ WMI_TLV_TAG_STRUCT_ROAM_SYNCH_EVENT,
- ++ WMI_TLV_TAG_STRUCT_ROAM_SYNCH_COMPLETE,
- ++ WMI_TLV_TAG_STRUCT_EXTWOW_ENABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_EXTWOW_SET_APP_TYPE1_PARAMS_CMD,
- ++ WMI_TLV_TAG_STRUCT_EXTWOW_SET_APP_TYPE2_PARAMS_CMD,
- ++ WMI_TLV_TAG_STRUCT_LPI_STATUS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_LPI_HANDOFF_EVENT,
- ++ WMI_TLV_TAG_STRUCT_VDEV_RATE_STATS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_VDEV_RATE_HT_INFO,
- ++ WMI_TLV_TAG_STRUCT_RIC_REQUEST,
- ++ WMI_TLV_TAG_STRUCT_PDEV_GET_TEMPERATURE_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_TEMPERATURE_EVENT,
- ++ WMI_TLV_TAG_STRUCT_SET_DHCP_SERVER_OFFLOAD_CMD,
- ++ WMI_TLV_TAG_STRUCT_TPC_CHAINMASK_CONFIG_CMD,
- ++ WMI_TLV_TAG_STRUCT_RIC_TSPEC,
- ++ WMI_TLV_TAG_STRUCT_TPC_CHAINMASK_CONFIG,
- ++ WMI_TLV_TAG_STRUCT_IPA_OFFLOAD_CMD,
- ++ WMI_TLV_TAG_STRUCT_SCAN_PROB_REQ_OUI_CMD,
- ++ WMI_TLV_TAG_STRUCT_KEY_MATERIAL,
- ++ WMI_TLV_TAG_STRUCT_TDLS_SET_OFFCHAN_MODE_CMD,
- ++ WMI_TLV_TAG_STRUCT_SET_LED_FLASHING_CMD,
- ++ WMI_TLV_TAG_STRUCT_MDNS_OFFLOAD_CMD,
- ++ WMI_TLV_TAG_STRUCT_MDNS_SET_FQDN_CMD,
- ++ WMI_TLV_TAG_STRUCT_MDNS_SET_RESP_CMD,
- ++ WMI_TLV_TAG_STRUCT_MDNS_GET_STATS_CMD,
- ++ WMI_TLV_TAG_STRUCT_MDNS_STATS_EVENT,
- ++ WMI_TLV_TAG_STRUCT_ROAM_INVOKE_CMD,
- ++ WMI_TLV_TAG_STRUCT_PDEV_RESUME_EVENT,
- ++ WMI_TLV_TAG_STRUCT_PDEV_SET_ANTENNA_DIVERSITY_CMD,
- ++ WMI_TLV_TAG_STRUCT_SAP_OFL_ENABLE_CMD,
- ++ WMI_TLV_TAG_STRUCT_SAP_OFL_ADD_STA_EVENT,
- ++ WMI_TLV_TAG_STRUCT_SAP_OFL_DEL_STA_EVENT,
- ++ WMI_TLV_TAG_STRUCT_APFIND_CMD_PARAM,
- ++ WMI_TLV_TAG_STRUCT_APFIND_EVENT_HDR,
- ++
- ++ WMI_TLV_TAG_MAX
- ++};
- ++
- ++enum wmi_tlv_service {
- ++ WMI_TLV_SERVICE_BEACON_OFFLOAD = 0,
- ++ WMI_TLV_SERVICE_SCAN_OFFLOAD,
- ++ WMI_TLV_SERVICE_ROAM_SCAN_OFFLOAD,
- ++ WMI_TLV_SERVICE_BCN_MISS_OFFLOAD,
- ++ WMI_TLV_SERVICE_STA_PWRSAVE,
- ++ WMI_TLV_SERVICE_STA_ADVANCED_PWRSAVE,
- ++ WMI_TLV_SERVICE_AP_UAPSD,
- ++ WMI_TLV_SERVICE_AP_DFS,
- ++ WMI_TLV_SERVICE_11AC,
- ++ WMI_TLV_SERVICE_BLOCKACK,
- ++ WMI_TLV_SERVICE_PHYERR,
- ++ WMI_TLV_SERVICE_BCN_FILTER,
- ++ WMI_TLV_SERVICE_RTT,
- ++ WMI_TLV_SERVICE_WOW,
- ++ WMI_TLV_SERVICE_RATECTRL_CACHE,
- ++ WMI_TLV_SERVICE_IRAM_TIDS,
- ++ WMI_TLV_SERVICE_ARPNS_OFFLOAD,
- ++ WMI_TLV_SERVICE_NLO,
- ++ WMI_TLV_SERVICE_GTK_OFFLOAD,
- ++ WMI_TLV_SERVICE_SCAN_SCH,
- ++ WMI_TLV_SERVICE_CSA_OFFLOAD,
- ++ WMI_TLV_SERVICE_CHATTER,
- ++ WMI_TLV_SERVICE_COEX_FREQAVOID,
- ++ WMI_TLV_SERVICE_PACKET_POWER_SAVE,
- ++ WMI_TLV_SERVICE_FORCE_FW_HANG,
- ++ WMI_TLV_SERVICE_GPIO,
- ++ WMI_TLV_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
- ++ WMI_TLV_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
- ++ WMI_TLV_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
- ++ WMI_TLV_SERVICE_STA_KEEP_ALIVE,
- ++ WMI_TLV_SERVICE_TX_ENCAP,
- ++ WMI_TLV_SERVICE_AP_PS_DETECT_OUT_OF_SYNC,
- ++ WMI_TLV_SERVICE_EARLY_RX,
- ++ WMI_TLV_SERVICE_STA_SMPS,
- ++ WMI_TLV_SERVICE_FWTEST,
- ++ WMI_TLV_SERVICE_STA_WMMAC,
- ++ WMI_TLV_SERVICE_TDLS,
- ++ WMI_TLV_SERVICE_BURST,
- ++ WMI_TLV_SERVICE_MCC_BCN_INTERVAL_CHANGE,
- ++ WMI_TLV_SERVICE_ADAPTIVE_OCS,
- ++ WMI_TLV_SERVICE_BA_SSN_SUPPORT,
- ++ WMI_TLV_SERVICE_FILTER_IPSEC_NATKEEPALIVE,
- ++ WMI_TLV_SERVICE_WLAN_HB,
- ++ WMI_TLV_SERVICE_LTE_ANT_SHARE_SUPPORT,
- ++ WMI_TLV_SERVICE_BATCH_SCAN,
- ++ WMI_TLV_SERVICE_QPOWER,
- ++ WMI_TLV_SERVICE_PLMREQ,
- ++ WMI_TLV_SERVICE_THERMAL_MGMT,
- ++ WMI_TLV_SERVICE_RMC,
- ++ WMI_TLV_SERVICE_MHF_OFFLOAD,
- ++ WMI_TLV_SERVICE_COEX_SAR,
- ++ WMI_TLV_SERVICE_BCN_TXRATE_OVERRIDE,
- ++ WMI_TLV_SERVICE_NAN,
- ++ WMI_TLV_SERVICE_L1SS_STAT,
- ++ WMI_TLV_SERVICE_ESTIMATE_LINKSPEED,
- ++ WMI_TLV_SERVICE_OBSS_SCAN,
- ++ WMI_TLV_SERVICE_TDLS_OFFCHAN,
- ++ WMI_TLV_SERVICE_TDLS_UAPSD_BUFFER_STA,
- ++ WMI_TLV_SERVICE_TDLS_UAPSD_SLEEP_STA,
- ++ WMI_TLV_SERVICE_IBSS_PWRSAVE,
- ++ WMI_TLV_SERVICE_LPASS,
- ++ WMI_TLV_SERVICE_EXTSCAN,
- ++ WMI_TLV_SERVICE_D0WOW,
- ++ WMI_TLV_SERVICE_HSOFFLOAD,
- ++ WMI_TLV_SERVICE_ROAM_HO_OFFLOAD,
- ++ WMI_TLV_SERVICE_RX_FULL_REORDER,
- ++ WMI_TLV_SERVICE_DHCP_OFFLOAD,
- ++ WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
- ++ WMI_TLV_SERVICE_MDNS_OFFLOAD,
- ++ WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
- ++};
- ++
- ++#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
- ++ ((svc_id) < (len) && \
- ++ __le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
- ++ BIT((svc_id)%(sizeof(u32))))
- ++
- ++#define SVCMAP(x, y, len) \
- ++ do { \
- ++ if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \
- ++ __set_bit(y, out); \
- ++ } while (0)
- ++
- ++static inline void
- ++wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len)
- ++{
- ++ SVCMAP(WMI_TLV_SERVICE_BEACON_OFFLOAD,
- ++ WMI_SERVICE_BEACON_OFFLOAD, len);
- ++ SVCMAP(WMI_TLV_SERVICE_SCAN_OFFLOAD,
- ++ WMI_SERVICE_SCAN_OFFLOAD, len);
- ++ SVCMAP(WMI_TLV_SERVICE_ROAM_SCAN_OFFLOAD,
- ++ WMI_SERVICE_ROAM_SCAN_OFFLOAD, len);
- ++ SVCMAP(WMI_TLV_SERVICE_BCN_MISS_OFFLOAD,
- ++ WMI_SERVICE_BCN_MISS_OFFLOAD, len);
- ++ SVCMAP(WMI_TLV_SERVICE_STA_PWRSAVE,
- ++ WMI_SERVICE_STA_PWRSAVE, len);
- ++ SVCMAP(WMI_TLV_SERVICE_STA_ADVANCED_PWRSAVE,
- ++ WMI_SERVICE_STA_ADVANCED_PWRSAVE, len);
- ++ SVCMAP(WMI_TLV_SERVICE_AP_UAPSD,
- ++ WMI_SERVICE_AP_UAPSD, len);
- ++ SVCMAP(WMI_TLV_SERVICE_AP_DFS,
- ++ WMI_SERVICE_AP_DFS, len);
- ++ SVCMAP(WMI_TLV_SERVICE_11AC,
- ++ WMI_SERVICE_11AC, len);
- ++ SVCMAP(WMI_TLV_SERVICE_BLOCKACK,
- ++ WMI_SERVICE_BLOCKACK, len);
- ++ SVCMAP(WMI_TLV_SERVICE_PHYERR,
- ++ WMI_SERVICE_PHYERR, len);
- ++ SVCMAP(WMI_TLV_SERVICE_BCN_FILTER,
- ++ WMI_SERVICE_BCN_FILTER, len);
- ++ SVCMAP(WMI_TLV_SERVICE_RTT,
- ++ WMI_SERVICE_RTT, len);
- ++ SVCMAP(WMI_TLV_SERVICE_WOW,
- ++ WMI_SERVICE_WOW, len);
- ++ SVCMAP(WMI_TLV_SERVICE_RATECTRL_CACHE,
- ++ WMI_SERVICE_RATECTRL_CACHE, len);
- ++ SVCMAP(WMI_TLV_SERVICE_IRAM_TIDS,
- ++ WMI_SERVICE_IRAM_TIDS, len);
- ++ SVCMAP(WMI_TLV_SERVICE_ARPNS_OFFLOAD,
- ++ WMI_SERVICE_ARPNS_OFFLOAD, len);
- ++ SVCMAP(WMI_TLV_SERVICE_NLO,
- ++ WMI_SERVICE_NLO, len);
- ++ SVCMAP(WMI_TLV_SERVICE_GTK_OFFLOAD,
- ++ WMI_SERVICE_GTK_OFFLOAD, len);
- ++ SVCMAP(WMI_TLV_SERVICE_SCAN_SCH,
- ++ WMI_SERVICE_SCAN_SCH, len);
- ++ SVCMAP(WMI_TLV_SERVICE_CSA_OFFLOAD,
- ++ WMI_SERVICE_CSA_OFFLOAD, len);
- ++ SVCMAP(WMI_TLV_SERVICE_CHATTER,
- ++ WMI_SERVICE_CHATTER, len);
- ++ SVCMAP(WMI_TLV_SERVICE_COEX_FREQAVOID,
- ++ WMI_SERVICE_COEX_FREQAVOID, len);
- ++ SVCMAP(WMI_TLV_SERVICE_PACKET_POWER_SAVE,
- ++ WMI_SERVICE_PACKET_POWER_SAVE, len);
- ++ SVCMAP(WMI_TLV_SERVICE_FORCE_FW_HANG,
- ++ WMI_SERVICE_FORCE_FW_HANG, len);
- ++ SVCMAP(WMI_TLV_SERVICE_GPIO,
- ++ WMI_SERVICE_GPIO, len);
- ++ SVCMAP(WMI_TLV_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
- ++ WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, len);
- ++ SVCMAP(WMI_TLV_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
- ++ WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len);
- ++ SVCMAP(WMI_TLV_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
- ++ WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len);
- ++ SVCMAP(WMI_TLV_SERVICE_STA_KEEP_ALIVE,
- ++ WMI_SERVICE_STA_KEEP_ALIVE, len);
- ++ SVCMAP(WMI_TLV_SERVICE_TX_ENCAP,
- ++ WMI_SERVICE_TX_ENCAP, len);
- ++ SVCMAP(WMI_TLV_SERVICE_AP_PS_DETECT_OUT_OF_SYNC,
- ++ WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, len);
- ++ SVCMAP(WMI_TLV_SERVICE_EARLY_RX,
- ++ WMI_SERVICE_EARLY_RX, len);
- ++ SVCMAP(WMI_TLV_SERVICE_STA_SMPS,
- ++ WMI_SERVICE_STA_SMPS, len);
- ++ SVCMAP(WMI_TLV_SERVICE_FWTEST,
- ++ WMI_SERVICE_FWTEST, len);
- ++ SVCMAP(WMI_TLV_SERVICE_STA_WMMAC,
- ++ WMI_SERVICE_STA_WMMAC, len);
- ++ SVCMAP(WMI_TLV_SERVICE_TDLS,
- ++ WMI_SERVICE_TDLS, len);
- ++ SVCMAP(WMI_TLV_SERVICE_BURST,
- ++ WMI_SERVICE_BURST, len);
- ++ SVCMAP(WMI_TLV_SERVICE_MCC_BCN_INTERVAL_CHANGE,
- ++ WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE, len);
- ++ SVCMAP(WMI_TLV_SERVICE_ADAPTIVE_OCS,
- ++ WMI_SERVICE_ADAPTIVE_OCS, len);
- ++ SVCMAP(WMI_TLV_SERVICE_BA_SSN_SUPPORT,
- ++ WMI_SERVICE_BA_SSN_SUPPORT, len);
- ++ SVCMAP(WMI_TLV_SERVICE_FILTER_IPSEC_NATKEEPALIVE,
- ++ WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE, len);
- ++ SVCMAP(WMI_TLV_SERVICE_WLAN_HB,
- ++ WMI_SERVICE_WLAN_HB, len);
- ++ SVCMAP(WMI_TLV_SERVICE_LTE_ANT_SHARE_SUPPORT,
- ++ WMI_SERVICE_LTE_ANT_SHARE_SUPPORT, len);
- ++ SVCMAP(WMI_TLV_SERVICE_BATCH_SCAN,
- ++ WMI_SERVICE_BATCH_SCAN, len);
- ++ SVCMAP(WMI_TLV_SERVICE_QPOWER,
- ++ WMI_SERVICE_QPOWER, len);
- ++ SVCMAP(WMI_TLV_SERVICE_PLMREQ,
- ++ WMI_SERVICE_PLMREQ, len);
- ++ SVCMAP(WMI_TLV_SERVICE_THERMAL_MGMT,
- ++ WMI_SERVICE_THERMAL_MGMT, len);
- ++ SVCMAP(WMI_TLV_SERVICE_RMC,
- ++ WMI_SERVICE_RMC, len);
- ++ SVCMAP(WMI_TLV_SERVICE_MHF_OFFLOAD,
- ++ WMI_SERVICE_MHF_OFFLOAD, len);
- ++ SVCMAP(WMI_TLV_SERVICE_COEX_SAR,
- ++ WMI_SERVICE_COEX_SAR, len);
- ++ SVCMAP(WMI_TLV_SERVICE_BCN_TXRATE_OVERRIDE,
- ++ WMI_SERVICE_BCN_TXRATE_OVERRIDE, len);
- ++ SVCMAP(WMI_TLV_SERVICE_NAN,
- ++ WMI_SERVICE_NAN, len);
- ++ SVCMAP(WMI_TLV_SERVICE_L1SS_STAT,
- ++ WMI_SERVICE_L1SS_STAT, len);
- ++ SVCMAP(WMI_TLV_SERVICE_ESTIMATE_LINKSPEED,
- ++ WMI_SERVICE_ESTIMATE_LINKSPEED, len);
- ++ SVCMAP(WMI_TLV_SERVICE_OBSS_SCAN,
- ++ WMI_SERVICE_OBSS_SCAN, len);
- ++ SVCMAP(WMI_TLV_SERVICE_TDLS_OFFCHAN,
- ++ WMI_SERVICE_TDLS_OFFCHAN, len);
- ++ SVCMAP(WMI_TLV_SERVICE_TDLS_UAPSD_BUFFER_STA,
- ++ WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, len);
- ++ SVCMAP(WMI_TLV_SERVICE_TDLS_UAPSD_SLEEP_STA,
- ++ WMI_SERVICE_TDLS_UAPSD_SLEEP_STA, len);
- ++ SVCMAP(WMI_TLV_SERVICE_IBSS_PWRSAVE,
- ++ WMI_SERVICE_IBSS_PWRSAVE, len);
- ++ SVCMAP(WMI_TLV_SERVICE_LPASS,
- ++ WMI_SERVICE_LPASS, len);
- ++ SVCMAP(WMI_TLV_SERVICE_EXTSCAN,
- ++ WMI_SERVICE_EXTSCAN, len);
- ++ SVCMAP(WMI_TLV_SERVICE_D0WOW,
- ++ WMI_SERVICE_D0WOW, len);
- ++ SVCMAP(WMI_TLV_SERVICE_HSOFFLOAD,
- ++ WMI_SERVICE_HSOFFLOAD, len);
- ++ SVCMAP(WMI_TLV_SERVICE_ROAM_HO_OFFLOAD,
- ++ WMI_SERVICE_ROAM_HO_OFFLOAD, len);
- ++ SVCMAP(WMI_TLV_SERVICE_RX_FULL_REORDER,
- ++ WMI_SERVICE_RX_FULL_REORDER, len);
- ++ SVCMAP(WMI_TLV_SERVICE_DHCP_OFFLOAD,
- ++ WMI_SERVICE_DHCP_OFFLOAD, len);
- ++ SVCMAP(WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
- ++ WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, len);
- ++ SVCMAP(WMI_TLV_SERVICE_MDNS_OFFLOAD,
- ++ WMI_SERVICE_MDNS_OFFLOAD, len);
- ++ SVCMAP(WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
- ++ WMI_SERVICE_SAP_AUTH_OFFLOAD, len);
- ++}
- ++
- ++#undef SVCMAP
- ++
- ++struct wmi_tlv {
- ++ __le16 len;
- ++ __le16 tag;
- ++ u8 value[0];
- ++} __packed;
- ++
- ++#define WMI_TLV_MGMT_RX_NUM_RSSI 4
- ++
- ++struct wmi_tlv_mgmt_rx_ev {
- ++ __le32 channel;
- ++ __le32 snr;
- ++ __le32 rate;
- ++ __le32 phy_mode;
- ++ __le32 buf_len;
- ++ __le32 status;
- ++ __le32 rssi[WMI_TLV_MGMT_RX_NUM_RSSI];
- ++} __packed;
- ++
- ++struct wmi_tlv_abi_version {
- ++ __le32 abi_ver0;
- ++ __le32 abi_ver1;
- ++ __le32 abi_ver_ns0;
- ++ __le32 abi_ver_ns1;
- ++ __le32 abi_ver_ns2;
- ++ __le32 abi_ver_ns3;
- ++} __packed;
- ++
- ++enum wmi_tlv_hw_bd_id {
- ++ WMI_TLV_HW_BD_LEGACY = 0,
- ++ WMI_TLV_HW_BD_QCA6174 = 1,
- ++ WMI_TLV_HW_BD_QCA2582 = 2,
- ++};
- ++
- ++struct wmi_tlv_hw_bd_info {
- ++ u8 rev;
- ++ u8 project_id;
- ++ u8 custom_id;
- ++ u8 reference_design_id;
- ++} __packed;
- ++
- ++struct wmi_tlv_svc_rdy_ev {
- ++ __le32 fw_build_vers;
- ++ struct wmi_tlv_abi_version abi;
- ++ __le32 phy_capability;
- ++ __le32 max_frag_entry;
- ++ __le32 num_rf_chains;
- ++ __le32 ht_cap_info;
- ++ __le32 vht_cap_info;
- ++ __le32 vht_supp_mcs;
- ++ __le32 hw_min_tx_power;
- ++ __le32 hw_max_tx_power;
- ++ __le32 sys_cap_info;
- ++ __le32 min_pkt_size_enable;
- ++ __le32 max_bcn_ie_size;
- ++ __le32 num_mem_reqs;
- ++ __le32 max_num_scan_chans;
- ++ __le32 hw_bd_id; /* 0 means hw_bd_info is invalid */
- ++ struct wmi_tlv_hw_bd_info hw_bd_info[5];
- ++} __packed;
- ++
- ++struct wmi_tlv_rdy_ev {
- ++ struct wmi_tlv_abi_version abi;
- ++ struct wmi_mac_addr mac_addr;
- ++ __le32 status;
- ++} __packed;
- ++
- ++struct wmi_tlv_resource_config {
- ++ __le32 num_vdevs;
- ++ __le32 num_peers;
- ++ __le32 num_offload_peers;
- ++ __le32 num_offload_reorder_bufs;
- ++ __le32 num_peer_keys;
- ++ __le32 num_tids;
- ++ __le32 ast_skid_limit;
- ++ __le32 tx_chain_mask;
- ++ __le32 rx_chain_mask;
- ++ __le32 rx_timeout_pri[4];
- ++ __le32 rx_decap_mode;
- ++ __le32 scan_max_pending_reqs;
- ++ __le32 bmiss_offload_max_vdev;
- ++ __le32 roam_offload_max_vdev;
- ++ __le32 roam_offload_max_ap_profiles;
- ++ __le32 num_mcast_groups;
- ++ __le32 num_mcast_table_elems;
- ++ __le32 mcast2ucast_mode;
- ++ __le32 tx_dbg_log_size;
- ++ __le32 num_wds_entries;
- ++ __le32 dma_burst_size;
- ++ __le32 mac_aggr_delim;
- ++ __le32 rx_skip_defrag_timeout_dup_detection_check;
- ++ __le32 vow_config;
- ++ __le32 gtk_offload_max_vdev;
- ++ __le32 num_msdu_desc;
- ++ __le32 max_frag_entries;
- ++ __le32 num_tdls_vdevs;
- ++ __le32 num_tdls_conn_table_entries;
- ++ __le32 beacon_tx_offload_max_vdev;
- ++ __le32 num_multicast_filter_entries;
- ++ __le32 num_wow_filters;
- ++ __le32 num_keep_alive_pattern;
- ++ __le32 keep_alive_pattern_size;
- ++ __le32 max_tdls_concurrent_sleep_sta;
- ++ __le32 max_tdls_concurrent_buffer_sta;
- ++} __packed;
- ++
- ++struct wmi_tlv_init_cmd {
- ++ struct wmi_tlv_abi_version abi;
- ++ __le32 num_host_mem_chunks;
- ++} __packed;
- ++
- ++struct wmi_tlv_pdev_set_param_cmd {
- ++ __le32 pdev_id; /* not used yet */
- ++ __le32 param_id;
- ++ __le32 param_value;
- ++} __packed;
- ++
- ++struct wmi_tlv_pdev_set_rd_cmd {
- ++ __le32 pdev_id; /* not used yet */
- ++ __le32 regd;
- ++ __le32 regd_2ghz;
- ++ __le32 regd_5ghz;
- ++ __le32 conform_limit_2ghz;
- ++ __le32 conform_limit_5ghz;
- ++} __packed;
- ++
- ++struct wmi_tlv_scan_chan_list_cmd {
- ++ __le32 num_scan_chans;
- ++} __packed;
- ++
- ++struct wmi_tlv_start_scan_cmd {
- ++ struct wmi_start_scan_common common;
- ++ __le32 burst_duration_ms;
- ++ __le32 num_channels;
- ++ __le32 num_bssids;
- ++ __le32 num_ssids;
- ++ __le32 ie_len;
- ++ __le32 num_probes;
- ++} __packed;
- ++
- ++struct wmi_tlv_vdev_start_cmd {
- ++ __le32 vdev_id;
- ++ __le32 requestor_id;
- ++ __le32 bcn_intval;
- ++ __le32 dtim_period;
- ++ __le32 flags;
- ++ struct wmi_ssid ssid;
- ++ __le32 bcn_tx_rate;
- ++ __le32 bcn_tx_power;
- ++ __le32 num_noa_descr;
- ++ __le32 disable_hw_ack;
- ++} __packed;
- ++
- ++enum {
- ++ WMI_TLV_PEER_TYPE_DEFAULT = 0, /* generic / non-BSS / self-peer */
- ++ WMI_TLV_PEER_TYPE_BSS = 1,
- ++ WMI_TLV_PEER_TYPE_TDLS = 2,
- ++ WMI_TLV_PEER_TYPE_HOST_MAX = 127,
- ++ WMI_TLV_PEER_TYPE_ROAMOFFLOAD_TMP = 128,
- ++};
- ++
- ++struct wmi_tlv_peer_create_cmd {
- ++ __le32 vdev_id;
- ++ struct wmi_mac_addr peer_addr;
- ++ __le32 peer_type;
- ++} __packed;
- ++
- ++struct wmi_tlv_peer_assoc_cmd {
- ++ struct wmi_mac_addr mac_addr;
- ++ __le32 vdev_id;
- ++ __le32 new_assoc;
- ++ __le32 assoc_id;
- ++ __le32 flags;
- ++ __le32 caps;
- ++ __le32 listen_intval;
- ++ __le32 ht_caps;
- ++ __le32 max_mpdu;
- ++ __le32 mpdu_density;
- ++ __le32 rate_caps;
- ++ __le32 nss;
- ++ __le32 vht_caps;
- ++ __le32 phy_mode;
- ++ __le32 ht_info[2];
- ++ __le32 num_legacy_rates;
- ++ __le32 num_ht_rates;
- ++} __packed;
- ++
- ++struct wmi_tlv_pdev_suspend {
- ++ __le32 pdev_id; /* not used yet */
- ++ __le32 opt;
- ++} __packed;
- ++
- ++struct wmi_tlv_pdev_set_wmm_cmd {
- ++ __le32 pdev_id; /* not used yet */
- ++ __le32 dg_type; /* no idea.. */
- ++} __packed;
- ++
- ++struct wmi_tlv_vdev_wmm_params {
- ++ __le32 dummy;
- ++ struct wmi_wmm_params params;
- ++} __packed;
- ++
- ++struct wmi_tlv_vdev_set_wmm_cmd {
- ++ __le32 vdev_id;
- ++ struct wmi_tlv_vdev_wmm_params vdev_wmm_params[4];
- ++} __packed;
- ++
- ++struct wmi_tlv_phyerr_ev {
- ++ __le32 num_phyerrs;
- ++ __le32 tsf_l32;
- ++ __le32 tsf_u32;
- ++ __le32 buf_len;
- ++} __packed;
- ++
- ++enum wmi_tlv_dbglog_param {
- ++ WMI_TLV_DBGLOG_PARAM_LOG_LEVEL = 1,
- ++ WMI_TLV_DBGLOG_PARAM_VDEV_ENABLE,
- ++ WMI_TLV_DBGLOG_PARAM_VDEV_DISABLE,
- ++ WMI_TLV_DBGLOG_PARAM_VDEV_ENABLE_BITMAP,
- ++ WMI_TLV_DBGLOG_PARAM_VDEV_DISABLE_BITMAP,
- ++};
- ++
- ++enum wmi_tlv_dbglog_log_level {
- ++ WMI_TLV_DBGLOG_LOG_LEVEL_VERBOSE = 0,
- ++ WMI_TLV_DBGLOG_LOG_LEVEL_INFO,
- ++ WMI_TLV_DBGLOG_LOG_LEVEL_INFO_LVL_1,
- ++ WMI_TLV_DBGLOG_LOG_LEVEL_INFO_LVL_2,
- ++ WMI_TLV_DBGLOG_LOG_LEVEL_WARN,
- ++ WMI_TLV_DBGLOG_LOG_LEVEL_ERR,
- ++};
- ++
- ++#define WMI_TLV_DBGLOG_BITMAP_MAX_IDS 512
- ++#define WMI_TLV_DBGLOG_BITMAP_MAX_WORDS (WMI_TLV_DBGLOG_BITMAP_MAX_IDS / \
- ++ sizeof(__le32))
- ++#define WMI_TLV_DBGLOG_ALL_MODULES 0xffff
- ++#define WMI_TLV_DBGLOG_LOG_LEVEL_VALUE(module_id, log_level) \
- ++ (((module_id << 16) & 0xffff0000) | \
- ++ ((log_level << 0) & 0x000000ff))
- ++
- ++struct wmi_tlv_dbglog_cmd {
- ++ __le32 param;
- ++ __le32 value;
- ++} __packed;
- ++
- ++struct wmi_tlv_resume_cmd {
- ++ __le32 reserved;
- ++} __packed;
- ++
- ++struct wmi_tlv_req_stats_cmd {
- ++ __le32 stats_id; /* wmi_stats_id */
- ++ __le32 vdev_id;
- ++ struct wmi_mac_addr peer_macaddr;
- ++} __packed;
- ++
- ++struct wmi_tlv_vdev_stats {
- ++ __le32 vdev_id;
- ++ __le32 beacon_snr;
- ++ __le32 data_snr;
- ++ __le32 num_tx_frames[4]; /* per-AC */
- ++ __le32 num_rx_frames;
- ++ __le32 num_tx_frames_retries[4];
- ++ __le32 num_tx_frames_failures[4];
- ++ __le32 num_rts_fail;
- ++ __le32 num_rts_success;
- ++ __le32 num_rx_err;
- ++ __le32 num_rx_discard;
- ++ __le32 num_tx_not_acked;
- ++ __le32 tx_rate_history[10];
- ++ __le32 beacon_rssi_history[10];
- ++} __packed;
- ++
- ++struct wmi_tlv_pktlog_enable {
- ++ __le32 reserved;
- ++ __le32 filter;
- ++} __packed;
- ++
- ++struct wmi_tlv_pktlog_disable {
- ++ __le32 reserved;
- ++} __packed;
- ++
- ++enum wmi_tlv_bcn_tx_status {
- ++ WMI_TLV_BCN_TX_STATUS_OK,
- ++ WMI_TLV_BCN_TX_STATUS_XRETRY,
- ++ WMI_TLV_BCN_TX_STATUS_DROP,
- ++ WMI_TLV_BCN_TX_STATUS_FILTERED,
- ++};
- ++
- ++struct wmi_tlv_bcn_tx_status_ev {
- ++ __le32 vdev_id;
- ++ __le32 tx_status;
- ++} __packed;
- ++
- ++struct wmi_tlv_bcn_prb_info {
- ++ __le32 caps;
- ++ __le32 erp;
- ++ u8 ies[0];
- ++} __packed;
- ++
- ++struct wmi_tlv_bcn_tmpl_cmd {
- ++ __le32 vdev_id;
- ++ __le32 tim_ie_offset;
- ++ __le32 buf_len;
- ++} __packed;
- ++
- ++struct wmi_tlv_prb_tmpl_cmd {
- ++ __le32 vdev_id;
- ++ __le32 buf_len;
- ++} __packed;
- ++
- ++struct wmi_tlv_p2p_go_bcn_ie {
- ++ __le32 vdev_id;
- ++ __le32 ie_len;
- ++} __packed;
- ++
- ++enum wmi_tlv_diag_item_type {
- ++ WMI_TLV_DIAG_ITEM_TYPE_FW_EVENT,
- ++ WMI_TLV_DIAG_ITEM_TYPE_FW_LOG,
- ++ WMI_TLV_DIAG_ITEM_TYPE_FW_DEBUG_MSG,
- ++};
- ++
- ++struct wmi_tlv_diag_item {
- ++ u8 type;
- ++ u8 reserved;
- ++ __le16 len;
- ++ __le32 timestamp;
- ++ __le32 code;
- ++ u8 payload[0];
- ++} __packed;
- ++
- ++struct wmi_tlv_diag_data_ev {
- ++ __le32 num_items;
- ++} __packed;
- ++
- ++struct wmi_tlv_sta_keepalive_cmd {
- ++ __le32 vdev_id;
- ++ __le32 enabled;
- ++ __le32 method; /* WMI_STA_KEEPALIVE_METHOD_ */
- ++ __le32 interval; /* in seconds */
- ++} __packed;
- ++
- ++struct wmi_tlv_stats_ev {
- ++ __le32 stats_id; /* WMI_STAT_ */
- ++ __le32 num_pdev_stats;
- ++ __le32 num_vdev_stats;
- ++ __le32 num_peer_stats;
- ++ __le32 num_bcnflt_stats;
- ++ __le32 num_chan_stats;
- ++} __packed;
- ++
- ++void ath10k_wmi_tlv_attach(struct ath10k *ar);
- ++
- ++#endif
- +--- a/backport-include/linux/etherdevice.h
- ++++ b/backport-include/linux/etherdevice.h
- +@@ -148,6 +148,29 @@ static inline bool ether_addr_equal_unal
- + return memcmp(addr1, addr2, ETH_ALEN) == 0;
- + #endif
- + }
- ++
- ++/**
- ++ * ether_addr_copy - Copy an Ethernet address
- ++ * @dst: Pointer to a six-byte array Ethernet address destination
- ++ * @src: Pointer to a six-byte array Ethernet address source
- ++ *
- ++ * Please note: dst & src must both be aligned to u16.
- ++ */
- ++#define ether_addr_copy LINUX_BACKPORT(ether_addr_copy)
- ++static inline void ether_addr_copy(u8 *dst, const u8 *src)
- ++{
- ++#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
- ++ *(u32 *)dst = *(const u32 *)src;
- ++ *(u16 *)(dst + 4) = *(const u16 *)(src + 4);
- ++#else
- ++ u16 *a = (u16 *)dst;
- ++ const u16 *b = (const u16 *)src;
- ++
- ++ a[0] = b[0];
- ++ a[1] = b[1];
- ++ a[2] = b[2];
- ++#endif
- ++}
- + #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) */
- +
- + #endif /* _BACKPORT_LINUX_ETHERDEVICE_H */
- +--- a/drivers/net/wireless/ath/spectral_common.h
- ++++ b/drivers/net/wireless/ath/spectral_common.h
- +@@ -20,6 +20,11 @@
- + #define SPECTRAL_HT20_NUM_BINS 56
- + #define SPECTRAL_HT20_40_NUM_BINS 128
- +
- ++/* TODO: could possibly be 512, but no samples this large
- ++ * could be acquired so far.
- ++ */
- ++#define SPECTRAL_ATH10K_MAX_NUM_BINS 256
- ++
- + /* FFT sample format given to userspace via debugfs.
- + *
- + * Please keep the type/length at the front position and change
- +@@ -31,6 +36,7 @@
- + enum ath_fft_sample_type {
- + ATH_FFT_SAMPLE_HT20 = 1,
- + ATH_FFT_SAMPLE_HT20_40,
- ++ ATH_FFT_SAMPLE_ATH10K,
- + };
- +
- + struct fft_sample_tlv {
- +@@ -85,4 +91,23 @@ struct fft_sample_ht20_40 {
- + u8 data[SPECTRAL_HT20_40_NUM_BINS];
- + } __packed;
- +
- ++struct fft_sample_ath10k {
- ++ struct fft_sample_tlv tlv;
- ++ u8 chan_width_mhz;
- ++ __be16 freq1;
- ++ __be16 freq2;
- ++ __be16 noise;
- ++ __be16 max_magnitude;
- ++ __be16 total_gain_db;
- ++ __be16 base_pwr_db;
- ++ __be64 tsf;
- ++ s8 max_index;
- ++ u8 rssi;
- ++ u8 relpwr_db;
- ++ u8 avgpwr_db;
- ++ u8 max_exp;
- ++
- ++ u8 data[0];
- ++} __packed;
- ++
- + #endif /* SPECTRAL_COMMON_H */
- diff --git a/package/kernel/mac80211/patches/920-ath10k_allow_fallback_to_board_bin_on_empty_otp_stream.patch b/package/kernel/mac80211/patches/920-ath10k_allow_fallback_to_board_bin_on_empty_otp_stream.patch
- index 6a5c766..6a3d2a4 100644
- --- a/package/kernel/mac80211/patches/920-ath10k_allow_fallback_to_board_bin_on_empty_otp_stream.patch
- +++ b/package/kernel/mac80211/patches/920-ath10k_allow_fallback_to_board_bin_on_empty_otp_stream.patch
- @@ -1,14 +1,14 @@
- --- a/drivers/net/wireless/ath/ath10k/core.c
- +++ b/drivers/net/wireless/ath/ath10k/core.c
- -@@ -277,7 +277,10 @@ static int ath10k_download_and_run_otp(s
- +@@ -387,7 +387,10 @@ static int ath10k_download_and_run_otp(s
-
- - ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
- + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
-
- -- if (result != 0) {
- +- if (!skip_otp && result != 0) {
- + if (result == 2) {
- -+ ath10k_warn("otp stream is empty, using board.bin contents");
- ++ ath10k_warn(ar, "otp stream is empty, using board.bin contents");
- + return 0;
- -+ } else if (result != 0) {
- - ath10k_err("otp calibration failed: %d", result);
- ++ } else if (!skip_otp && result != 0) {
- + ath10k_err(ar, "otp calibration failed: %d", result);
- return -EINVAL;
- }
- diff --git a/package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch b/package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch
- new file mode 100644
- index 0000000..c664faa
- --- /dev/null
- +++ b/package/kernel/mac80211/patches/921-ath10k_init_devices_synchronously.patch
- @@ -0,0 +1,33 @@
- +From: Sven Eckelmann <sven@open-mesh.com>
- +Date: Tue, 18 Nov 2014 12:29:28 +0100
- +Subject: [PATCH] ath10k: Don't initialize devices asynchronously
- +
- +OpenWrt requires all PHYs to be initialized to create the configuration files
- +during bootup. ath10k violates this because it delays the creation of the PHY
- +to a not well defined point in the future.
- +
- +Forcing the work to be done immediately works around this problem but may also
- +delay the boot when firmware images cannot be found.
- +
- +Signed-off-by: Sven Eckelmann <sven@open-mesh.com>
- +---
- +
- +--- a/drivers/net/wireless/ath/ath10k/core.c
- ++++ b/drivers/net/wireless/ath/ath10k/core.c
- +@@ -1321,6 +1321,16 @@ int ath10k_core_register(struct ath10k *
- + ar->chip_id = chip_id;
- + queue_work(ar->workqueue, &ar->register_work);
- +
- ++ /* OpenWrt requires all PHYs to be initialized to create the
- ++ * configuration files during bootup. ath10k violates this
- ++ * because it delays the creation of the PHY to a not well defined
- ++ * point in the future.
- ++ *
- ++ * Forcing the work to be done immediately works around this problem
- ++ * but may also delay the boot when firmware images cannot be found.
- ++ */
- ++ flush_workqueue(ar->workqueue);
- ++
- + return 0;
- + }
- + EXPORT_SYMBOL(ath10k_core_register);
- diff --git a/package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch b/package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch
- new file mode 100644
- index 0000000..54174b1
- --- /dev/null
- +++ b/package/kernel/mac80211/patches/930-ath10k_add_tpt_led_trigger.patch
- @@ -0,0 +1,37 @@
- +--- a/drivers/net/wireless/ath/ath10k/mac.c
- ++++ b/drivers/net/wireless/ath/ath10k/mac.c
- +@@ -5405,6 +5405,21 @@ struct ath10k_vif *ath10k_get_arvif(stru
- + return arvif_iter.arvif;
- + }
- +
- ++#ifdef CPTCFG_MAC80211_LEDS
- ++static const struct ieee80211_tpt_blink ath10k_tpt_blink[] = {
- ++ { .throughput = 0 * 1024, .blink_time = 334 },
- ++ { .throughput = 1 * 1024, .blink_time = 260 },
- ++ { .throughput = 2 * 1024, .blink_time = 220 },
- ++ { .throughput = 5 * 1024, .blink_time = 190 },
- ++ { .throughput = 10 * 1024, .blink_time = 170 },
- ++ { .throughput = 25 * 1024, .blink_time = 150 },
- ++ { .throughput = 54 * 1024, .blink_time = 130 },
- ++ { .throughput = 120 * 1024, .blink_time = 110 },
- ++ { .throughput = 265 * 1024, .blink_time = 80 },
- ++ { .throughput = 586 * 1024, .blink_time = 50 },
- ++};
- ++#endif
- ++
- + int ath10k_mac_register(struct ath10k *ar)
- + {
- + struct ieee80211_supported_band *band;
- +@@ -5567,6 +5582,12 @@ int ath10k_mac_register(struct ath10k *a
- + goto err_free;
- + }
- +
- ++#if CPTCFG_MAC80211_LEDS
- ++ ieee80211_create_tpt_led_trigger(ar->hw,
- ++ IEEE80211_TPT_LEDTRIG_FL_RADIO, ath10k_tpt_blink,
- ++ ARRAY_SIZE(ath10k_tpt_blink));
- ++#endif
- ++
- + ret = ieee80211_register_hw(ar->hw);
- + if (ret) {
- + ath10k_err(ar, "failed to register ieee80211: %d\n", ret);
- diff --git a/package/kernel/mac80211/patches/950-ath10k_AP_IBSS.patch b/package/kernel/mac80211/patches/950-ath10k_AP_IBSS.patch
- new file mode 100644
- index 0000000..0011b5d
- --- /dev/null
- +++ b/package/kernel/mac80211/patches/950-ath10k_AP_IBSS.patch
- @@ -0,0 +1,32 @@
- +--- a/drivers/net/wireless/ath/ath10k/mac.c
- ++++ b/drivers/net/wireless/ath/ath10k/mac.c
- +@@ -5253,6 +5253,10 @@ static const struct ieee80211_iface_limi
- + .max = 7,
- + .types = BIT(NL80211_IFTYPE_AP)
- + },
- ++ {
- ++ .max = 1,
- ++ .types = BIT(NL80211_IFTYPE_ADHOC)
- ++ },
- + };
- +
- + static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
- +@@ -5260,6 +5264,10 @@ static const struct ieee80211_iface_limi
- + .max = 8,
- + .types = BIT(NL80211_IFTYPE_AP)
- + },
- ++ {
- ++ .max = 1,
- ++ .types = BIT(NL80211_IFTYPE_ADHOC)
- ++ },
- + };
- +
- + static const struct ieee80211_iface_combination ath10k_if_comb[] = {
- +@@ -5555,6 +5563,7 @@ int ath10k_mac_register(struct ath10k *a
- + ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
- + ar->hw->wiphy->n_iface_combinations =
- + ARRAY_SIZE(ath10k_10x_if_comb);
- ++ ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
- + break;
- + case ATH10K_FW_WMI_OP_VERSION_UNSET:
- + case ATH10K_FW_WMI_OP_VERSION_MAX:
|