0005-surface-sam.patch 731 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501
  1. From 0c700275d9f211fd8a11f7d6614e2f520638ba1f Mon Sep 17 00:00:00 2001
  2. From: Maximilian Luz <luzmaximilian@gmail.com>
  3. Date: Mon, 21 Dec 2020 19:39:51 +0100
  4. Subject: [PATCH] platform/surface: Add Surface Aggregator subsystem
  5. Add Surface System Aggregator Module core and Surface Serial Hub driver,
  6. required for the embedded controller found on Microsoft Surface devices.
  7. The Surface System Aggregator Module (SSAM, SAM or Surface Aggregator)
  8. is an embedded controller (EC) found on 4th and later generation
  9. Microsoft Surface devices, with the exception of the Surface Go series.
  10. This EC provides various functionality, depending on the device in
  11. question. This can include battery status and thermal reporting (5th and
  12. later generations), but also HID keyboard (6th+) and touchpad input
  13. (7th+) on Surface Laptop and Surface Book 3 series devices.
  14. This patch provides the basic necessities for communication with the SAM
  15. EC on 5th and later generation devices. On these devices, the EC
  16. provides an interface that acts as serial device, called the Surface
  17. Serial Hub (SSH). 4th generation devices, on which the EC interface is
  18. provided via an HID-over-I2C device, are not supported by this patch.
  19. Specifically, this patch adds a driver for the SSH device (device HID
  20. MSHW0084 in ACPI), as well as a controller structure and associated API.
  21. This represents the functional core of the Surface Aggregator kernel
  22. subsystem, introduced with this patch, and will be expanded upon in
  23. subsequent commits.
  24. The SSH driver acts as the main attachment point for this subsystem and
  25. sets-up and manages the controller structure. The controller in turn
  26. provides a basic communication interface, allowing to send requests from
  27. host to EC and receiving the corresponding responses, as well as
  28. managing and receiving events, sent from EC to host. It is structured
  29. into multiple layers, with the top layer presenting the API used by
  30. other kernel drivers and the lower layers modeled after the serial
  31. protocol used for communication.
  32. Said other drivers are then responsible for providing the (Surface model
  33. specific) functionality accessible through the EC (e.g. battery status
  34. reporting, thermal information, ...) via said controller structure and
  35. API, and will be added in future commits.
  36. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  37. Link: https://lore.kernel.org/r/20201221183959.1186143-2-luzmaximilian@gmail.com
  38. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  39. Patchset: surface-sam
  40. ---
  41. MAINTAINERS | 8 +
  42. drivers/platform/surface/Kconfig | 2 +
  43. drivers/platform/surface/Makefile | 1 +
  44. drivers/platform/surface/aggregator/Kconfig | 42 +
  45. drivers/platform/surface/aggregator/Makefile | 10 +
  46. .../platform/surface/aggregator/controller.c | 2504 +++++++++++++++++
  47. .../platform/surface/aggregator/controller.h | 276 ++
  48. drivers/platform/surface/aggregator/core.c | 787 ++++++
  49. .../platform/surface/aggregator/ssh_msgb.h | 205 ++
  50. .../surface/aggregator/ssh_packet_layer.c | 1710 +++++++++++
  51. .../surface/aggregator/ssh_packet_layer.h | 187 ++
  52. .../platform/surface/aggregator/ssh_parser.c | 228 ++
  53. .../platform/surface/aggregator/ssh_parser.h | 154 +
  54. .../surface/aggregator/ssh_request_layer.c | 1211 ++++++++
  55. .../surface/aggregator/ssh_request_layer.h | 143 +
  56. include/linux/surface_aggregator/controller.h | 824 ++++++
  57. include/linux/surface_aggregator/serial_hub.h | 672 +++++
  58. 17 files changed, 8964 insertions(+)
  59. create mode 100644 drivers/platform/surface/aggregator/Kconfig
  60. create mode 100644 drivers/platform/surface/aggregator/Makefile
  61. create mode 100644 drivers/platform/surface/aggregator/controller.c
  62. create mode 100644 drivers/platform/surface/aggregator/controller.h
  63. create mode 100644 drivers/platform/surface/aggregator/core.c
  64. create mode 100644 drivers/platform/surface/aggregator/ssh_msgb.h
  65. create mode 100644 drivers/platform/surface/aggregator/ssh_packet_layer.c
  66. create mode 100644 drivers/platform/surface/aggregator/ssh_packet_layer.h
  67. create mode 100644 drivers/platform/surface/aggregator/ssh_parser.c
  68. create mode 100644 drivers/platform/surface/aggregator/ssh_parser.h
  69. create mode 100644 drivers/platform/surface/aggregator/ssh_request_layer.c
  70. create mode 100644 drivers/platform/surface/aggregator/ssh_request_layer.h
  71. create mode 100644 include/linux/surface_aggregator/controller.h
  72. create mode 100644 include/linux/surface_aggregator/serial_hub.h
  73. diff --git a/MAINTAINERS b/MAINTAINERS
  74. index b6ab9c1a2119..530792c869c4 100644
  75. --- a/MAINTAINERS
  76. +++ b/MAINTAINERS
  77. @@ -11806,6 +11806,14 @@ L: platform-driver-x86@vger.kernel.org
  78. S: Supported
  79. F: drivers/platform/surface/surfacepro3_button.c
  80. +MICROSOFT SURFACE SYSTEM AGGREGATOR SUBSYSTEM
  81. +M: Maximilian Luz <luzmaximilian@gmail.com>
  82. +S: Maintained
  83. +W: https://github.com/linux-surface/surface-aggregator-module
  84. +C: irc://chat.freenode.net/##linux-surface
  85. +F: drivers/platform/surface/aggregator/
  86. +F: include/linux/surface_aggregator/
  87. +
  88. MICROTEK X6 SCANNER
  89. M: Oliver Neukum <oliver@neukum.org>
  90. S: Maintained
  91. diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig
  92. index b5dc9148066c..ef6b4051e7c8 100644
  93. --- a/drivers/platform/surface/Kconfig
  94. +++ b/drivers/platform/surface/Kconfig
  95. @@ -63,4 +63,6 @@ config SURFACE_PRO3_BUTTON
  96. help
  97. This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet.
  98. +source "drivers/platform/surface/aggregator/Kconfig"
  99. +
  100. endif # SURFACE_PLATFORMS
  101. diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile
  102. index 3d5fa0daa56b..c5392098cfb9 100644
  103. --- a/drivers/platform/surface/Makefile
  104. +++ b/drivers/platform/surface/Makefile
  105. @@ -7,6 +7,7 @@
  106. obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
  107. obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
  108. obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o
  109. +obj-$(CONFIG_SURFACE_AGGREGATOR) += aggregator/
  110. obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o
  111. obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o
  112. obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
  113. diff --git a/drivers/platform/surface/aggregator/Kconfig b/drivers/platform/surface/aggregator/Kconfig
  114. new file mode 100644
  115. index 000000000000..e9f4ad96e40a
  116. --- /dev/null
  117. +++ b/drivers/platform/surface/aggregator/Kconfig
  118. @@ -0,0 +1,42 @@
  119. +# SPDX-License-Identifier: GPL-2.0+
  120. +# Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  121. +
  122. +menuconfig SURFACE_AGGREGATOR
  123. + tristate "Microsoft Surface System Aggregator Module Subsystem and Drivers"
  124. + depends on SERIAL_DEV_BUS
  125. + select CRC_CCITT
  126. + help
  127. + The Surface System Aggregator Module (Surface SAM or SSAM) is an
  128. + embedded controller (EC) found on 5th- and later-generation Microsoft
  129. + Surface devices (i.e. Surface Pro 5, Surface Book 2, Surface Laptop,
  130. + and newer, with exception of Surface Go series devices).
  131. +
  132. + Depending on the device in question, this EC provides varying
  133. + functionality, including:
  134. + - EC access from ACPI via Surface ACPI Notify (5th- and 6th-generation)
  135. + - battery status information (all devices)
  136. + - thermal sensor access (all devices)
  137. + - performance mode / cooling mode control (all devices)
  138. + - clipboard detachment system control (Surface Book 2 and 3)
  139. + - HID / keyboard input (Surface Laptops, Surface Book 3)
  140. +
  141. + This option controls whether the Surface SAM subsystem core will be
  142. + built. This includes a driver for the Surface Serial Hub (SSH), which
  143. + is the device responsible for the communication with the EC, and a
  144. + basic kernel interface exposing the EC functionality to other client
  145. + drivers, i.e. allowing them to make requests to the EC and receive
  146. + events from it. Selecting this option alone will not provide any
  147. + client drivers and therefore no functionality beyond the in-kernel
  148. + interface. Said functionality is the responsibility of the respective
  149. + client drivers.
  150. +
  151. + Note: While 4th-generation Surface devices also make use of a SAM EC,
  152. + due to a difference in the communication interface of the controller,
  153. + only 5th and later generations are currently supported. Specifically,
  154. + devices using SAM-over-SSH are supported, whereas devices using
  155. + SAM-over-HID, which is used on the 4th generation, are currently not
  156. + supported.
  157. +
  158. + Choose m if you want to build the SAM subsystem core and SSH driver as
  159. + module, y if you want to build it into the kernel and n if you don't
  160. + want it at all.
  161. diff --git a/drivers/platform/surface/aggregator/Makefile b/drivers/platform/surface/aggregator/Makefile
  162. new file mode 100644
  163. index 000000000000..faad18d4a7f2
  164. --- /dev/null
  165. +++ b/drivers/platform/surface/aggregator/Makefile
  166. @@ -0,0 +1,10 @@
  167. +# SPDX-License-Identifier: GPL-2.0+
  168. +# Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  169. +
  170. +obj-$(CONFIG_SURFACE_AGGREGATOR) += surface_aggregator.o
  171. +
  172. +surface_aggregator-objs := core.o
  173. +surface_aggregator-objs += ssh_parser.o
  174. +surface_aggregator-objs += ssh_packet_layer.o
  175. +surface_aggregator-objs += ssh_request_layer.o
  176. +surface_aggregator-objs += controller.o
  177. diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
  178. new file mode 100644
  179. index 000000000000..488318cf2098
  180. --- /dev/null
  181. +++ b/drivers/platform/surface/aggregator/controller.c
  182. @@ -0,0 +1,2504 @@
  183. +// SPDX-License-Identifier: GPL-2.0+
  184. +/*
  185. + * Main SSAM/SSH controller structure and functionality.
  186. + *
  187. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  188. + */
  189. +
  190. +#include <linux/acpi.h>
  191. +#include <linux/atomic.h>
  192. +#include <linux/completion.h>
  193. +#include <linux/gpio/consumer.h>
  194. +#include <linux/interrupt.h>
  195. +#include <linux/kref.h>
  196. +#include <linux/limits.h>
  197. +#include <linux/list.h>
  198. +#include <linux/lockdep.h>
  199. +#include <linux/mutex.h>
  200. +#include <linux/rculist.h>
  201. +#include <linux/rbtree.h>
  202. +#include <linux/rwsem.h>
  203. +#include <linux/serdev.h>
  204. +#include <linux/slab.h>
  205. +#include <linux/spinlock.h>
  206. +#include <linux/srcu.h>
  207. +#include <linux/types.h>
  208. +#include <linux/workqueue.h>
  209. +
  210. +#include <linux/surface_aggregator/controller.h>
  211. +#include <linux/surface_aggregator/serial_hub.h>
  212. +
  213. +#include "controller.h"
  214. +#include "ssh_msgb.h"
  215. +#include "ssh_request_layer.h"
  216. +
  217. +
  218. +/* -- Safe counters. -------------------------------------------------------- */
  219. +
  220. +/**
  221. + * ssh_seq_reset() - Reset/initialize sequence ID counter.
  222. + * @c: The counter to reset.
  223. + */
  224. +static void ssh_seq_reset(struct ssh_seq_counter *c)
  225. +{
  226. + WRITE_ONCE(c->value, 0);
  227. +}
  228. +
  229. +/**
  230. + * ssh_seq_next() - Get next sequence ID.
  231. + * @c: The counter providing the sequence IDs.
  232. + *
  233. + * Return: Returns the next sequence ID of the counter.
  234. + */
  235. +static u8 ssh_seq_next(struct ssh_seq_counter *c)
  236. +{
  237. + u8 old = READ_ONCE(c->value);
  238. + u8 new = old + 1;
  239. + u8 ret;
  240. +
  241. + while (unlikely((ret = cmpxchg(&c->value, old, new)) != old)) {
  242. + old = ret;
  243. + new = old + 1;
  244. + }
  245. +
  246. + return old;
  247. +}
  248. +
  249. +/**
  250. + * ssh_rqid_reset() - Reset/initialize request ID counter.
  251. + * @c: The counter to reset.
  252. + */
  253. +static void ssh_rqid_reset(struct ssh_rqid_counter *c)
  254. +{
  255. + WRITE_ONCE(c->value, 0);
  256. +}
  257. +
  258. +/**
  259. + * ssh_rqid_next() - Get next request ID.
  260. + * @c: The counter providing the request IDs.
  261. + *
  262. + * Return: Returns the next request ID of the counter, skipping any reserved
  263. + * request IDs.
  264. + */
  265. +static u16 ssh_rqid_next(struct ssh_rqid_counter *c)
  266. +{
  267. + u16 old = READ_ONCE(c->value);
  268. + u16 new = ssh_rqid_next_valid(old);
  269. + u16 ret;
  270. +
  271. + while (unlikely((ret = cmpxchg(&c->value, old, new)) != old)) {
  272. + old = ret;
  273. + new = ssh_rqid_next_valid(old);
  274. + }
  275. +
  276. + return old;
  277. +}
  278. +
  279. +
  280. +/* -- Event notifier/callbacks. --------------------------------------------- */
  281. +/*
  282. + * The notifier system is based on linux/notifier.h, specifically the SRCU
  283. + * implementation. The difference to that is, that some bits of the notifier
  284. + * call return value can be tracked across multiple calls. This is done so
  285. + * that handling of events can be tracked and a warning can be issued in case
  286. + * an event goes unhandled. The idea of that warning is that it should help
  287. + * discover and identify new/currently unimplemented features.
  288. + */
  289. +
  290. +/**
  291. + * ssam_event_matches_notifier() - Test if an event matches a notifier.
  292. + * @n: The event notifier to test against.
  293. + * @event: The event to test.
  294. + *
  295. + * Return: Returns %true if the given event matches the given notifier
  296. + * according to the rules set in the notifier's event mask, %false otherwise.
  297. + */
  298. +static bool ssam_event_matches_notifier(const struct ssam_event_notifier *n,
  299. + const struct ssam_event *event)
  300. +{
  301. + bool match = n->event.id.target_category == event->target_category;
  302. +
  303. + if (n->event.mask & SSAM_EVENT_MASK_TARGET)
  304. + match &= n->event.reg.target_id == event->target_id;
  305. +
  306. + if (n->event.mask & SSAM_EVENT_MASK_INSTANCE)
  307. + match &= n->event.id.instance == event->instance_id;
  308. +
  309. + return match;
  310. +}
  311. +
  312. +/**
  313. + * ssam_nfblk_call_chain() - Call event notifier callbacks of the given chain.
  314. + * @nh: The notifier head for which the notifier callbacks should be called.
  315. + * @event: The event data provided to the callbacks.
  316. + *
  317. + * Call all registered notifier callbacks in order of their priority until
  318. + * either no notifier is left or a notifier returns a value with the
  319. + * %SSAM_NOTIF_STOP bit set. Note that this bit is automatically set via
  320. + * ssam_notifier_from_errno() on any non-zero error value.
  321. + *
  322. + * Return: Returns the notifier status value, which contains the notifier
  323. + * status bits (%SSAM_NOTIF_HANDLED and %SSAM_NOTIF_STOP) as well as a
  324. + * potential error value returned from the last executed notifier callback.
  325. + * Use ssam_notifier_to_errno() to convert this value to the original error
  326. + * value.
  327. + */
  328. +static int ssam_nfblk_call_chain(struct ssam_nf_head *nh, struct ssam_event *event)
  329. +{
  330. + struct ssam_event_notifier *nf;
  331. + int ret = 0, idx;
  332. +
  333. + idx = srcu_read_lock(&nh->srcu);
  334. +
  335. + list_for_each_entry_rcu(nf, &nh->head, base.node,
  336. + srcu_read_lock_held(&nh->srcu)) {
  337. + if (ssam_event_matches_notifier(nf, event)) {
  338. + ret = (ret & SSAM_NOTIF_STATE_MASK) | nf->base.fn(nf, event);
  339. + if (ret & SSAM_NOTIF_STOP)
  340. + break;
  341. + }
  342. + }
  343. +
  344. + srcu_read_unlock(&nh->srcu, idx);
  345. + return ret;
  346. +}
  347. +
  348. +/**
  349. + * ssam_nfblk_insert() - Insert a new notifier block into the given notifier
  350. + * list.
  351. + * @nh: The notifier head into which the block should be inserted.
  352. + * @nb: The notifier block to add.
  353. + *
  354. + * Note: This function must be synchronized by the caller with respect to other
  355. + * insert, find, and/or remove calls by holding ``struct ssam_nf.lock``.
  356. + *
  357. + * Return: Returns zero on success, %-EEXIST if the notifier block has already
  358. + * been registered.
  359. + */
  360. +static int ssam_nfblk_insert(struct ssam_nf_head *nh, struct ssam_notifier_block *nb)
  361. +{
  362. + struct ssam_notifier_block *p;
  363. + struct list_head *h;
  364. +
  365. + /* Runs under lock, no need for RCU variant. */
  366. + list_for_each(h, &nh->head) {
  367. + p = list_entry(h, struct ssam_notifier_block, node);
  368. +
  369. + if (unlikely(p == nb)) {
  370. + WARN(1, "double register detected");
  371. + return -EEXIST;
  372. + }
  373. +
  374. + if (nb->priority > p->priority)
  375. + break;
  376. + }
  377. +
  378. + list_add_tail_rcu(&nb->node, h);
  379. + return 0;
  380. +}
  381. +
  382. +/**
  383. + * ssam_nfblk_find() - Check if a notifier block is registered on the given
  384. + * notifier head.
  385. + * list.
  386. + * @nh: The notifier head on which to search.
  387. + * @nb: The notifier block to search for.
  388. + *
  389. + * Note: This function must be synchronized by the caller with respect to other
  390. + * insert, find, and/or remove calls by holding ``struct ssam_nf.lock``.
  391. + *
  392. + * Return: Returns true if the given notifier block is registered on the given
  393. + * notifier head, false otherwise.
  394. + */
  395. +static bool ssam_nfblk_find(struct ssam_nf_head *nh, struct ssam_notifier_block *nb)
  396. +{
  397. + struct ssam_notifier_block *p;
  398. +
  399. + /* Runs under lock, no need for RCU variant. */
  400. + list_for_each_entry(p, &nh->head, node) {
  401. + if (p == nb)
  402. + return true;
  403. + }
  404. +
  405. + return false;
  406. +}
  407. +
  408. +/**
  409. + * ssam_nfblk_remove() - Remove a notifier block from its notifier list.
  410. + * @nb: The notifier block to be removed.
  411. + *
  412. + * Note: This function must be synchronized by the caller with respect to
  413. + * other insert, find, and/or remove calls by holding ``struct ssam_nf.lock``.
  414. + * Furthermore, the caller _must_ ensure SRCU synchronization by calling
  415. + * synchronize_srcu() with ``nh->srcu`` after leaving the critical section, to
  416. + * ensure that the removed notifier block is not in use any more.
  417. + */
  418. +static void ssam_nfblk_remove(struct ssam_notifier_block *nb)
  419. +{
  420. + list_del_rcu(&nb->node);
  421. +}
  422. +
  423. +/**
  424. + * ssam_nf_head_init() - Initialize the given notifier head.
  425. + * @nh: The notifier head to initialize.
  426. + */
  427. +static int ssam_nf_head_init(struct ssam_nf_head *nh)
  428. +{
  429. + int status;
  430. +
  431. + status = init_srcu_struct(&nh->srcu);
  432. + if (status)
  433. + return status;
  434. +
  435. + INIT_LIST_HEAD(&nh->head);
  436. + return 0;
  437. +}
  438. +
  439. +/**
  440. + * ssam_nf_head_destroy() - Deinitialize the given notifier head.
  441. + * @nh: The notifier head to deinitialize.
  442. + */
  443. +static void ssam_nf_head_destroy(struct ssam_nf_head *nh)
  444. +{
  445. + cleanup_srcu_struct(&nh->srcu);
  446. +}
  447. +
  448. +
  449. +/* -- Event/notification registry. ------------------------------------------ */
  450. +
  451. +/**
  452. + * struct ssam_nf_refcount_key - Key used for event activation reference
  453. + * counting.
  454. + * @reg: The registry via which the event is enabled/disabled.
  455. + * @id: The ID uniquely describing the event.
  456. + */
  457. +struct ssam_nf_refcount_key {
  458. + struct ssam_event_registry reg;
  459. + struct ssam_event_id id;
  460. +};
  461. +
  462. +/**
  463. + * struct ssam_nf_refcount_entry - RB-tree entry for reference counting event
  464. + * activations.
  465. + * @node: The node of this entry in the rb-tree.
  466. + * @key: The key of the event.
  467. + * @refcount: The reference-count of the event.
  468. + * @flags: The flags used when enabling the event.
  469. + */
  470. +struct ssam_nf_refcount_entry {
  471. + struct rb_node node;
  472. + struct ssam_nf_refcount_key key;
  473. + int refcount;
  474. + u8 flags;
  475. +};
  476. +
  477. +/**
  478. + * ssam_nf_refcount_inc() - Increment reference-/activation-count of the given
  479. + * event.
  480. + * @nf: The notifier system reference.
  481. + * @reg: The registry used to enable/disable the event.
  482. + * @id: The event ID.
  483. + *
  484. + * Increments the reference-/activation-count associated with the specified
  485. + * event type/ID, allocating a new entry for this event ID if necessary. A
  486. + * newly allocated entry will have a refcount of one.
  487. + *
  488. + * Note: ``nf->lock`` must be held when calling this function.
  489. + *
  490. + * Return: Returns the refcount entry on success. Returns an error pointer
  491. + * with %-ENOSPC if there have already been %INT_MAX events of the specified
  492. + * ID and type registered, or %-ENOMEM if the entry could not be allocated.
  493. + */
  494. +static struct ssam_nf_refcount_entry *
  495. +ssam_nf_refcount_inc(struct ssam_nf *nf, struct ssam_event_registry reg,
  496. + struct ssam_event_id id)
  497. +{
  498. + struct ssam_nf_refcount_entry *entry;
  499. + struct ssam_nf_refcount_key key;
  500. + struct rb_node **link = &nf->refcount.rb_node;
  501. + struct rb_node *parent = NULL;
  502. + int cmp;
  503. +
  504. + lockdep_assert_held(&nf->lock);
  505. +
  506. + key.reg = reg;
  507. + key.id = id;
  508. +
  509. + while (*link) {
  510. + entry = rb_entry(*link, struct ssam_nf_refcount_entry, node);
  511. + parent = *link;
  512. +
  513. + cmp = memcmp(&key, &entry->key, sizeof(key));
  514. + if (cmp < 0) {
  515. + link = &(*link)->rb_left;
  516. + } else if (cmp > 0) {
  517. + link = &(*link)->rb_right;
  518. + } else if (entry->refcount < INT_MAX) {
  519. + entry->refcount++;
  520. + return entry;
  521. + } else {
  522. + WARN_ON(1);
  523. + return ERR_PTR(-ENOSPC);
  524. + }
  525. + }
  526. +
  527. + entry = kzalloc(sizeof(*entry), GFP_KERNEL);
  528. + if (!entry)
  529. + return ERR_PTR(-ENOMEM);
  530. +
  531. + entry->key = key;
  532. + entry->refcount = 1;
  533. +
  534. + rb_link_node(&entry->node, parent, link);
  535. + rb_insert_color(&entry->node, &nf->refcount);
  536. +
  537. + return entry;
  538. +}
  539. +
  540. +/**
  541. + * ssam_nf_refcount_dec() - Decrement reference-/activation-count of the given
  542. + * event.
  543. + * @nf: The notifier system reference.
  544. + * @reg: The registry used to enable/disable the event.
  545. + * @id: The event ID.
  546. + *
  547. + * Decrements the reference-/activation-count of the specified event,
  548. + * returning its entry. If the returned entry has a refcount of zero, the
  549. + * caller is responsible for freeing it using kfree().
  550. + *
  551. + * Note: ``nf->lock`` must be held when calling this function.
  552. + *
  553. + * Return: Returns the refcount entry on success or %NULL if the entry has not
  554. + * been found.
  555. + */
  556. +static struct ssam_nf_refcount_entry *
  557. +ssam_nf_refcount_dec(struct ssam_nf *nf, struct ssam_event_registry reg,
  558. + struct ssam_event_id id)
  559. +{
  560. + struct ssam_nf_refcount_entry *entry;
  561. + struct ssam_nf_refcount_key key;
  562. + struct rb_node *node = nf->refcount.rb_node;
  563. + int cmp;
  564. +
  565. + lockdep_assert_held(&nf->lock);
  566. +
  567. + key.reg = reg;
  568. + key.id = id;
  569. +
  570. + while (node) {
  571. + entry = rb_entry(node, struct ssam_nf_refcount_entry, node);
  572. +
  573. + cmp = memcmp(&key, &entry->key, sizeof(key));
  574. + if (cmp < 0) {
  575. + node = node->rb_left;
  576. + } else if (cmp > 0) {
  577. + node = node->rb_right;
  578. + } else {
  579. + entry->refcount--;
  580. + if (entry->refcount == 0)
  581. + rb_erase(&entry->node, &nf->refcount);
  582. +
  583. + return entry;
  584. + }
  585. + }
  586. +
  587. + return NULL;
  588. +}
  589. +
  590. +/**
  591. + * ssam_nf_refcount_empty() - Test if the notification system has any
  592. + * enabled/active events.
  593. + * @nf: The notification system.
  594. + */
  595. +static bool ssam_nf_refcount_empty(struct ssam_nf *nf)
  596. +{
  597. + return RB_EMPTY_ROOT(&nf->refcount);
  598. +}
  599. +
  600. +/**
  601. + * ssam_nf_call() - Call notification callbacks for the provided event.
  602. + * @nf: The notifier system
  603. + * @dev: The associated device, only used for logging.
  604. + * @rqid: The request ID of the event.
  605. + * @event: The event provided to the callbacks.
  606. + *
  607. + * Execute registered callbacks in order of their priority until either no
  608. + * callback is left or a callback returns a value with the %SSAM_NOTIF_STOP
  609. + * bit set. Note that this bit is set automatically when converting non-zero
  610. + * error values via ssam_notifier_from_errno() to notifier values.
  611. + *
  612. + * Also note that any callback that could handle an event should return a value
  613. + * with bit %SSAM_NOTIF_HANDLED set, indicating that the event does not go
  614. + * unhandled/ignored. In case no registered callback could handle an event,
  615. + * this function will emit a warning.
  616. + *
  617. + * In case a callback failed, this function will emit an error message.
  618. + */
  619. +static void ssam_nf_call(struct ssam_nf *nf, struct device *dev, u16 rqid,
  620. + struct ssam_event *event)
  621. +{
  622. + struct ssam_nf_head *nf_head;
  623. + int status, nf_ret;
  624. +
  625. + if (!ssh_rqid_is_event(rqid)) {
  626. + dev_warn(dev, "event: unsupported rqid: %#06x\n", rqid);
  627. + return;
  628. + }
  629. +
  630. + nf_head = &nf->head[ssh_rqid_to_event(rqid)];
  631. + nf_ret = ssam_nfblk_call_chain(nf_head, event);
  632. + status = ssam_notifier_to_errno(nf_ret);
  633. +
  634. + if (status < 0) {
  635. + dev_err(dev,
  636. + "event: error handling event: %d (tc: %#04x, tid: %#04x, cid: %#04x, iid: %#04x)\n",
  637. + status, event->target_category, event->target_id,
  638. + event->command_id, event->instance_id);
  639. + } else if (!(nf_ret & SSAM_NOTIF_HANDLED)) {
  640. + dev_warn(dev,
  641. + "event: unhandled event (rqid: %#04x, tc: %#04x, tid: %#04x, cid: %#04x, iid: %#04x)\n",
  642. + rqid, event->target_category, event->target_id,
  643. + event->command_id, event->instance_id);
  644. + }
  645. +}
  646. +
  647. +/**
  648. + * ssam_nf_init() - Initialize the notifier system.
  649. + * @nf: The notifier system to initialize.
  650. + */
  651. +static int ssam_nf_init(struct ssam_nf *nf)
  652. +{
  653. + int i, status;
  654. +
  655. + for (i = 0; i < SSH_NUM_EVENTS; i++) {
  656. + status = ssam_nf_head_init(&nf->head[i]);
  657. + if (status)
  658. + break;
  659. + }
  660. +
  661. + if (status) {
  662. + while (i--)
  663. + ssam_nf_head_destroy(&nf->head[i]);
  664. +
  665. + return status;
  666. + }
  667. +
  668. + mutex_init(&nf->lock);
  669. + return 0;
  670. +}
  671. +
  672. +/**
  673. + * ssam_nf_destroy() - Deinitialize the notifier system.
  674. + * @nf: The notifier system to deinitialize.
  675. + */
  676. +static void ssam_nf_destroy(struct ssam_nf *nf)
  677. +{
  678. + int i;
  679. +
  680. + for (i = 0; i < SSH_NUM_EVENTS; i++)
  681. + ssam_nf_head_destroy(&nf->head[i]);
  682. +
  683. + mutex_destroy(&nf->lock);
  684. +}
  685. +
  686. +
  687. +/* -- Event/async request completion system. -------------------------------- */
  688. +
  689. +#define SSAM_CPLT_WQ_NAME "ssam_cpltq"
  690. +
  691. +/*
  692. + * SSAM_CPLT_WQ_BATCH - Maximum number of event item completions executed per
  693. + * work execution. Used to prevent livelocking of the workqueue. Value chosen
  694. + * via educated guess, may be adjusted.
  695. + */
  696. +#define SSAM_CPLT_WQ_BATCH 10
  697. +
  698. +/**
  699. + * ssam_event_item_alloc() - Allocate an event item with the given payload size.
  700. + * @len: The event payload length.
  701. + * @flags: The flags used for allocation.
  702. + *
  703. + * Allocate an event item with the given payload size. Sets the item
  704. + * operations and payload length values. The item free callback (``ops.free``)
  705. + * should not be overwritten after this call.
  706. + *
  707. + * Return: Returns the newly allocated event item.
  708. + */
  709. +static struct ssam_event_item *ssam_event_item_alloc(size_t len, gfp_t flags)
  710. +{
  711. + struct ssam_event_item *item;
  712. +
  713. + item = kzalloc(struct_size(item, event.data, len), flags);
  714. + if (!item)
  715. + return NULL;
  716. +
  717. + item->event.length = len;
  718. + return item;
  719. +}
  720. +
  721. +/**
  722. + * ssam_event_queue_push() - Push an event item to the event queue.
  723. + * @q: The event queue.
  724. + * @item: The item to add.
  725. + */
  726. +static void ssam_event_queue_push(struct ssam_event_queue *q,
  727. + struct ssam_event_item *item)
  728. +{
  729. + spin_lock(&q->lock);
  730. + list_add_tail(&item->node, &q->head);
  731. + spin_unlock(&q->lock);
  732. +}
  733. +
  734. +/**
  735. + * ssam_event_queue_pop() - Pop the next event item from the event queue.
  736. + * @q: The event queue.
  737. + *
  738. + * Returns and removes the next event item from the queue. Returns %NULL If
  739. + * there is no event item left.
  740. + */
  741. +static struct ssam_event_item *ssam_event_queue_pop(struct ssam_event_queue *q)
  742. +{
  743. + struct ssam_event_item *item;
  744. +
  745. + spin_lock(&q->lock);
  746. + item = list_first_entry_or_null(&q->head, struct ssam_event_item, node);
  747. + if (item)
  748. + list_del(&item->node);
  749. + spin_unlock(&q->lock);
  750. +
  751. + return item;
  752. +}
  753. +
  754. +/**
  755. + * ssam_event_queue_is_empty() - Check if the event queue is empty.
  756. + * @q: The event queue.
  757. + */
  758. +static bool ssam_event_queue_is_empty(struct ssam_event_queue *q)
  759. +{
  760. + bool empty;
  761. +
  762. + spin_lock(&q->lock);
  763. + empty = list_empty(&q->head);
  764. + spin_unlock(&q->lock);
  765. +
  766. + return empty;
  767. +}
  768. +
  769. +/**
  770. + * ssam_cplt_get_event_queue() - Get the event queue for the given parameters.
  771. + * @cplt: The completion system on which to look for the queue.
  772. + * @tid: The target ID of the queue.
  773. + * @rqid: The request ID representing the event ID for which to get the queue.
  774. + *
  775. + * Return: Returns the event queue corresponding to the event type described
  776. + * by the given parameters. If the request ID does not represent an event,
  777. + * this function returns %NULL. If the target ID is not supported, this
  778. + * function will fall back to the default target ID (``tid = 1``).
  779. + */
  780. +static
  781. +struct ssam_event_queue *ssam_cplt_get_event_queue(struct ssam_cplt *cplt,
  782. + u8 tid, u16 rqid)
  783. +{
  784. + u16 event = ssh_rqid_to_event(rqid);
  785. + u16 tidx = ssh_tid_to_index(tid);
  786. +
  787. + if (!ssh_rqid_is_event(rqid)) {
  788. + dev_err(cplt->dev, "event: unsupported request ID: %#06x\n", rqid);
  789. + return NULL;
  790. + }
  791. +
  792. + if (!ssh_tid_is_valid(tid)) {
  793. + dev_warn(cplt->dev, "event: unsupported target ID: %u\n", tid);
  794. + tidx = 0;
  795. + }
  796. +
  797. + return &cplt->event.target[tidx].queue[event];
  798. +}
  799. +
  800. +/**
  801. + * ssam_cplt_submit() - Submit a work item to the completion system workqueue.
  802. + * @cplt: The completion system.
  803. + * @work: The work item to submit.
  804. + */
  805. +static bool ssam_cplt_submit(struct ssam_cplt *cplt, struct work_struct *work)
  806. +{
  807. + return queue_work(cplt->wq, work);
  808. +}
  809. +
  810. +/**
  811. + * ssam_cplt_submit_event() - Submit an event to the completion system.
  812. + * @cplt: The completion system.
  813. + * @item: The event item to submit.
  814. + *
  815. + * Submits the event to the completion system by queuing it on the event item
  816. + * queue and queuing the respective event queue work item on the completion
  817. + * workqueue, which will eventually complete the event.
  818. + *
  819. + * Return: Returns zero on success, %-EINVAL if there is no event queue that
  820. + * can handle the given event item.
  821. + */
  822. +static int ssam_cplt_submit_event(struct ssam_cplt *cplt,
  823. + struct ssam_event_item *item)
  824. +{
  825. + struct ssam_event_queue *evq;
  826. +
  827. + evq = ssam_cplt_get_event_queue(cplt, item->event.target_id, item->rqid);
  828. + if (!evq)
  829. + return -EINVAL;
  830. +
  831. + ssam_event_queue_push(evq, item);
  832. + ssam_cplt_submit(cplt, &evq->work);
  833. + return 0;
  834. +}
  835. +
  836. +/**
  837. + * ssam_cplt_flush() - Flush the completion system.
  838. + * @cplt: The completion system.
  839. + *
  840. + * Flush the completion system by waiting until all currently submitted work
  841. + * items have been completed.
  842. + *
  843. + * Note: This function does not guarantee that all events will have been
  844. + * handled once this call terminates. In case of a larger number of
  845. + * to-be-completed events, the event queue work function may re-schedule its
  846. + * work item, which this flush operation will ignore.
  847. + *
  848. + * This operation is only intended to, during normal operation prior to
  849. + * shutdown, try to complete most events and requests to get them out of the
  850. + * system while the system is still fully operational. It does not aim to
  851. + * provide any guarantee that all of them have been handled.
  852. + */
  853. +static void ssam_cplt_flush(struct ssam_cplt *cplt)
  854. +{
  855. + flush_workqueue(cplt->wq);
  856. +}
  857. +
  858. +static void ssam_event_queue_work_fn(struct work_struct *work)
  859. +{
  860. + struct ssam_event_queue *queue;
  861. + struct ssam_event_item *item;
  862. + struct ssam_nf *nf;
  863. + struct device *dev;
  864. + unsigned int iterations = SSAM_CPLT_WQ_BATCH;
  865. +
  866. + queue = container_of(work, struct ssam_event_queue, work);
  867. + nf = &queue->cplt->event.notif;
  868. + dev = queue->cplt->dev;
  869. +
  870. + /* Limit number of processed events to avoid livelocking. */
  871. + do {
  872. + item = ssam_event_queue_pop(queue);
  873. + if (!item)
  874. + return;
  875. +
  876. + ssam_nf_call(nf, dev, item->rqid, &item->event);
  877. + kfree(item);
  878. + } while (--iterations);
  879. +
  880. + if (!ssam_event_queue_is_empty(queue))
  881. + ssam_cplt_submit(queue->cplt, &queue->work);
  882. +}
  883. +
  884. +/**
  885. + * ssam_event_queue_init() - Initialize an event queue.
  886. + * @cplt: The completion system on which the queue resides.
  887. + * @evq: The event queue to initialize.
  888. + */
  889. +static void ssam_event_queue_init(struct ssam_cplt *cplt,
  890. + struct ssam_event_queue *evq)
  891. +{
  892. + evq->cplt = cplt;
  893. + spin_lock_init(&evq->lock);
  894. + INIT_LIST_HEAD(&evq->head);
  895. + INIT_WORK(&evq->work, ssam_event_queue_work_fn);
  896. +}
  897. +
  898. +/**
  899. + * ssam_cplt_init() - Initialize completion system.
  900. + * @cplt: The completion system to initialize.
  901. + * @dev: The device used for logging.
  902. + */
  903. +static int ssam_cplt_init(struct ssam_cplt *cplt, struct device *dev)
  904. +{
  905. + struct ssam_event_target *target;
  906. + int status, c, i;
  907. +
  908. + cplt->dev = dev;
  909. +
  910. + cplt->wq = create_workqueue(SSAM_CPLT_WQ_NAME);
  911. + if (!cplt->wq)
  912. + return -ENOMEM;
  913. +
  914. + for (c = 0; c < ARRAY_SIZE(cplt->event.target); c++) {
  915. + target = &cplt->event.target[c];
  916. +
  917. + for (i = 0; i < ARRAY_SIZE(target->queue); i++)
  918. + ssam_event_queue_init(cplt, &target->queue[i]);
  919. + }
  920. +
  921. + status = ssam_nf_init(&cplt->event.notif);
  922. + if (status)
  923. + destroy_workqueue(cplt->wq);
  924. +
  925. + return status;
  926. +}
  927. +
  928. +/**
  929. + * ssam_cplt_destroy() - Deinitialize the completion system.
  930. + * @cplt: The completion system to deinitialize.
  931. + *
  932. + * Deinitialize the given completion system and ensure that all pending, i.e.
  933. + * yet-to-be-completed, event items and requests have been handled.
  934. + */
  935. +static void ssam_cplt_destroy(struct ssam_cplt *cplt)
  936. +{
  937. + /*
  938. + * Note: destroy_workqueue ensures that all currently queued work will
  939. + * be fully completed and the workqueue drained. This means that this
  940. + * call will inherently also free any queued ssam_event_items, thus we
  941. + * don't have to take care of that here explicitly.
  942. + */
  943. + destroy_workqueue(cplt->wq);
  944. + ssam_nf_destroy(&cplt->event.notif);
  945. +}
  946. +
  947. +
  948. +/* -- Main SSAM device structures. ------------------------------------------ */
  949. +
  950. +/**
  951. + * ssam_controller_device() - Get the &struct device associated with this
  952. + * controller.
  953. + * @c: The controller for which to get the device.
  954. + *
  955. + * Return: Returns the &struct device associated with this controller,
  956. + * providing its lower-level transport.
  957. + */
  958. +struct device *ssam_controller_device(struct ssam_controller *c)
  959. +{
  960. + return ssh_rtl_get_device(&c->rtl);
  961. +}
  962. +EXPORT_SYMBOL_GPL(ssam_controller_device);
  963. +
  964. +static void __ssam_controller_release(struct kref *kref)
  965. +{
  966. + struct ssam_controller *ctrl = to_ssam_controller(kref, kref);
  967. +
  968. + /*
  969. + * The lock-call here is to satisfy lockdep. At this point we really
  970. + * expect this to be the last remaining reference to the controller.
  971. + * Anything else is a bug.
  972. + */
  973. + ssam_controller_lock(ctrl);
  974. + ssam_controller_destroy(ctrl);
  975. + ssam_controller_unlock(ctrl);
  976. +
  977. + kfree(ctrl);
  978. +}
  979. +
  980. +/**
  981. + * ssam_controller_get() - Increment reference count of controller.
  982. + * @c: The controller.
  983. + *
  984. + * Return: Returns the controller provided as input.
  985. + */
  986. +struct ssam_controller *ssam_controller_get(struct ssam_controller *c)
  987. +{
  988. + if (c)
  989. + kref_get(&c->kref);
  990. + return c;
  991. +}
  992. +EXPORT_SYMBOL_GPL(ssam_controller_get);
  993. +
  994. +/**
  995. + * ssam_controller_put() - Decrement reference count of controller.
  996. + * @c: The controller.
  997. + */
  998. +void ssam_controller_put(struct ssam_controller *c)
  999. +{
  1000. + if (c)
  1001. + kref_put(&c->kref, __ssam_controller_release);
  1002. +}
  1003. +EXPORT_SYMBOL_GPL(ssam_controller_put);
  1004. +
  1005. +/**
  1006. + * ssam_controller_statelock() - Lock the controller against state transitions.
  1007. + * @c: The controller to lock.
  1008. + *
  1009. + * Lock the controller against state transitions. Holding this lock guarantees
  1010. + * that the controller will not transition between states, i.e. if the
  1011. + * controller is in state "started", when this lock has been acquired, it will
  1012. + * remain in this state at least until the lock has been released.
  1013. + *
  1014. + * Multiple clients may concurrently hold this lock. In other words: The
  1015. + * ``statelock`` functions represent the read-lock part of a r/w-semaphore.
  1016. + * Actions causing state transitions of the controller must be executed while
  1017. + * holding the write-part of this r/w-semaphore (see ssam_controller_lock()
  1018. + * and ssam_controller_unlock() for that).
  1019. + *
  1020. + * See ssam_controller_stateunlock() for the corresponding unlock function.
  1021. + */
  1022. +void ssam_controller_statelock(struct ssam_controller *c)
  1023. +{
  1024. + down_read(&c->lock);
  1025. +}
  1026. +EXPORT_SYMBOL_GPL(ssam_controller_statelock);
  1027. +
  1028. +/**
  1029. + * ssam_controller_stateunlock() - Unlock controller state transitions.
  1030. + * @c: The controller to unlock.
  1031. + *
  1032. + * See ssam_controller_statelock() for the corresponding lock function.
  1033. + */
  1034. +void ssam_controller_stateunlock(struct ssam_controller *c)
  1035. +{
  1036. + up_read(&c->lock);
  1037. +}
  1038. +EXPORT_SYMBOL_GPL(ssam_controller_stateunlock);
  1039. +
  1040. +/**
  1041. + * ssam_controller_lock() - Acquire the main controller lock.
  1042. + * @c: The controller to lock.
  1043. + *
  1044. + * This lock must be held for any state transitions, including transition to
  1045. + * suspend/resumed states and during shutdown. See ssam_controller_statelock()
  1046. + * for more details on controller locking.
  1047. + *
  1048. + * See ssam_controller_unlock() for the corresponding unlock function.
  1049. + */
  1050. +void ssam_controller_lock(struct ssam_controller *c)
  1051. +{
  1052. + down_write(&c->lock);
  1053. +}
  1054. +
  1055. +/*
  1056. + * ssam_controller_unlock() - Release the main controller lock.
  1057. + * @c: The controller to unlock.
  1058. + *
  1059. + * See ssam_controller_lock() for the corresponding lock function.
  1060. + */
  1061. +void ssam_controller_unlock(struct ssam_controller *c)
  1062. +{
  1063. + up_write(&c->lock);
  1064. +}
  1065. +
  1066. +static void ssam_handle_event(struct ssh_rtl *rtl,
  1067. + const struct ssh_command *cmd,
  1068. + const struct ssam_span *data)
  1069. +{
  1070. + struct ssam_controller *ctrl = to_ssam_controller(rtl, rtl);
  1071. + struct ssam_event_item *item;
  1072. +
  1073. + item = ssam_event_item_alloc(data->len, GFP_KERNEL);
  1074. + if (!item)
  1075. + return;
  1076. +
  1077. + item->rqid = get_unaligned_le16(&cmd->rqid);
  1078. + item->event.target_category = cmd->tc;
  1079. + item->event.target_id = cmd->tid_in;
  1080. + item->event.command_id = cmd->cid;
  1081. + item->event.instance_id = cmd->iid;
  1082. + memcpy(&item->event.data[0], data->ptr, data->len);
  1083. +
  1084. + if (WARN_ON(ssam_cplt_submit_event(&ctrl->cplt, item)))
  1085. + kfree(item);
  1086. +}
  1087. +
  1088. +static const struct ssh_rtl_ops ssam_rtl_ops = {
  1089. + .handle_event = ssam_handle_event,
  1090. +};
  1091. +
  1092. +static bool ssam_notifier_is_empty(struct ssam_controller *ctrl);
  1093. +static void ssam_notifier_unregister_all(struct ssam_controller *ctrl);
  1094. +
  1095. +#define SSAM_SSH_DSM_REVISION 0
  1096. +
  1097. +/* d5e383e1-d892-4a76-89fc-f6aaae7ed5b5 */
  1098. +static const guid_t SSAM_SSH_DSM_GUID =
  1099. + GUID_INIT(0xd5e383e1, 0xd892, 0x4a76,
  1100. + 0x89, 0xfc, 0xf6, 0xaa, 0xae, 0x7e, 0xd5, 0xb5);
  1101. +
  1102. +enum ssh_dsm_fn {
  1103. + SSH_DSM_FN_SSH_POWER_PROFILE = 0x05,
  1104. + SSH_DSM_FN_SCREEN_ON_SLEEP_IDLE_TIMEOUT = 0x06,
  1105. + SSH_DSM_FN_SCREEN_OFF_SLEEP_IDLE_TIMEOUT = 0x07,
  1106. + SSH_DSM_FN_D3_CLOSES_HANDLE = 0x08,
  1107. + SSH_DSM_FN_SSH_BUFFER_SIZE = 0x09,
  1108. +};
  1109. +
  1110. +static int ssam_dsm_get_functions(acpi_handle handle, u64 *funcs)
  1111. +{
  1112. + union acpi_object *obj;
  1113. + u64 mask = 0;
  1114. + int i;
  1115. +
  1116. + *funcs = 0;
  1117. +
  1118. + /*
  1119. + * The _DSM function is only present on newer models. It is not
  1120. + * present on 5th and 6th generation devices (i.e. up to and including
  1121. + * Surface Pro 6, Surface Laptop 2, Surface Book 2).
  1122. + *
  1123. + * If the _DSM is not present, indicate that no function is supported.
  1124. + * This will result in default values being set.
  1125. + */
  1126. + if (!acpi_has_method(handle, "_DSM"))
  1127. + return 0;
  1128. +
  1129. + obj = acpi_evaluate_dsm_typed(handle, &SSAM_SSH_DSM_GUID,
  1130. + SSAM_SSH_DSM_REVISION, 0, NULL,
  1131. + ACPI_TYPE_BUFFER);
  1132. + if (!obj)
  1133. + return -EIO;
  1134. +
  1135. + for (i = 0; i < obj->buffer.length && i < 8; i++)
  1136. + mask |= (((u64)obj->buffer.pointer[i]) << (i * 8));
  1137. +
  1138. + if (mask & BIT(0))
  1139. + *funcs = mask;
  1140. +
  1141. + ACPI_FREE(obj);
  1142. + return 0;
  1143. +}
  1144. +
  1145. +static int ssam_dsm_load_u32(acpi_handle handle, u64 funcs, u64 func, u32 *ret)
  1146. +{
  1147. + union acpi_object *obj;
  1148. + u64 val;
  1149. +
  1150. + if (!(funcs & BIT(func)))
  1151. + return 0; /* Not supported, leave *ret at its default value */
  1152. +
  1153. + obj = acpi_evaluate_dsm_typed(handle, &SSAM_SSH_DSM_GUID,
  1154. + SSAM_SSH_DSM_REVISION, func, NULL,
  1155. + ACPI_TYPE_INTEGER);
  1156. + if (!obj)
  1157. + return -EIO;
  1158. +
  1159. + val = obj->integer.value;
  1160. + ACPI_FREE(obj);
  1161. +
  1162. + if (val > U32_MAX)
  1163. + return -ERANGE;
  1164. +
  1165. + *ret = val;
  1166. + return 0;
  1167. +}
  1168. +
  1169. +/**
  1170. + * ssam_controller_caps_load_from_acpi() - Load controller capabilities from
  1171. + * ACPI _DSM.
  1172. + * @handle: The handle of the ACPI controller/SSH device.
  1173. + * @caps: Where to store the capabilities in.
  1174. + *
  1175. + * Initializes the given controller capabilities with default values, then
  1176. + * checks and, if the respective _DSM functions are available, loads the
  1177. + * actual capabilities from the _DSM.
  1178. + *
  1179. + * Return: Returns zero on success, a negative error code on failure.
  1180. + */
  1181. +static
  1182. +int ssam_controller_caps_load_from_acpi(acpi_handle handle,
  1183. + struct ssam_controller_caps *caps)
  1184. +{
  1185. + u32 d3_closes_handle = false;
  1186. + u64 funcs;
  1187. + int status;
  1188. +
  1189. + /* Set defaults. */
  1190. + caps->ssh_power_profile = U32_MAX;
  1191. + caps->screen_on_sleep_idle_timeout = U32_MAX;
  1192. + caps->screen_off_sleep_idle_timeout = U32_MAX;
  1193. + caps->d3_closes_handle = false;
  1194. + caps->ssh_buffer_size = U32_MAX;
  1195. +
  1196. + /* Pre-load supported DSM functions. */
  1197. + status = ssam_dsm_get_functions(handle, &funcs);
  1198. + if (status)
  1199. + return status;
  1200. +
  1201. + /* Load actual values from ACPI, if present. */
  1202. + status = ssam_dsm_load_u32(handle, funcs, SSH_DSM_FN_SSH_POWER_PROFILE,
  1203. + &caps->ssh_power_profile);
  1204. + if (status)
  1205. + return status;
  1206. +
  1207. + status = ssam_dsm_load_u32(handle, funcs,
  1208. + SSH_DSM_FN_SCREEN_ON_SLEEP_IDLE_TIMEOUT,
  1209. + &caps->screen_on_sleep_idle_timeout);
  1210. + if (status)
  1211. + return status;
  1212. +
  1213. + status = ssam_dsm_load_u32(handle, funcs,
  1214. + SSH_DSM_FN_SCREEN_OFF_SLEEP_IDLE_TIMEOUT,
  1215. + &caps->screen_off_sleep_idle_timeout);
  1216. + if (status)
  1217. + return status;
  1218. +
  1219. + status = ssam_dsm_load_u32(handle, funcs, SSH_DSM_FN_D3_CLOSES_HANDLE,
  1220. + &d3_closes_handle);
  1221. + if (status)
  1222. + return status;
  1223. +
  1224. + caps->d3_closes_handle = !!d3_closes_handle;
  1225. +
  1226. + status = ssam_dsm_load_u32(handle, funcs, SSH_DSM_FN_SSH_BUFFER_SIZE,
  1227. + &caps->ssh_buffer_size);
  1228. + if (status)
  1229. + return status;
  1230. +
  1231. + return 0;
  1232. +}
  1233. +
  1234. +/**
  1235. + * ssam_controller_init() - Initialize SSAM controller.
  1236. + * @ctrl: The controller to initialize.
  1237. + * @serdev: The serial device representing the underlying data transport.
  1238. + *
  1239. + * Initializes the given controller. Does neither start receiver nor
  1240. + * transmitter threads. After this call, the controller has to be hooked up to
  1241. + * the serdev core separately via &struct serdev_device_ops, relaying calls to
  1242. + * ssam_controller_receive_buf() and ssam_controller_write_wakeup(). Once the
  1243. + * controller has been hooked up, transmitter and receiver threads may be
  1244. + * started via ssam_controller_start(). These setup steps need to be completed
  1245. + * before controller can be used for requests.
  1246. + */
  1247. +int ssam_controller_init(struct ssam_controller *ctrl,
  1248. + struct serdev_device *serdev)
  1249. +{
  1250. + acpi_handle handle = ACPI_HANDLE(&serdev->dev);
  1251. + int status;
  1252. +
  1253. + init_rwsem(&ctrl->lock);
  1254. + kref_init(&ctrl->kref);
  1255. +
  1256. + status = ssam_controller_caps_load_from_acpi(handle, &ctrl->caps);
  1257. + if (status)
  1258. + return status;
  1259. +
  1260. + dev_dbg(&serdev->dev,
  1261. + "device capabilities:\n"
  1262. + " ssh_power_profile: %u\n"
  1263. + " ssh_buffer_size: %u\n"
  1264. + " screen_on_sleep_idle_timeout: %u\n"
  1265. + " screen_off_sleep_idle_timeout: %u\n"
  1266. + " d3_closes_handle: %u\n",
  1267. + ctrl->caps.ssh_power_profile,
  1268. + ctrl->caps.ssh_buffer_size,
  1269. + ctrl->caps.screen_on_sleep_idle_timeout,
  1270. + ctrl->caps.screen_off_sleep_idle_timeout,
  1271. + ctrl->caps.d3_closes_handle);
  1272. +
  1273. + ssh_seq_reset(&ctrl->counter.seq);
  1274. + ssh_rqid_reset(&ctrl->counter.rqid);
  1275. +
  1276. + /* Initialize event/request completion system. */
  1277. + status = ssam_cplt_init(&ctrl->cplt, &serdev->dev);
  1278. + if (status)
  1279. + return status;
  1280. +
  1281. + /* Initialize request and packet transport layers. */
  1282. + status = ssh_rtl_init(&ctrl->rtl, serdev, &ssam_rtl_ops);
  1283. + if (status) {
  1284. + ssam_cplt_destroy(&ctrl->cplt);
  1285. + return status;
  1286. + }
  1287. +
  1288. + /*
  1289. + * Set state via write_once even though we expect to be in an
  1290. + * exclusive context, due to smoke-testing in
  1291. + * ssam_request_sync_submit().
  1292. + */
  1293. + WRITE_ONCE(ctrl->state, SSAM_CONTROLLER_INITIALIZED);
  1294. + return 0;
  1295. +}
  1296. +
  1297. +/**
  1298. + * ssam_controller_start() - Start the receiver and transmitter threads of the
  1299. + * controller.
  1300. + * @ctrl: The controller.
  1301. + *
  1302. + * Note: When this function is called, the controller should be properly
  1303. + * hooked up to the serdev core via &struct serdev_device_ops. Please refer
  1304. + * to ssam_controller_init() for more details on controller initialization.
  1305. + *
  1306. + * This function must be called with the main controller lock held (i.e. by
  1307. + * calling ssam_controller_lock()).
  1308. + */
  1309. +int ssam_controller_start(struct ssam_controller *ctrl)
  1310. +{
  1311. + int status;
  1312. +
  1313. + lockdep_assert_held_write(&ctrl->lock);
  1314. +
  1315. + if (ctrl->state != SSAM_CONTROLLER_INITIALIZED)
  1316. + return -EINVAL;
  1317. +
  1318. + status = ssh_rtl_start(&ctrl->rtl);
  1319. + if (status)
  1320. + return status;
  1321. +
  1322. + /*
  1323. + * Set state via write_once even though we expect to be locked/in an
  1324. + * exclusive context, due to smoke-testing in
  1325. + * ssam_request_sync_submit().
  1326. + */
  1327. + WRITE_ONCE(ctrl->state, SSAM_CONTROLLER_STARTED);
  1328. + return 0;
  1329. +}
  1330. +
  1331. +/*
  1332. + * SSAM_CTRL_SHUTDOWN_FLUSH_TIMEOUT - Timeout for flushing requests during
  1333. + * shutdown.
  1334. + *
  1335. + * Chosen to be larger than one full request timeout, including packets timing
  1336. + * out. This value should give ample time to complete any outstanding requests
  1337. + * during normal operation and account for the odd package timeout.
  1338. + */
  1339. +#define SSAM_CTRL_SHUTDOWN_FLUSH_TIMEOUT msecs_to_jiffies(5000)
  1340. +
  1341. +/**
  1342. + * ssam_controller_shutdown() - Shut down the controller.
  1343. + * @ctrl: The controller.
  1344. + *
  1345. + * Shuts down the controller by flushing all pending requests and stopping the
  1346. + * transmitter and receiver threads. All requests submitted after this call
  1347. + * will fail with %-ESHUTDOWN. While it is discouraged to do so, this function
  1348. + * is safe to use in parallel with ongoing request submission.
  1349. + *
  1350. + * In the course of this shutdown procedure, all currently registered
  1351. + * notifiers will be unregistered. It is, however, strongly recommended to not
  1352. + * rely on this behavior, and instead the party registering the notifier
  1353. + * should unregister it before the controller gets shut down, e.g. via the
  1354. + * SSAM bus which guarantees client devices to be removed before a shutdown.
  1355. + *
  1356. + * Note that events may still be pending after this call, but, due to the
  1357. + * notifiers being unregistered, these events will be dropped when the
  1358. + * controller is subsequently destroyed via ssam_controller_destroy().
  1359. + *
  1360. + * This function must be called with the main controller lock held (i.e. by
  1361. + * calling ssam_controller_lock()).
  1362. + */
  1363. +void ssam_controller_shutdown(struct ssam_controller *ctrl)
  1364. +{
  1365. + enum ssam_controller_state s = ctrl->state;
  1366. + int status;
  1367. +
  1368. + lockdep_assert_held_write(&ctrl->lock);
  1369. +
  1370. + if (s == SSAM_CONTROLLER_UNINITIALIZED || s == SSAM_CONTROLLER_STOPPED)
  1371. + return;
  1372. +
  1373. + /*
  1374. + * Try to flush pending events and requests while everything still
  1375. + * works. Note: There may still be packets and/or requests in the
  1376. + * system after this call (e.g. via control packets submitted by the
  1377. + * packet transport layer or flush timeout / failure, ...). Those will
  1378. + * be handled with the ssh_rtl_shutdown() call below.
  1379. + */
  1380. + status = ssh_rtl_flush(&ctrl->rtl, SSAM_CTRL_SHUTDOWN_FLUSH_TIMEOUT);
  1381. + if (status) {
  1382. + ssam_err(ctrl, "failed to flush request transport layer: %d\n",
  1383. + status);
  1384. + }
  1385. +
  1386. + /* Try to flush all currently completing requests and events. */
  1387. + ssam_cplt_flush(&ctrl->cplt);
  1388. +
  1389. + /*
  1390. + * We expect all notifiers to have been removed by the respective client
  1391. + * driver that set them up at this point. If this warning occurs, some
  1392. + * client driver has not done that...
  1393. + */
  1394. + WARN_ON(!ssam_notifier_is_empty(ctrl));
  1395. +
  1396. + /*
  1397. + * Nevertheless, we should still take care of drivers that don't behave
  1398. + * well. Thus disable all enabled events, unregister all notifiers.
  1399. + */
  1400. + ssam_notifier_unregister_all(ctrl);
  1401. +
  1402. + /*
  1403. + * Cancel remaining requests. Ensure no new ones can be queued and stop
  1404. + * threads.
  1405. + */
  1406. + ssh_rtl_shutdown(&ctrl->rtl);
  1407. +
  1408. + /*
  1409. + * Set state via write_once even though we expect to be locked/in an
  1410. + * exclusive context, due to smoke-testing in
  1411. + * ssam_request_sync_submit().
  1412. + */
  1413. + WRITE_ONCE(ctrl->state, SSAM_CONTROLLER_STOPPED);
  1414. + ctrl->rtl.ptl.serdev = NULL;
  1415. +}
  1416. +
  1417. +/**
  1418. + * ssam_controller_destroy() - Destroy the controller and free its resources.
  1419. + * @ctrl: The controller.
  1420. + *
  1421. + * Ensures that all resources associated with the controller get freed. This
  1422. + * function should only be called after the controller has been stopped via
  1423. + * ssam_controller_shutdown(). In general, this function should not be called
  1424. + * directly. The only valid place to call this function directly is during
  1425. + * initialization, before the controller has been fully initialized and passed
  1426. + * to other processes. This function is called automatically when the
  1427. + * reference count of the controller reaches zero.
  1428. + *
  1429. + * This function must be called with the main controller lock held (i.e. by
  1430. + * calling ssam_controller_lock()).
  1431. + */
  1432. +void ssam_controller_destroy(struct ssam_controller *ctrl)
  1433. +{
  1434. + lockdep_assert_held_write(&ctrl->lock);
  1435. +
  1436. + if (ctrl->state == SSAM_CONTROLLER_UNINITIALIZED)
  1437. + return;
  1438. +
  1439. + WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED);
  1440. +
  1441. + /*
  1442. + * Note: New events could still have been received after the previous
  1443. + * flush in ssam_controller_shutdown, before the request transport layer
  1444. + * has been shut down. At this point, after the shutdown, we can be sure
  1445. + * that no new events will be queued. The call to ssam_cplt_destroy will
  1446. + * ensure that those remaining are being completed and freed.
  1447. + */
  1448. +
  1449. + /* Actually free resources. */
  1450. + ssam_cplt_destroy(&ctrl->cplt);
  1451. + ssh_rtl_destroy(&ctrl->rtl);
  1452. +
  1453. + /*
  1454. + * Set state via write_once even though we expect to be locked/in an
  1455. + * exclusive context, due to smoke-testing in
  1456. + * ssam_request_sync_submit().
  1457. + */
  1458. + WRITE_ONCE(ctrl->state, SSAM_CONTROLLER_UNINITIALIZED);
  1459. +}
  1460. +
  1461. +/**
  1462. + * ssam_controller_suspend() - Suspend the controller.
  1463. + * @ctrl: The controller to suspend.
  1464. + *
  1465. + * Marks the controller as suspended. Note that display-off and D0-exit
  1466. + * notifications have to be sent manually before transitioning the controller
  1467. + * into the suspended state via this function.
  1468. + *
  1469. + * See ssam_controller_resume() for the corresponding resume function.
  1470. + *
  1471. + * Return: Returns %-EINVAL if the controller is currently not in the
  1472. + * "started" state.
  1473. + */
  1474. +int ssam_controller_suspend(struct ssam_controller *ctrl)
  1475. +{
  1476. + ssam_controller_lock(ctrl);
  1477. +
  1478. + if (ctrl->state != SSAM_CONTROLLER_STARTED) {
  1479. + ssam_controller_unlock(ctrl);
  1480. + return -EINVAL;
  1481. + }
  1482. +
  1483. + ssam_dbg(ctrl, "pm: suspending controller\n");
  1484. +
  1485. + /*
  1486. + * Set state via write_once even though we're locked, due to
  1487. + * smoke-testing in ssam_request_sync_submit().
  1488. + */
  1489. + WRITE_ONCE(ctrl->state, SSAM_CONTROLLER_SUSPENDED);
  1490. +
  1491. + ssam_controller_unlock(ctrl);
  1492. + return 0;
  1493. +}
  1494. +
  1495. +/**
  1496. + * ssam_controller_resume() - Resume the controller from suspend.
  1497. + * @ctrl: The controller to resume.
  1498. + *
  1499. + * Resume the controller from the suspended state it was put into via
  1500. + * ssam_controller_suspend(). This function does not issue display-on and
  1501. + * D0-entry notifications. If required, those have to be sent manually after
  1502. + * this call.
  1503. + *
  1504. + * Return: Returns %-EINVAL if the controller is currently not suspended.
  1505. + */
  1506. +int ssam_controller_resume(struct ssam_controller *ctrl)
  1507. +{
  1508. + ssam_controller_lock(ctrl);
  1509. +
  1510. + if (ctrl->state != SSAM_CONTROLLER_SUSPENDED) {
  1511. + ssam_controller_unlock(ctrl);
  1512. + return -EINVAL;
  1513. + }
  1514. +
  1515. + ssam_dbg(ctrl, "pm: resuming controller\n");
  1516. +
  1517. + /*
  1518. + * Set state via write_once even though we're locked, due to
  1519. + * smoke-testing in ssam_request_sync_submit().
  1520. + */
  1521. + WRITE_ONCE(ctrl->state, SSAM_CONTROLLER_STARTED);
  1522. +
  1523. + ssam_controller_unlock(ctrl);
  1524. + return 0;
  1525. +}
  1526. +
  1527. +
  1528. +/* -- Top-level request interface ------------------------------------------- */
  1529. +
  1530. +/**
  1531. + * ssam_request_write_data() - Construct and write SAM request message to
  1532. + * buffer.
  1533. + * @buf: The buffer to write the data to.
  1534. + * @ctrl: The controller via which the request will be sent.
  1535. + * @spec: The request data and specification.
  1536. + *
  1537. + * Constructs a SAM/SSH request message and writes it to the provided buffer.
  1538. + * The request and transport counters, specifically RQID and SEQ, will be set
  1539. + * in this call. These counters are obtained from the controller. It is thus
  1540. + * only valid to send the resulting message via the controller specified here.
  1541. + *
  1542. + * For calculation of the required buffer size, refer to the
  1543. + * SSH_COMMAND_MESSAGE_LENGTH() macro.
  1544. + *
  1545. + * Return: Returns the number of bytes used in the buffer on success. Returns
  1546. + * %-EINVAL if the payload length provided in the request specification is too
  1547. + * large (larger than %SSH_COMMAND_MAX_PAYLOAD_SIZE) or if the provided buffer
  1548. + * is too small.
  1549. + */
  1550. +ssize_t ssam_request_write_data(struct ssam_span *buf,
  1551. + struct ssam_controller *ctrl,
  1552. + const struct ssam_request *spec)
  1553. +{
  1554. + struct msgbuf msgb;
  1555. + u16 rqid;
  1556. + u8 seq;
  1557. +
  1558. + if (spec->length > SSH_COMMAND_MAX_PAYLOAD_SIZE)
  1559. + return -EINVAL;
  1560. +
  1561. + if (SSH_COMMAND_MESSAGE_LENGTH(spec->length) > buf->len)
  1562. + return -EINVAL;
  1563. +
  1564. + msgb_init(&msgb, buf->ptr, buf->len);
  1565. + seq = ssh_seq_next(&ctrl->counter.seq);
  1566. + rqid = ssh_rqid_next(&ctrl->counter.rqid);
  1567. + msgb_push_cmd(&msgb, seq, rqid, spec);
  1568. +
  1569. + return msgb_bytes_used(&msgb);
  1570. +}
  1571. +EXPORT_SYMBOL_GPL(ssam_request_write_data);
  1572. +
  1573. +static void ssam_request_sync_complete(struct ssh_request *rqst,
  1574. + const struct ssh_command *cmd,
  1575. + const struct ssam_span *data, int status)
  1576. +{
  1577. + struct ssh_rtl *rtl = ssh_request_rtl(rqst);
  1578. + struct ssam_request_sync *r;
  1579. +
  1580. + r = container_of(rqst, struct ssam_request_sync, base);
  1581. + r->status = status;
  1582. +
  1583. + if (r->resp)
  1584. + r->resp->length = 0;
  1585. +
  1586. + if (status) {
  1587. + rtl_dbg_cond(rtl, "rsp: request failed: %d\n", status);
  1588. + return;
  1589. + }
  1590. +
  1591. + if (!data) /* Handle requests without a response. */
  1592. + return;
  1593. +
  1594. + if (!r->resp || !r->resp->pointer) {
  1595. + if (data->len)
  1596. + rtl_warn(rtl, "rsp: no response buffer provided, dropping data\n");
  1597. + return;
  1598. + }
  1599. +
  1600. + if (data->len > r->resp->capacity) {
  1601. + rtl_err(rtl,
  1602. + "rsp: response buffer too small, capacity: %zu bytes, got: %zu bytes\n",
  1603. + r->resp->capacity, data->len);
  1604. + r->status = -ENOSPC;
  1605. + return;
  1606. + }
  1607. +
  1608. + r->resp->length = data->len;
  1609. + memcpy(r->resp->pointer, data->ptr, data->len);
  1610. +}
  1611. +
  1612. +static void ssam_request_sync_release(struct ssh_request *rqst)
  1613. +{
  1614. + complete_all(&container_of(rqst, struct ssam_request_sync, base)->comp);
  1615. +}
  1616. +
  1617. +static const struct ssh_request_ops ssam_request_sync_ops = {
  1618. + .release = ssam_request_sync_release,
  1619. + .complete = ssam_request_sync_complete,
  1620. +};
  1621. +
  1622. +/**
  1623. + * ssam_request_sync_alloc() - Allocate a synchronous request.
  1624. + * @payload_len: The length of the request payload.
  1625. + * @flags: Flags used for allocation.
  1626. + * @rqst: Where to store the pointer to the allocated request.
  1627. + * @buffer: Where to store the buffer descriptor for the message buffer of
  1628. + * the request.
  1629. + *
  1630. + * Allocates a synchronous request with corresponding message buffer. The
  1631. + * request still needs to be initialized ssam_request_sync_init() before
  1632. + * it can be submitted, and the message buffer data must still be set to the
  1633. + * returned buffer via ssam_request_sync_set_data() after it has been filled,
  1634. + * if need be with adjusted message length.
  1635. + *
  1636. + * After use, the request and its corresponding message buffer should be freed
  1637. + * via ssam_request_sync_free(). The buffer must not be freed separately.
  1638. + *
  1639. + * Return: Returns zero on success, %-ENOMEM if the request could not be
  1640. + * allocated.
  1641. + */
  1642. +int ssam_request_sync_alloc(size_t payload_len, gfp_t flags,
  1643. + struct ssam_request_sync **rqst,
  1644. + struct ssam_span *buffer)
  1645. +{
  1646. + size_t msglen = SSH_COMMAND_MESSAGE_LENGTH(payload_len);
  1647. +
  1648. + *rqst = kzalloc(sizeof(**rqst) + msglen, flags);
  1649. + if (!*rqst)
  1650. + return -ENOMEM;
  1651. +
  1652. + buffer->ptr = (u8 *)(*rqst + 1);
  1653. + buffer->len = msglen;
  1654. +
  1655. + return 0;
  1656. +}
  1657. +EXPORT_SYMBOL_GPL(ssam_request_sync_alloc);
  1658. +
  1659. +/**
  1660. + * ssam_request_sync_free() - Free a synchronous request.
  1661. + * @rqst: The request to be freed.
  1662. + *
  1663. + * Free a synchronous request and its corresponding buffer allocated with
  1664. + * ssam_request_sync_alloc(). Do not use for requests allocated on the stack
  1665. + * or via any other function.
  1666. + *
  1667. + * Warning: The caller must ensure that the request is not in use any more.
  1668. + * I.e. the caller must ensure that it has the only reference to the request
  1669. + * and the request is not currently pending. This means that the caller has
  1670. + * either never submitted the request, request submission has failed, or the
  1671. + * caller has waited until the submitted request has been completed via
  1672. + * ssam_request_sync_wait().
  1673. + */
  1674. +void ssam_request_sync_free(struct ssam_request_sync *rqst)
  1675. +{
  1676. + kfree(rqst);
  1677. +}
  1678. +EXPORT_SYMBOL_GPL(ssam_request_sync_free);
  1679. +
  1680. +/**
  1681. + * ssam_request_sync_init() - Initialize a synchronous request struct.
  1682. + * @rqst: The request to initialize.
  1683. + * @flags: The request flags.
  1684. + *
  1685. + * Initializes the given request struct. Does not initialize the request
  1686. + * message data. This has to be done explicitly after this call via
  1687. + * ssam_request_sync_set_data() and the actual message data has to be written
  1688. + * via ssam_request_write_data().
  1689. + *
  1690. + * Return: Returns zero on success or %-EINVAL if the given flags are invalid.
  1691. + */
  1692. +int ssam_request_sync_init(struct ssam_request_sync *rqst,
  1693. + enum ssam_request_flags flags)
  1694. +{
  1695. + int status;
  1696. +
  1697. + status = ssh_request_init(&rqst->base, flags, &ssam_request_sync_ops);
  1698. + if (status)
  1699. + return status;
  1700. +
  1701. + init_completion(&rqst->comp);
  1702. + rqst->resp = NULL;
  1703. + rqst->status = 0;
  1704. +
  1705. + return 0;
  1706. +}
  1707. +EXPORT_SYMBOL_GPL(ssam_request_sync_init);
  1708. +
  1709. +/**
  1710. + * ssam_request_sync_submit() - Submit a synchronous request.
  1711. + * @ctrl: The controller with which to submit the request.
  1712. + * @rqst: The request to submit.
  1713. + *
  1714. + * Submit a synchronous request. The request has to be initialized and
  1715. + * properly set up, including response buffer (may be %NULL if no response is
  1716. + * expected) and command message data. This function does not wait for the
  1717. + * request to be completed.
  1718. + *
  1719. + * If this function succeeds, ssam_request_sync_wait() must be used to ensure
  1720. + * that the request has been completed before the response data can be
  1721. + * accessed and/or the request can be freed. On failure, the request may
  1722. + * immediately be freed.
  1723. + *
  1724. + * This function may only be used if the controller is active, i.e. has been
  1725. + * initialized and not suspended.
  1726. + */
  1727. +int ssam_request_sync_submit(struct ssam_controller *ctrl,
  1728. + struct ssam_request_sync *rqst)
  1729. +{
  1730. + int status;
  1731. +
  1732. + /*
  1733. + * This is only a superficial check. In general, the caller needs to
  1734. + * ensure that the controller is initialized and is not (and does not
  1735. + * get) suspended during use, i.e. until the request has been completed
  1736. + * (if _absolutely_ necessary, by use of ssam_controller_statelock/
  1737. + * ssam_controller_stateunlock, but something like ssam_client_link
  1738. + * should be preferred as this needs to last until the request has been
  1739. + * completed).
  1740. + *
  1741. + * Note that it is actually safe to use this function while the
  1742. + * controller is in the process of being shut down (as ssh_rtl_submit
  1743. + * is safe with regards to this), but it is generally discouraged to do
  1744. + * so.
  1745. + */
  1746. + if (WARN_ON(READ_ONCE(ctrl->state) != SSAM_CONTROLLER_STARTED)) {
  1747. + ssh_request_put(&rqst->base);
  1748. + return -ENODEV;
  1749. + }
  1750. +
  1751. + status = ssh_rtl_submit(&ctrl->rtl, &rqst->base);
  1752. + ssh_request_put(&rqst->base);
  1753. +
  1754. + return status;
  1755. +}
  1756. +EXPORT_SYMBOL_GPL(ssam_request_sync_submit);
  1757. +
  1758. +/**
  1759. + * ssam_request_sync() - Execute a synchronous request.
  1760. + * @ctrl: The controller via which the request will be submitted.
  1761. + * @spec: The request specification and payload.
  1762. + * @rsp: The response buffer.
  1763. + *
  1764. + * Allocates a synchronous request with its message data buffer on the heap
  1765. + * via ssam_request_sync_alloc(), fully initializes it via the provided
  1766. + * request specification, submits it, and finally waits for its completion
  1767. + * before freeing it and returning its status.
  1768. + *
  1769. + * Return: Returns the status of the request or any failure during setup.
  1770. + */
  1771. +int ssam_request_sync(struct ssam_controller *ctrl,
  1772. + const struct ssam_request *spec,
  1773. + struct ssam_response *rsp)
  1774. +{
  1775. + struct ssam_request_sync *rqst;
  1776. + struct ssam_span buf;
  1777. + ssize_t len;
  1778. + int status;
  1779. +
  1780. + status = ssam_request_sync_alloc(spec->length, GFP_KERNEL, &rqst, &buf);
  1781. + if (status)
  1782. + return status;
  1783. +
  1784. + status = ssam_request_sync_init(rqst, spec->flags);
  1785. + if (status)
  1786. + return status;
  1787. +
  1788. + ssam_request_sync_set_resp(rqst, rsp);
  1789. +
  1790. + len = ssam_request_write_data(&buf, ctrl, spec);
  1791. + if (len < 0) {
  1792. + ssam_request_sync_free(rqst);
  1793. + return len;
  1794. + }
  1795. +
  1796. + ssam_request_sync_set_data(rqst, buf.ptr, len);
  1797. +
  1798. + status = ssam_request_sync_submit(ctrl, rqst);
  1799. + if (!status)
  1800. + status = ssam_request_sync_wait(rqst);
  1801. +
  1802. + ssam_request_sync_free(rqst);
  1803. + return status;
  1804. +}
  1805. +EXPORT_SYMBOL_GPL(ssam_request_sync);
  1806. +
  1807. +/**
  1808. + * ssam_request_sync_with_buffer() - Execute a synchronous request with the
  1809. + * provided buffer as back-end for the message buffer.
  1810. + * @ctrl: The controller via which the request will be submitted.
  1811. + * @spec: The request specification and payload.
  1812. + * @rsp: The response buffer.
  1813. + * @buf: The buffer for the request message data.
  1814. + *
  1815. + * Allocates a synchronous request struct on the stack, fully initializes it
  1816. + * using the provided buffer as message data buffer, submits it, and then
  1817. + * waits for its completion before returning its status. The
  1818. + * SSH_COMMAND_MESSAGE_LENGTH() macro can be used to compute the required
  1819. + * message buffer size.
  1820. + *
  1821. + * This function does essentially the same as ssam_request_sync(), but instead
  1822. + * of dynamically allocating the request and message data buffer, it uses the
  1823. + * provided message data buffer and stores the (small) request struct on the
  1824. + * heap.
  1825. + *
  1826. + * Return: Returns the status of the request or any failure during setup.
  1827. + */
  1828. +int ssam_request_sync_with_buffer(struct ssam_controller *ctrl,
  1829. + const struct ssam_request *spec,
  1830. + struct ssam_response *rsp,
  1831. + struct ssam_span *buf)
  1832. +{
  1833. + struct ssam_request_sync rqst;
  1834. + ssize_t len;
  1835. + int status;
  1836. +
  1837. + status = ssam_request_sync_init(&rqst, spec->flags);
  1838. + if (status)
  1839. + return status;
  1840. +
  1841. + ssam_request_sync_set_resp(&rqst, rsp);
  1842. +
  1843. + len = ssam_request_write_data(buf, ctrl, spec);
  1844. + if (len < 0)
  1845. + return len;
  1846. +
  1847. + ssam_request_sync_set_data(&rqst, buf->ptr, len);
  1848. +
  1849. + status = ssam_request_sync_submit(ctrl, &rqst);
  1850. + if (!status)
  1851. + status = ssam_request_sync_wait(&rqst);
  1852. +
  1853. + return status;
  1854. +}
  1855. +EXPORT_SYMBOL_GPL(ssam_request_sync_with_buffer);
  1856. +
  1857. +
  1858. +/* -- Internal SAM requests. ------------------------------------------------ */
  1859. +
  1860. +static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_get_firmware_version, __le32, {
  1861. + .target_category = SSAM_SSH_TC_SAM,
  1862. + .target_id = 0x01,
  1863. + .command_id = 0x13,
  1864. + .instance_id = 0x00,
  1865. +});
  1866. +
  1867. +static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_off, u8, {
  1868. + .target_category = SSAM_SSH_TC_SAM,
  1869. + .target_id = 0x01,
  1870. + .command_id = 0x15,
  1871. + .instance_id = 0x00,
  1872. +});
  1873. +
  1874. +static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_on, u8, {
  1875. + .target_category = SSAM_SSH_TC_SAM,
  1876. + .target_id = 0x01,
  1877. + .command_id = 0x16,
  1878. + .instance_id = 0x00,
  1879. +});
  1880. +
  1881. +static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_exit, u8, {
  1882. + .target_category = SSAM_SSH_TC_SAM,
  1883. + .target_id = 0x01,
  1884. + .command_id = 0x33,
  1885. + .instance_id = 0x00,
  1886. +});
  1887. +
  1888. +static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_entry, u8, {
  1889. + .target_category = SSAM_SSH_TC_SAM,
  1890. + .target_id = 0x01,
  1891. + .command_id = 0x34,
  1892. + .instance_id = 0x00,
  1893. +});
  1894. +
  1895. +/**
  1896. + * struct ssh_notification_params - Command payload to enable/disable SSH
  1897. + * notifications.
  1898. + * @target_category: The target category for which notifications should be
  1899. + * enabled/disabled.
  1900. + * @flags: Flags determining how notifications are being sent.
  1901. + * @request_id: The request ID that is used to send these notifications.
  1902. + * @instance_id: The specific instance in the given target category for
  1903. + * which notifications should be enabled.
  1904. + */
  1905. +struct ssh_notification_params {
  1906. + u8 target_category;
  1907. + u8 flags;
  1908. + __le16 request_id;
  1909. + u8 instance_id;
  1910. +} __packed;
  1911. +
  1912. +static_assert(sizeof(struct ssh_notification_params) == 5);
  1913. +
  1914. +static int __ssam_ssh_event_request(struct ssam_controller *ctrl,
  1915. + struct ssam_event_registry reg, u8 cid,
  1916. + struct ssam_event_id id, u8 flags)
  1917. +{
  1918. + struct ssh_notification_params params;
  1919. + struct ssam_request rqst;
  1920. + struct ssam_response result;
  1921. + int status;
  1922. +
  1923. + u16 rqid = ssh_tc_to_rqid(id.target_category);
  1924. + u8 buf = 0;
  1925. +
  1926. + /* Only allow RQIDs that lie within the event spectrum. */
  1927. + if (!ssh_rqid_is_event(rqid))
  1928. + return -EINVAL;
  1929. +
  1930. + params.target_category = id.target_category;
  1931. + params.instance_id = id.instance;
  1932. + params.flags = flags;
  1933. + put_unaligned_le16(rqid, &params.request_id);
  1934. +
  1935. + rqst.target_category = reg.target_category;
  1936. + rqst.target_id = reg.target_id;
  1937. + rqst.command_id = cid;
  1938. + rqst.instance_id = 0x00;
  1939. + rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
  1940. + rqst.length = sizeof(params);
  1941. + rqst.payload = (u8 *)&params;
  1942. +
  1943. + result.capacity = sizeof(buf);
  1944. + result.length = 0;
  1945. + result.pointer = &buf;
  1946. +
  1947. + status = ssam_retry(ssam_request_sync_onstack, ctrl, &rqst, &result,
  1948. + sizeof(params));
  1949. +
  1950. + return status < 0 ? status : buf;
  1951. +}
  1952. +
  1953. +/**
  1954. + * ssam_ssh_event_enable() - Enable SSH event.
  1955. + * @ctrl: The controller for which to enable the event.
  1956. + * @reg: The event registry describing what request to use for enabling and
  1957. + * disabling the event.
  1958. + * @id: The event identifier.
  1959. + * @flags: The event flags.
  1960. + *
  1961. + * Enables the specified event on the EC. This function does not manage
  1962. + * reference counting of enabled events and is basically only a wrapper for
  1963. + * the raw EC request. If the specified event is already enabled, the EC will
  1964. + * ignore this request.
  1965. + *
  1966. + * Return: Returns the status of the executed SAM request (zero on success and
  1967. + * negative on direct failure) or %-EPROTO if the request response indicates a
  1968. + * failure.
  1969. + */
  1970. +static int ssam_ssh_event_enable(struct ssam_controller *ctrl,
  1971. + struct ssam_event_registry reg,
  1972. + struct ssam_event_id id, u8 flags)
  1973. +{
  1974. + int status;
  1975. +
  1976. + status = __ssam_ssh_event_request(ctrl, reg, reg.cid_enable, id, flags);
  1977. +
  1978. + if (status < 0 && status != -EINVAL) {
  1979. + ssam_err(ctrl,
  1980. + "failed to enable event source (tc: %#04x, iid: %#04x, reg: %#04x)\n",
  1981. + id.target_category, id.instance, reg.target_category);
  1982. + }
  1983. +
  1984. + if (status > 0) {
  1985. + ssam_err(ctrl,
  1986. + "unexpected result while enabling event source: %#04x (tc: %#04x, iid: %#04x, reg: %#04x)\n",
  1987. + status, id.target_category, id.instance, reg.target_category);
  1988. + return -EPROTO;
  1989. + }
  1990. +
  1991. + return status;
  1992. +}
  1993. +
  1994. +/**
  1995. + * ssam_ssh_event_disable() - Disable SSH event.
  1996. + * @ctrl: The controller for which to disable the event.
  1997. + * @reg: The event registry describing what request to use for enabling and
  1998. + * disabling the event (must be same as used when enabling the event).
  1999. + * @id: The event identifier.
  2000. + * @flags: The event flags (likely ignored for disabling of events).
  2001. + *
  2002. + * Disables the specified event on the EC. This function does not manage
  2003. + * reference counting of enabled events and is basically only a wrapper for
  2004. + * the raw EC request. If the specified event is already disabled, the EC will
  2005. + * ignore this request.
  2006. + *
  2007. + * Return: Returns the status of the executed SAM request (zero on success and
  2008. + * negative on direct failure) or %-EPROTO if the request response indicates a
  2009. + * failure.
  2010. + */
  2011. +static int ssam_ssh_event_disable(struct ssam_controller *ctrl,
  2012. + struct ssam_event_registry reg,
  2013. + struct ssam_event_id id, u8 flags)
  2014. +{
  2015. + int status;
  2016. +
  2017. + status = __ssam_ssh_event_request(ctrl, reg, reg.cid_enable, id, flags);
  2018. +
  2019. + if (status < 0 && status != -EINVAL) {
  2020. + ssam_err(ctrl,
  2021. + "failed to disable event source (tc: %#04x, iid: %#04x, reg: %#04x)\n",
  2022. + id.target_category, id.instance, reg.target_category);
  2023. + }
  2024. +
  2025. + if (status > 0) {
  2026. + ssam_err(ctrl,
  2027. + "unexpected result while disabling event source: %#04x (tc: %#04x, iid: %#04x, reg: %#04x)\n",
  2028. + status, id.target_category, id.instance, reg.target_category);
  2029. + return -EPROTO;
  2030. + }
  2031. +
  2032. + return status;
  2033. +}
  2034. +
  2035. +
  2036. +/* -- Wrappers for internal SAM requests. ----------------------------------- */
  2037. +
  2038. +/**
  2039. + * ssam_get_firmware_version() - Get the SAM/EC firmware version.
  2040. + * @ctrl: The controller.
  2041. + * @version: Where to store the version number.
  2042. + *
  2043. + * Return: Returns zero on success or the status of the executed SAM request
  2044. + * if that request failed.
  2045. + */
  2046. +int ssam_get_firmware_version(struct ssam_controller *ctrl, u32 *version)
  2047. +{
  2048. + __le32 __version;
  2049. + int status;
  2050. +
  2051. + status = ssam_retry(ssam_ssh_get_firmware_version, ctrl, &__version);
  2052. + if (status)
  2053. + return status;
  2054. +
  2055. + *version = le32_to_cpu(__version);
  2056. + return 0;
  2057. +}
  2058. +
  2059. +/**
  2060. + * ssam_ctrl_notif_display_off() - Notify EC that the display has been turned
  2061. + * off.
  2062. + * @ctrl: The controller.
  2063. + *
  2064. + * Notify the EC that the display has been turned off and the driver may enter
  2065. + * a lower-power state. This will prevent events from being sent directly.
  2066. + * Rather, the EC signals an event by pulling the wakeup GPIO high for as long
  2067. + * as there are pending events. The events then need to be manually released,
  2068. + * one by one, via the GPIO callback request. All pending events accumulated
  2069. + * during this state can also be released by issuing the display-on
  2070. + * notification, e.g. via ssam_ctrl_notif_display_on(), which will also reset
  2071. + * the GPIO.
  2072. + *
  2073. + * On some devices, specifically ones with an integrated keyboard, the keyboard
  2074. + * backlight will be turned off by this call.
  2075. + *
  2076. + * This function will only send the display-off notification command if
  2077. + * display notifications are supported by the EC. Currently all known devices
  2078. + * support these notifications.
  2079. + *
  2080. + * Use ssam_ctrl_notif_display_on() to reverse the effects of this function.
  2081. + *
  2082. + * Return: Returns zero on success or if no request has been executed, the
  2083. + * status of the executed SAM request if that request failed, or %-EPROTO if
  2084. + * an unexpected response has been received.
  2085. + */
  2086. +int ssam_ctrl_notif_display_off(struct ssam_controller *ctrl)
  2087. +{
  2088. + int status;
  2089. + u8 response;
  2090. +
  2091. + ssam_dbg(ctrl, "pm: notifying display off\n");
  2092. +
  2093. + status = ssam_retry(ssam_ssh_notif_display_off, ctrl, &response);
  2094. + if (status)
  2095. + return status;
  2096. +
  2097. + if (response != 0) {
  2098. + ssam_err(ctrl, "unexpected response from display-off notification: %#04x\n",
  2099. + response);
  2100. + return -EPROTO;
  2101. + }
  2102. +
  2103. + return 0;
  2104. +}
  2105. +
  2106. +/**
  2107. + * ssam_ctrl_notif_display_on() - Notify EC that the display has been turned on.
  2108. + * @ctrl: The controller.
  2109. + *
  2110. + * Notify the EC that the display has been turned back on and the driver has
  2111. + * exited its lower-power state. This notification is the counterpart to the
  2112. + * display-off notification sent via ssam_ctrl_notif_display_off() and will
  2113. + * reverse its effects, including resetting events to their default behavior.
  2114. + *
  2115. + * This function will only send the display-on notification command if display
  2116. + * notifications are supported by the EC. Currently all known devices support
  2117. + * these notifications.
  2118. + *
  2119. + * See ssam_ctrl_notif_display_off() for more details.
  2120. + *
  2121. + * Return: Returns zero on success or if no request has been executed, the
  2122. + * status of the executed SAM request if that request failed, or %-EPROTO if
  2123. + * an unexpected response has been received.
  2124. + */
  2125. +int ssam_ctrl_notif_display_on(struct ssam_controller *ctrl)
  2126. +{
  2127. + int status;
  2128. + u8 response;
  2129. +
  2130. + ssam_dbg(ctrl, "pm: notifying display on\n");
  2131. +
  2132. + status = ssam_retry(ssam_ssh_notif_display_on, ctrl, &response);
  2133. + if (status)
  2134. + return status;
  2135. +
  2136. + if (response != 0) {
  2137. + ssam_err(ctrl, "unexpected response from display-on notification: %#04x\n",
  2138. + response);
  2139. + return -EPROTO;
  2140. + }
  2141. +
  2142. + return 0;
  2143. +}
  2144. +
  2145. +/**
  2146. + * ssam_ctrl_notif_d0_exit() - Notify EC that the driver/device exits the D0
  2147. + * power state.
  2148. + * @ctrl: The controller
  2149. + *
  2150. + * Notifies the EC that the driver prepares to exit the D0 power state in
  2151. + * favor of a lower-power state. Exact effects of this function related to the
  2152. + * EC are currently unknown.
  2153. + *
  2154. + * This function will only send the D0-exit notification command if D0-state
  2155. + * notifications are supported by the EC. Only newer Surface generations
  2156. + * support these notifications.
  2157. + *
  2158. + * Use ssam_ctrl_notif_d0_entry() to reverse the effects of this function.
  2159. + *
  2160. + * Return: Returns zero on success or if no request has been executed, the
  2161. + * status of the executed SAM request if that request failed, or %-EPROTO if
  2162. + * an unexpected response has been received.
  2163. + */
  2164. +int ssam_ctrl_notif_d0_exit(struct ssam_controller *ctrl)
  2165. +{
  2166. + int status;
  2167. + u8 response;
  2168. +
  2169. + if (!ctrl->caps.d3_closes_handle)
  2170. + return 0;
  2171. +
  2172. + ssam_dbg(ctrl, "pm: notifying D0 exit\n");
  2173. +
  2174. + status = ssam_retry(ssam_ssh_notif_d0_exit, ctrl, &response);
  2175. + if (status)
  2176. + return status;
  2177. +
  2178. + if (response != 0) {
  2179. + ssam_err(ctrl, "unexpected response from D0-exit notification: %#04x\n",
  2180. + response);
  2181. + return -EPROTO;
  2182. + }
  2183. +
  2184. + return 0;
  2185. +}
  2186. +
  2187. +/**
  2188. + * ssam_ctrl_notif_d0_entry() - Notify EC that the driver/device enters the D0
  2189. + * power state.
  2190. + * @ctrl: The controller
  2191. + *
  2192. + * Notifies the EC that the driver has exited a lower-power state and entered
  2193. + * the D0 power state. Exact effects of this function related to the EC are
  2194. + * currently unknown.
  2195. + *
  2196. + * This function will only send the D0-entry notification command if D0-state
  2197. + * notifications are supported by the EC. Only newer Surface generations
  2198. + * support these notifications.
  2199. + *
  2200. + * See ssam_ctrl_notif_d0_exit() for more details.
  2201. + *
  2202. + * Return: Returns zero on success or if no request has been executed, the
  2203. + * status of the executed SAM request if that request failed, or %-EPROTO if
  2204. + * an unexpected response has been received.
  2205. + */
  2206. +int ssam_ctrl_notif_d0_entry(struct ssam_controller *ctrl)
  2207. +{
  2208. + int status;
  2209. + u8 response;
  2210. +
  2211. + if (!ctrl->caps.d3_closes_handle)
  2212. + return 0;
  2213. +
  2214. + ssam_dbg(ctrl, "pm: notifying D0 entry\n");
  2215. +
  2216. + status = ssam_retry(ssam_ssh_notif_d0_entry, ctrl, &response);
  2217. + if (status)
  2218. + return status;
  2219. +
  2220. + if (response != 0) {
  2221. + ssam_err(ctrl, "unexpected response from D0-entry notification: %#04x\n",
  2222. + response);
  2223. + return -EPROTO;
  2224. + }
  2225. +
  2226. + return 0;
  2227. +}
  2228. +
  2229. +
  2230. +/* -- Top-level event registry interface. ----------------------------------- */
  2231. +
  2232. +/**
  2233. + * ssam_notifier_register() - Register an event notifier.
  2234. + * @ctrl: The controller to register the notifier on.
  2235. + * @n: The event notifier to register.
  2236. + *
  2237. + * Register an event notifier and increment the usage counter of the
  2238. + * associated SAM event. If the event was previously not enabled, it will be
  2239. + * enabled during this call.
  2240. + *
  2241. + * Return: Returns zero on success, %-ENOSPC if there have already been
  2242. + * %INT_MAX notifiers for the event ID/type associated with the notifier block
  2243. + * registered, %-ENOMEM if the corresponding event entry could not be
  2244. + * allocated. If this is the first time that a notifier block is registered
  2245. + * for the specific associated event, returns the status of the event-enable
  2246. + * EC-command.
  2247. + */
  2248. +int ssam_notifier_register(struct ssam_controller *ctrl,
  2249. + struct ssam_event_notifier *n)
  2250. +{
  2251. + u16 rqid = ssh_tc_to_rqid(n->event.id.target_category);
  2252. + struct ssam_nf_refcount_entry *entry;
  2253. + struct ssam_nf_head *nf_head;
  2254. + struct ssam_nf *nf;
  2255. + int status;
  2256. +
  2257. + if (!ssh_rqid_is_event(rqid))
  2258. + return -EINVAL;
  2259. +
  2260. + nf = &ctrl->cplt.event.notif;
  2261. + nf_head = &nf->head[ssh_rqid_to_event(rqid)];
  2262. +
  2263. + mutex_lock(&nf->lock);
  2264. +
  2265. + entry = ssam_nf_refcount_inc(nf, n->event.reg, n->event.id);
  2266. + if (IS_ERR(entry)) {
  2267. + mutex_unlock(&nf->lock);
  2268. + return PTR_ERR(entry);
  2269. + }
  2270. +
  2271. + ssam_dbg(ctrl, "enabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n",
  2272. + n->event.reg.target_category, n->event.id.target_category,
  2273. + n->event.id.instance, entry->refcount);
  2274. +
  2275. + status = ssam_nfblk_insert(nf_head, &n->base);
  2276. + if (status) {
  2277. + entry = ssam_nf_refcount_dec(nf, n->event.reg, n->event.id);
  2278. + if (entry->refcount == 0)
  2279. + kfree(entry);
  2280. +
  2281. + mutex_unlock(&nf->lock);
  2282. + return status;
  2283. + }
  2284. +
  2285. + if (entry->refcount == 1) {
  2286. + status = ssam_ssh_event_enable(ctrl, n->event.reg, n->event.id,
  2287. + n->event.flags);
  2288. + if (status) {
  2289. + ssam_nfblk_remove(&n->base);
  2290. + kfree(ssam_nf_refcount_dec(nf, n->event.reg, n->event.id));
  2291. + mutex_unlock(&nf->lock);
  2292. + synchronize_srcu(&nf_head->srcu);
  2293. + return status;
  2294. + }
  2295. +
  2296. + entry->flags = n->event.flags;
  2297. +
  2298. + } else if (entry->flags != n->event.flags) {
  2299. + ssam_warn(ctrl,
  2300. + "inconsistent flags when enabling event: got %#04x, expected %#04x (reg: %#04x, tc: %#04x, iid: %#04x)\n",
  2301. + n->event.flags, entry->flags, n->event.reg.target_category,
  2302. + n->event.id.target_category, n->event.id.instance);
  2303. + }
  2304. +
  2305. + mutex_unlock(&nf->lock);
  2306. + return 0;
  2307. +}
  2308. +EXPORT_SYMBOL_GPL(ssam_notifier_register);
  2309. +
  2310. +/**
  2311. + * ssam_notifier_unregister() - Unregister an event notifier.
  2312. + * @ctrl: The controller the notifier has been registered on.
  2313. + * @n: The event notifier to unregister.
  2314. + *
  2315. + * Unregister an event notifier and decrement the usage counter of the
  2316. + * associated SAM event. If the usage counter reaches zero, the event will be
  2317. + * disabled.
  2318. + *
  2319. + * Return: Returns zero on success, %-ENOENT if the given notifier block has
  2320. + * not been registered on the controller. If the given notifier block was the
  2321. + * last one associated with its specific event, returns the status of the
  2322. + * event-disable EC-command.
  2323. + */
  2324. +int ssam_notifier_unregister(struct ssam_controller *ctrl,
  2325. + struct ssam_event_notifier *n)
  2326. +{
  2327. + u16 rqid = ssh_tc_to_rqid(n->event.id.target_category);
  2328. + struct ssam_nf_refcount_entry *entry;
  2329. + struct ssam_nf_head *nf_head;
  2330. + struct ssam_nf *nf;
  2331. + int status = 0;
  2332. +
  2333. + if (!ssh_rqid_is_event(rqid))
  2334. + return -EINVAL;
  2335. +
  2336. + nf = &ctrl->cplt.event.notif;
  2337. + nf_head = &nf->head[ssh_rqid_to_event(rqid)];
  2338. +
  2339. + mutex_lock(&nf->lock);
  2340. +
  2341. + if (!ssam_nfblk_find(nf_head, &n->base)) {
  2342. + mutex_unlock(&nf->lock);
  2343. + return -ENOENT;
  2344. + }
  2345. +
  2346. + entry = ssam_nf_refcount_dec(nf, n->event.reg, n->event.id);
  2347. + if (WARN_ON(!entry)) {
  2348. + /*
  2349. + * If this does not return an entry, there's a logic error
  2350. + * somewhere: The notifier block is registered, but the event
  2351. + * refcount entry is not there. Remove the notifier block
  2352. + * anyways.
  2353. + */
  2354. + status = -ENOENT;
  2355. + goto remove;
  2356. + }
  2357. +
  2358. + ssam_dbg(ctrl, "disabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n",
  2359. + n->event.reg.target_category, n->event.id.target_category,
  2360. + n->event.id.instance, entry->refcount);
  2361. +
  2362. + if (entry->flags != n->event.flags) {
  2363. + ssam_warn(ctrl,
  2364. + "inconsistent flags when disabling event: got %#04x, expected %#04x (reg: %#04x, tc: %#04x, iid: %#04x)\n",
  2365. + n->event.flags, entry->flags, n->event.reg.target_category,
  2366. + n->event.id.target_category, n->event.id.instance);
  2367. + }
  2368. +
  2369. + if (entry->refcount == 0) {
  2370. + status = ssam_ssh_event_disable(ctrl, n->event.reg, n->event.id,
  2371. + n->event.flags);
  2372. + kfree(entry);
  2373. + }
  2374. +
  2375. +remove:
  2376. + ssam_nfblk_remove(&n->base);
  2377. + mutex_unlock(&nf->lock);
  2378. + synchronize_srcu(&nf_head->srcu);
  2379. +
  2380. + return status;
  2381. +}
  2382. +EXPORT_SYMBOL_GPL(ssam_notifier_unregister);
  2383. +
  2384. +/**
  2385. + * ssam_notifier_disable_registered() - Disable events for all registered
  2386. + * notifiers.
  2387. + * @ctrl: The controller for which to disable the notifiers/events.
  2388. + *
  2389. + * Disables events for all currently registered notifiers. In case of an error
  2390. + * (EC command failing), all previously disabled events will be restored and
  2391. + * the error code returned.
  2392. + *
  2393. + * This function is intended to disable all events prior to hibernation entry.
  2394. + * See ssam_notifier_restore_registered() to restore/re-enable all events
  2395. + * disabled with this function.
  2396. + *
  2397. + * Note that this function will not disable events for notifiers registered
  2398. + * after calling this function. It should thus be made sure that no new
  2399. + * notifiers are going to be added after this call and before the corresponding
  2400. + * call to ssam_notifier_restore_registered().
  2401. + *
  2402. + * Return: Returns zero on success. In case of failure returns the error code
  2403. + * returned by the failed EC command to disable an event.
  2404. + */
  2405. +int ssam_notifier_disable_registered(struct ssam_controller *ctrl)
  2406. +{
  2407. + struct ssam_nf *nf = &ctrl->cplt.event.notif;
  2408. + struct rb_node *n;
  2409. + int status;
  2410. +
  2411. + mutex_lock(&nf->lock);
  2412. + for (n = rb_first(&nf->refcount); n; n = rb_next(n)) {
  2413. + struct ssam_nf_refcount_entry *e;
  2414. +
  2415. + e = rb_entry(n, struct ssam_nf_refcount_entry, node);
  2416. + status = ssam_ssh_event_disable(ctrl, e->key.reg,
  2417. + e->key.id, e->flags);
  2418. + if (status)
  2419. + goto err;
  2420. + }
  2421. + mutex_unlock(&nf->lock);
  2422. +
  2423. + return 0;
  2424. +
  2425. +err:
  2426. + for (n = rb_prev(n); n; n = rb_prev(n)) {
  2427. + struct ssam_nf_refcount_entry *e;
  2428. +
  2429. + e = rb_entry(n, struct ssam_nf_refcount_entry, node);
  2430. + ssam_ssh_event_enable(ctrl, e->key.reg, e->key.id, e->flags);
  2431. + }
  2432. + mutex_unlock(&nf->lock);
  2433. +
  2434. + return status;
  2435. +}
  2436. +
  2437. +/**
  2438. + * ssam_notifier_restore_registered() - Restore/re-enable events for all
  2439. + * registered notifiers.
  2440. + * @ctrl: The controller for which to restore the notifiers/events.
  2441. + *
  2442. + * Restores/re-enables all events for which notifiers have been registered on
  2443. + * the given controller. In case of a failure, the error is logged and the
  2444. + * function continues to try and enable the remaining events.
  2445. + *
  2446. + * This function is intended to restore/re-enable all registered events after
  2447. + * hibernation. See ssam_notifier_disable_registered() for the counter part
  2448. + * disabling the events and more details.
  2449. + */
  2450. +void ssam_notifier_restore_registered(struct ssam_controller *ctrl)
  2451. +{
  2452. + struct ssam_nf *nf = &ctrl->cplt.event.notif;
  2453. + struct rb_node *n;
  2454. +
  2455. + mutex_lock(&nf->lock);
  2456. + for (n = rb_first(&nf->refcount); n; n = rb_next(n)) {
  2457. + struct ssam_nf_refcount_entry *e;
  2458. +
  2459. + e = rb_entry(n, struct ssam_nf_refcount_entry, node);
  2460. +
  2461. + /* Ignore errors, will get logged in call. */
  2462. + ssam_ssh_event_enable(ctrl, e->key.reg, e->key.id, e->flags);
  2463. + }
  2464. + mutex_unlock(&nf->lock);
  2465. +}
  2466. +
  2467. +/**
  2468. + * ssam_notifier_is_empty() - Check if there are any registered notifiers.
  2469. + * @ctrl: The controller to check on.
  2470. + *
  2471. + * Return: Returns %true if there are currently no notifiers registered on the
  2472. + * controller, %false otherwise.
  2473. + */
  2474. +static bool ssam_notifier_is_empty(struct ssam_controller *ctrl)
  2475. +{
  2476. + struct ssam_nf *nf = &ctrl->cplt.event.notif;
  2477. + bool result;
  2478. +
  2479. + mutex_lock(&nf->lock);
  2480. + result = ssam_nf_refcount_empty(nf);
  2481. + mutex_unlock(&nf->lock);
  2482. +
  2483. + return result;
  2484. +}
  2485. +
  2486. +/**
  2487. + * ssam_notifier_unregister_all() - Unregister all currently registered
  2488. + * notifiers.
  2489. + * @ctrl: The controller to unregister the notifiers on.
  2490. + *
  2491. + * Unregisters all currently registered notifiers. This function is used to
  2492. + * ensure that all notifiers will be unregistered and associated
  2493. + * entries/resources freed when the controller is being shut down.
  2494. + */
  2495. +static void ssam_notifier_unregister_all(struct ssam_controller *ctrl)
  2496. +{
  2497. + struct ssam_nf *nf = &ctrl->cplt.event.notif;
  2498. + struct ssam_nf_refcount_entry *e, *n;
  2499. +
  2500. + mutex_lock(&nf->lock);
  2501. + rbtree_postorder_for_each_entry_safe(e, n, &nf->refcount, node) {
  2502. + /* Ignore errors, will get logged in call. */
  2503. + ssam_ssh_event_disable(ctrl, e->key.reg, e->key.id, e->flags);
  2504. + kfree(e);
  2505. + }
  2506. + nf->refcount = RB_ROOT;
  2507. + mutex_unlock(&nf->lock);
  2508. +}
  2509. +
  2510. +
  2511. +/* -- Wakeup IRQ. ----------------------------------------------------------- */
  2512. +
  2513. +static irqreturn_t ssam_irq_handle(int irq, void *dev_id)
  2514. +{
  2515. + struct ssam_controller *ctrl = dev_id;
  2516. +
  2517. + ssam_dbg(ctrl, "pm: wake irq triggered\n");
  2518. +
  2519. + /*
  2520. + * Note: Proper wakeup detection is currently unimplemented.
  2521. + * When the EC is in display-off or any other non-D0 state, it
  2522. + * does not send events/notifications to the host. Instead it
  2523. + * signals that there are events available via the wakeup IRQ.
  2524. + * This driver is responsible for calling back to the EC to
  2525. + * release these events one-by-one.
  2526. + *
  2527. + * This IRQ should not cause a full system resume by its own.
  2528. + * Instead, events should be handled by their respective subsystem
  2529. + * drivers, which in turn should signal whether a full system
  2530. + * resume should be performed.
  2531. + *
  2532. + * TODO: Send GPIO callback command repeatedly to EC until callback
  2533. + * returns 0x00. Return flag of callback is "has more events".
  2534. + * Each time the command is sent, one event is "released". Once
  2535. + * all events have been released (return = 0x00), the GPIO is
  2536. + * re-armed. Detect wakeup events during this process, go back to
  2537. + * sleep if no wakeup event has been received.
  2538. + */
  2539. +
  2540. + return IRQ_HANDLED;
  2541. +}
  2542. +
  2543. +/**
  2544. + * ssam_irq_setup() - Set up SAM EC wakeup-GPIO interrupt.
  2545. + * @ctrl: The controller for which the IRQ should be set up.
  2546. + *
  2547. + * Set up an IRQ for the wakeup-GPIO pin of the SAM EC. This IRQ can be used
  2548. + * to wake the device from a low power state.
  2549. + *
  2550. + * Note that this IRQ can only be triggered while the EC is in the display-off
  2551. + * state. In this state, events are not sent to the host in the usual way.
  2552. + * Instead the wakeup-GPIO gets pulled to "high" as long as there are pending
  2553. + * events and these events need to be released one-by-one via the GPIO
  2554. + * callback request, either until there are no events left and the GPIO is
  2555. + * reset, or all at once by transitioning the EC out of the display-off state,
  2556. + * which will also clear the GPIO.
  2557. + *
  2558. + * Not all events, however, should trigger a full system wakeup. Instead the
  2559. + * driver should, if necessary, inspect and forward each event to the
  2560. + * corresponding subsystem, which in turn should decide if the system needs to
  2561. + * be woken up. This logic has not been implemented yet, thus wakeup by this
  2562. + * IRQ should be disabled by default to avoid spurious wake-ups, caused, for
  2563. + * example, by the remaining battery percentage changing. Refer to comments in
  2564. + * this function and comments in the corresponding IRQ handler for more
  2565. + * details on how this should be implemented.
  2566. + *
  2567. + * See also ssam_ctrl_notif_display_off() and ssam_ctrl_notif_display_off()
  2568. + * for functions to transition the EC into and out of the display-off state as
  2569. + * well as more details on it.
  2570. + *
  2571. + * The IRQ is disabled by default and has to be enabled before it can wake up
  2572. + * the device from suspend via ssam_irq_arm_for_wakeup(). On teardown, the IRQ
  2573. + * should be freed via ssam_irq_free().
  2574. + */
  2575. +int ssam_irq_setup(struct ssam_controller *ctrl)
  2576. +{
  2577. + struct device *dev = ssam_controller_device(ctrl);
  2578. + struct gpio_desc *gpiod;
  2579. + int irq;
  2580. + int status;
  2581. +
  2582. + /*
  2583. + * The actual GPIO interrupt is declared in ACPI as TRIGGER_HIGH.
  2584. + * However, the GPIO line only gets reset by sending the GPIO callback
  2585. + * command to SAM (or alternatively the display-on notification). As
  2586. + * proper handling for this interrupt is not implemented yet, leaving
  2587. + * the IRQ at TRIGGER_HIGH would cause an IRQ storm (as the callback
  2588. + * never gets sent and thus the line never gets reset). To avoid this,
  2589. + * mark the IRQ as TRIGGER_RISING for now, only creating a single
  2590. + * interrupt, and let the SAM resume callback during the controller
  2591. + * resume process clear it.
  2592. + */
  2593. + const int irqf = IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_RISING;
  2594. +
  2595. + gpiod = gpiod_get(dev, "ssam_wakeup-int", GPIOD_ASIS);
  2596. + if (IS_ERR(gpiod))
  2597. + return PTR_ERR(gpiod);
  2598. +
  2599. + irq = gpiod_to_irq(gpiod);
  2600. + gpiod_put(gpiod);
  2601. +
  2602. + if (irq < 0)
  2603. + return irq;
  2604. +
  2605. + status = request_threaded_irq(irq, NULL, ssam_irq_handle, irqf,
  2606. + "ssam_wakeup", ctrl);
  2607. + if (status)
  2608. + return status;
  2609. +
  2610. + ctrl->irq.num = irq;
  2611. + disable_irq(ctrl->irq.num);
  2612. + return 0;
  2613. +}
  2614. +
  2615. +/**
  2616. + * ssam_irq_free() - Free SAM EC wakeup-GPIO interrupt.
  2617. + * @ctrl: The controller for which the IRQ should be freed.
  2618. + *
  2619. + * Free the wakeup-GPIO IRQ previously set-up via ssam_irq_setup().
  2620. + */
  2621. +void ssam_irq_free(struct ssam_controller *ctrl)
  2622. +{
  2623. + free_irq(ctrl->irq.num, ctrl);
  2624. + ctrl->irq.num = -1;
  2625. +}
  2626. +
  2627. +/**
  2628. + * ssam_irq_arm_for_wakeup() - Arm the EC IRQ for wakeup, if enabled.
  2629. + * @ctrl: The controller for which the IRQ should be armed.
  2630. + *
  2631. + * Sets up the IRQ so that it can be used to wake the device. Specifically,
  2632. + * this function enables the irq and then, if the device is allowed to wake up
  2633. + * the system, calls enable_irq_wake(). See ssam_irq_disarm_wakeup() for the
  2634. + * corresponding function to disable the IRQ.
  2635. + *
  2636. + * This function is intended to arm the IRQ before entering S2idle suspend.
  2637. + *
  2638. + * Note: calls to ssam_irq_arm_for_wakeup() and ssam_irq_disarm_wakeup() must
  2639. + * be balanced.
  2640. + */
  2641. +int ssam_irq_arm_for_wakeup(struct ssam_controller *ctrl)
  2642. +{
  2643. + struct device *dev = ssam_controller_device(ctrl);
  2644. + int status;
  2645. +
  2646. + enable_irq(ctrl->irq.num);
  2647. + if (device_may_wakeup(dev)) {
  2648. + status = enable_irq_wake(ctrl->irq.num);
  2649. + if (status) {
  2650. + ssam_err(ctrl, "failed to enable wake IRQ: %d\n", status);
  2651. + disable_irq(ctrl->irq.num);
  2652. + return status;
  2653. + }
  2654. +
  2655. + ctrl->irq.wakeup_enabled = true;
  2656. + } else {
  2657. + ctrl->irq.wakeup_enabled = false;
  2658. + }
  2659. +
  2660. + return 0;
  2661. +}
  2662. +
  2663. +/**
  2664. + * ssam_irq_disarm_wakeup() - Disarm the wakeup IRQ.
  2665. + * @ctrl: The controller for which the IRQ should be disarmed.
  2666. + *
  2667. + * Disarm the IRQ previously set up for wake via ssam_irq_arm_for_wakeup().
  2668. + *
  2669. + * This function is intended to disarm the IRQ after exiting S2idle suspend.
  2670. + *
  2671. + * Note: calls to ssam_irq_arm_for_wakeup() and ssam_irq_disarm_wakeup() must
  2672. + * be balanced.
  2673. + */
  2674. +void ssam_irq_disarm_wakeup(struct ssam_controller *ctrl)
  2675. +{
  2676. + int status;
  2677. +
  2678. + if (ctrl->irq.wakeup_enabled) {
  2679. + status = disable_irq_wake(ctrl->irq.num);
  2680. + if (status)
  2681. + ssam_err(ctrl, "failed to disable wake IRQ: %d\n", status);
  2682. +
  2683. + ctrl->irq.wakeup_enabled = false;
  2684. + }
  2685. + disable_irq(ctrl->irq.num);
  2686. +}
  2687. diff --git a/drivers/platform/surface/aggregator/controller.h b/drivers/platform/surface/aggregator/controller.h
  2688. new file mode 100644
  2689. index 000000000000..5ee9e966f1d7
  2690. --- /dev/null
  2691. +++ b/drivers/platform/surface/aggregator/controller.h
  2692. @@ -0,0 +1,276 @@
  2693. +/* SPDX-License-Identifier: GPL-2.0+ */
  2694. +/*
  2695. + * Main SSAM/SSH controller structure and functionality.
  2696. + *
  2697. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  2698. + */
  2699. +
  2700. +#ifndef _SURFACE_AGGREGATOR_CONTROLLER_H
  2701. +#define _SURFACE_AGGREGATOR_CONTROLLER_H
  2702. +
  2703. +#include <linux/kref.h>
  2704. +#include <linux/list.h>
  2705. +#include <linux/mutex.h>
  2706. +#include <linux/rbtree.h>
  2707. +#include <linux/rwsem.h>
  2708. +#include <linux/serdev.h>
  2709. +#include <linux/spinlock.h>
  2710. +#include <linux/srcu.h>
  2711. +#include <linux/types.h>
  2712. +#include <linux/workqueue.h>
  2713. +
  2714. +#include <linux/surface_aggregator/controller.h>
  2715. +#include <linux/surface_aggregator/serial_hub.h>
  2716. +
  2717. +#include "ssh_request_layer.h"
  2718. +
  2719. +
  2720. +/* -- Safe counters. -------------------------------------------------------- */
  2721. +
  2722. +/**
  2723. + * struct ssh_seq_counter - Safe counter for SSH sequence IDs.
  2724. + * @value: The current counter value.
  2725. + */
  2726. +struct ssh_seq_counter {
  2727. + u8 value;
  2728. +};
  2729. +
  2730. +/**
  2731. + * struct ssh_rqid_counter - Safe counter for SSH request IDs.
  2732. + * @value: The current counter value.
  2733. + */
  2734. +struct ssh_rqid_counter {
  2735. + u16 value;
  2736. +};
  2737. +
  2738. +
  2739. +/* -- Event/notification system. -------------------------------------------- */
  2740. +
  2741. +/**
  2742. + * struct ssam_nf_head - Notifier head for SSAM events.
  2743. + * @srcu: The SRCU struct for synchronization.
  2744. + * @head: List-head for notifier blocks registered under this head.
  2745. + */
  2746. +struct ssam_nf_head {
  2747. + struct srcu_struct srcu;
  2748. + struct list_head head;
  2749. +};
  2750. +
  2751. +/**
  2752. + * struct ssam_nf - Notifier callback- and activation-registry for SSAM events.
  2753. + * @lock: Lock guarding (de-)registration of notifier blocks. Note: This
  2754. + * lock does not need to be held for notifier calls, only
  2755. + * registration and deregistration.
  2756. + * @refcount: The root of the RB-tree used for reference-counting enabled
  2757. + * events/notifications.
  2758. + * @head: The list of notifier heads for event/notification callbacks.
  2759. + */
  2760. +struct ssam_nf {
  2761. + struct mutex lock;
  2762. + struct rb_root refcount;
  2763. + struct ssam_nf_head head[SSH_NUM_EVENTS];
  2764. +};
  2765. +
  2766. +
  2767. +/* -- Event/async request completion system. -------------------------------- */
  2768. +
  2769. +struct ssam_cplt;
  2770. +
  2771. +/**
  2772. + * struct ssam_event_item - Struct for event queuing and completion.
  2773. + * @node: The node in the queue.
  2774. + * @rqid: The request ID of the event.
  2775. + * @event: Actual event data.
  2776. + */
  2777. +struct ssam_event_item {
  2778. + struct list_head node;
  2779. + u16 rqid;
  2780. +
  2781. + struct ssam_event event; /* must be last */
  2782. +};
  2783. +
  2784. +/**
  2785. + * struct ssam_event_queue - Queue for completing received events.
  2786. + * @cplt: Reference to the completion system on which this queue is active.
  2787. + * @lock: The lock for any operation on the queue.
  2788. + * @head: The list-head of the queue.
  2789. + * @work: The &struct work_struct performing completion work for this queue.
  2790. + */
  2791. +struct ssam_event_queue {
  2792. + struct ssam_cplt *cplt;
  2793. +
  2794. + spinlock_t lock;
  2795. + struct list_head head;
  2796. + struct work_struct work;
  2797. +};
  2798. +
  2799. +/**
  2800. + * struct ssam_event_target - Set of queues for a single SSH target ID.
  2801. + * @queue: The array of queues, one queue per event ID.
  2802. + */
  2803. +struct ssam_event_target {
  2804. + struct ssam_event_queue queue[SSH_NUM_EVENTS];
  2805. +};
  2806. +
  2807. +/**
  2808. + * struct ssam_cplt - SSAM event/async request completion system.
  2809. + * @dev: The device with which this system is associated. Only used
  2810. + * for logging.
  2811. + * @wq: The &struct workqueue_struct on which all completion work
  2812. + * items are queued.
  2813. + * @event: Event completion management.
  2814. + * @event.target: Array of &struct ssam_event_target, one for each target.
  2815. + * @event.notif: Notifier callbacks and event activation reference counting.
  2816. + */
  2817. +struct ssam_cplt {
  2818. + struct device *dev;
  2819. + struct workqueue_struct *wq;
  2820. +
  2821. + struct {
  2822. + struct ssam_event_target target[SSH_NUM_TARGETS];
  2823. + struct ssam_nf notif;
  2824. + } event;
  2825. +};
  2826. +
  2827. +
  2828. +/* -- Main SSAM device structures. ------------------------------------------ */
  2829. +
  2830. +/**
  2831. + * enum ssam_controller_state - State values for &struct ssam_controller.
  2832. + * @SSAM_CONTROLLER_UNINITIALIZED:
  2833. + * The controller has not been initialized yet or has been deinitialized.
  2834. + * @SSAM_CONTROLLER_INITIALIZED:
  2835. + * The controller is initialized, but has not been started yet.
  2836. + * @SSAM_CONTROLLER_STARTED:
  2837. + * The controller has been started and is ready to use.
  2838. + * @SSAM_CONTROLLER_STOPPED:
  2839. + * The controller has been stopped.
  2840. + * @SSAM_CONTROLLER_SUSPENDED:
  2841. + * The controller has been suspended.
  2842. + */
  2843. +enum ssam_controller_state {
  2844. + SSAM_CONTROLLER_UNINITIALIZED,
  2845. + SSAM_CONTROLLER_INITIALIZED,
  2846. + SSAM_CONTROLLER_STARTED,
  2847. + SSAM_CONTROLLER_STOPPED,
  2848. + SSAM_CONTROLLER_SUSPENDED,
  2849. +};
  2850. +
  2851. +/**
  2852. + * struct ssam_controller_caps - Controller device capabilities.
  2853. + * @ssh_power_profile: SSH power profile.
  2854. + * @ssh_buffer_size: SSH driver UART buffer size.
  2855. + * @screen_on_sleep_idle_timeout: SAM UART screen-on sleep idle timeout.
  2856. + * @screen_off_sleep_idle_timeout: SAM UART screen-off sleep idle timeout.
  2857. + * @d3_closes_handle: SAM closes UART handle in D3.
  2858. + *
  2859. + * Controller and SSH device capabilities found in ACPI.
  2860. + */
  2861. +struct ssam_controller_caps {
  2862. + u32 ssh_power_profile;
  2863. + u32 ssh_buffer_size;
  2864. + u32 screen_on_sleep_idle_timeout;
  2865. + u32 screen_off_sleep_idle_timeout;
  2866. + u32 d3_closes_handle:1;
  2867. +};
  2868. +
  2869. +/**
  2870. + * struct ssam_controller - SSAM controller device.
  2871. + * @kref: Reference count of the controller.
  2872. + * @lock: Main lock for the controller, used to guard state changes.
  2873. + * @state: Controller state.
  2874. + * @rtl: Request transport layer for SSH I/O.
  2875. + * @cplt: Completion system for SSH/SSAM events and asynchronous requests.
  2876. + * @counter: Safe SSH message ID counters.
  2877. + * @counter.seq: Sequence ID counter.
  2878. + * @counter.rqid: Request ID counter.
  2879. + * @irq: Wakeup IRQ resources.
  2880. + * @irq.num: The wakeup IRQ number.
  2881. + * @irq.wakeup_enabled: Whether wakeup by IRQ is enabled during suspend.
  2882. + * @caps: The controller device capabilities.
  2883. + */
  2884. +struct ssam_controller {
  2885. + struct kref kref;
  2886. +
  2887. + struct rw_semaphore lock;
  2888. + enum ssam_controller_state state;
  2889. +
  2890. + struct ssh_rtl rtl;
  2891. + struct ssam_cplt cplt;
  2892. +
  2893. + struct {
  2894. + struct ssh_seq_counter seq;
  2895. + struct ssh_rqid_counter rqid;
  2896. + } counter;
  2897. +
  2898. + struct {
  2899. + int num;
  2900. + bool wakeup_enabled;
  2901. + } irq;
  2902. +
  2903. + struct ssam_controller_caps caps;
  2904. +};
  2905. +
  2906. +#define to_ssam_controller(ptr, member) \
  2907. + container_of(ptr, struct ssam_controller, member)
  2908. +
  2909. +#define ssam_dbg(ctrl, fmt, ...) rtl_dbg(&(ctrl)->rtl, fmt, ##__VA_ARGS__)
  2910. +#define ssam_info(ctrl, fmt, ...) rtl_info(&(ctrl)->rtl, fmt, ##__VA_ARGS__)
  2911. +#define ssam_warn(ctrl, fmt, ...) rtl_warn(&(ctrl)->rtl, fmt, ##__VA_ARGS__)
  2912. +#define ssam_err(ctrl, fmt, ...) rtl_err(&(ctrl)->rtl, fmt, ##__VA_ARGS__)
  2913. +
  2914. +/**
  2915. + * ssam_controller_receive_buf() - Provide input-data to the controller.
  2916. + * @ctrl: The controller.
  2917. + * @buf: The input buffer.
  2918. + * @n: The number of bytes in the input buffer.
  2919. + *
  2920. + * Provide input data to be evaluated by the controller, which has been
  2921. + * received via the lower-level transport.
  2922. + *
  2923. + * Return: Returns the number of bytes consumed, or, if the packet transport
  2924. + * layer of the controller has been shut down, %-ESHUTDOWN.
  2925. + */
  2926. +static inline
  2927. +int ssam_controller_receive_buf(struct ssam_controller *ctrl,
  2928. + const unsigned char *buf, size_t n)
  2929. +{
  2930. + return ssh_ptl_rx_rcvbuf(&ctrl->rtl.ptl, buf, n);
  2931. +}
  2932. +
  2933. +/**
  2934. + * ssam_controller_write_wakeup() - Notify the controller that the underlying
  2935. + * device has space available for data to be written.
  2936. + * @ctrl: The controller.
  2937. + */
  2938. +static inline void ssam_controller_write_wakeup(struct ssam_controller *ctrl)
  2939. +{
  2940. + ssh_ptl_tx_wakeup_transfer(&ctrl->rtl.ptl);
  2941. +}
  2942. +
  2943. +int ssam_controller_init(struct ssam_controller *ctrl, struct serdev_device *s);
  2944. +int ssam_controller_start(struct ssam_controller *ctrl);
  2945. +void ssam_controller_shutdown(struct ssam_controller *ctrl);
  2946. +void ssam_controller_destroy(struct ssam_controller *ctrl);
  2947. +
  2948. +int ssam_notifier_disable_registered(struct ssam_controller *ctrl);
  2949. +void ssam_notifier_restore_registered(struct ssam_controller *ctrl);
  2950. +
  2951. +int ssam_irq_setup(struct ssam_controller *ctrl);
  2952. +void ssam_irq_free(struct ssam_controller *ctrl);
  2953. +int ssam_irq_arm_for_wakeup(struct ssam_controller *ctrl);
  2954. +void ssam_irq_disarm_wakeup(struct ssam_controller *ctrl);
  2955. +
  2956. +void ssam_controller_lock(struct ssam_controller *c);
  2957. +void ssam_controller_unlock(struct ssam_controller *c);
  2958. +
  2959. +int ssam_get_firmware_version(struct ssam_controller *ctrl, u32 *version);
  2960. +int ssam_ctrl_notif_display_off(struct ssam_controller *ctrl);
  2961. +int ssam_ctrl_notif_display_on(struct ssam_controller *ctrl);
  2962. +int ssam_ctrl_notif_d0_exit(struct ssam_controller *ctrl);
  2963. +int ssam_ctrl_notif_d0_entry(struct ssam_controller *ctrl);
  2964. +
  2965. +int ssam_controller_suspend(struct ssam_controller *ctrl);
  2966. +int ssam_controller_resume(struct ssam_controller *ctrl);
  2967. +
  2968. +#endif /* _SURFACE_AGGREGATOR_CONTROLLER_H */
  2969. diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
  2970. new file mode 100644
  2971. index 000000000000..18e0e9e34e7b
  2972. --- /dev/null
  2973. +++ b/drivers/platform/surface/aggregator/core.c
  2974. @@ -0,0 +1,787 @@
  2975. +// SPDX-License-Identifier: GPL-2.0+
  2976. +/*
  2977. + * Surface Serial Hub (SSH) driver for communication with the Surface/System
  2978. + * Aggregator Module (SSAM/SAM).
  2979. + *
  2980. + * Provides access to a SAM-over-SSH connected EC via a controller device.
  2981. + * Handles communication via requests as well as enabling, disabling, and
  2982. + * relaying of events.
  2983. + *
  2984. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  2985. + */
  2986. +
  2987. +#include <linux/acpi.h>
  2988. +#include <linux/atomic.h>
  2989. +#include <linux/completion.h>
  2990. +#include <linux/gpio/consumer.h>
  2991. +#include <linux/kernel.h>
  2992. +#include <linux/kref.h>
  2993. +#include <linux/module.h>
  2994. +#include <linux/pm.h>
  2995. +#include <linux/serdev.h>
  2996. +#include <linux/sysfs.h>
  2997. +
  2998. +#include <linux/surface_aggregator/controller.h>
  2999. +#include "controller.h"
  3000. +
  3001. +
  3002. +/* -- Static controller reference. ------------------------------------------ */
  3003. +
  3004. +/*
  3005. + * Main controller reference. The corresponding lock must be held while
  3006. + * accessing (reading/writing) the reference.
  3007. + */
  3008. +static struct ssam_controller *__ssam_controller;
  3009. +static DEFINE_SPINLOCK(__ssam_controller_lock);
  3010. +
  3011. +/**
  3012. + * ssam_get_controller() - Get reference to SSAM controller.
  3013. + *
  3014. + * Returns a reference to the SSAM controller of the system or %NULL if there
  3015. + * is none, it hasn't been set up yet, or it has already been unregistered.
  3016. + * This function automatically increments the reference count of the
  3017. + * controller, thus the calling party must ensure that ssam_controller_put()
  3018. + * is called when it doesn't need the controller any more.
  3019. + */
  3020. +struct ssam_controller *ssam_get_controller(void)
  3021. +{
  3022. + struct ssam_controller *ctrl;
  3023. +
  3024. + spin_lock(&__ssam_controller_lock);
  3025. +
  3026. + ctrl = __ssam_controller;
  3027. + if (!ctrl)
  3028. + goto out;
  3029. +
  3030. + if (WARN_ON(!kref_get_unless_zero(&ctrl->kref)))
  3031. + ctrl = NULL;
  3032. +
  3033. +out:
  3034. + spin_unlock(&__ssam_controller_lock);
  3035. + return ctrl;
  3036. +}
  3037. +EXPORT_SYMBOL_GPL(ssam_get_controller);
  3038. +
  3039. +/**
  3040. + * ssam_try_set_controller() - Try to set the main controller reference.
  3041. + * @ctrl: The controller to which the reference should point.
  3042. + *
  3043. + * Set the main controller reference to the given pointer if the reference
  3044. + * hasn't been set already.
  3045. + *
  3046. + * Return: Returns zero on success or %-EEXIST if the reference has already
  3047. + * been set.
  3048. + */
  3049. +static int ssam_try_set_controller(struct ssam_controller *ctrl)
  3050. +{
  3051. + int status = 0;
  3052. +
  3053. + spin_lock(&__ssam_controller_lock);
  3054. + if (!__ssam_controller)
  3055. + __ssam_controller = ctrl;
  3056. + else
  3057. + status = -EEXIST;
  3058. + spin_unlock(&__ssam_controller_lock);
  3059. +
  3060. + return status;
  3061. +}
  3062. +
  3063. +/**
  3064. + * ssam_clear_controller() - Remove/clear the main controller reference.
  3065. + *
  3066. + * Clears the main controller reference, i.e. sets it to %NULL. This function
  3067. + * should be called before the controller is shut down.
  3068. + */
  3069. +static void ssam_clear_controller(void)
  3070. +{
  3071. + spin_lock(&__ssam_controller_lock);
  3072. + __ssam_controller = NULL;
  3073. + spin_unlock(&__ssam_controller_lock);
  3074. +}
  3075. +
  3076. +/**
  3077. + * ssam_client_link() - Link an arbitrary client device to the controller.
  3078. + * @c: The controller to link to.
  3079. + * @client: The client device.
  3080. + *
  3081. + * Link an arbitrary client device to the controller by creating a device link
  3082. + * between it as consumer and the controller device as provider. This function
  3083. + * can be used for non-SSAM devices (or SSAM devices not registered as child
  3084. + * under the controller) to guarantee that the controller is valid for as long
  3085. + * as the driver of the client device is bound, and that proper suspend and
  3086. + * resume ordering is guaranteed.
  3087. + *
  3088. + * The device link does not have to be destructed manually. It is removed
  3089. + * automatically once the driver of the client device unbinds.
  3090. + *
  3091. + * Return: Returns zero on success, %-ENODEV if the controller is not ready or
  3092. + * going to be removed soon, or %-ENOMEM if the device link could not be
  3093. + * created for other reasons.
  3094. + */
  3095. +int ssam_client_link(struct ssam_controller *c, struct device *client)
  3096. +{
  3097. + const u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_CONSUMER;
  3098. + struct device_link *link;
  3099. + struct device *ctrldev;
  3100. +
  3101. + ssam_controller_statelock(c);
  3102. +
  3103. + if (c->state != SSAM_CONTROLLER_STARTED) {
  3104. + ssam_controller_stateunlock(c);
  3105. + return -ENODEV;
  3106. + }
  3107. +
  3108. + ctrldev = ssam_controller_device(c);
  3109. + if (!ctrldev) {
  3110. + ssam_controller_stateunlock(c);
  3111. + return -ENODEV;
  3112. + }
  3113. +
  3114. + link = device_link_add(client, ctrldev, flags);
  3115. + if (!link) {
  3116. + ssam_controller_stateunlock(c);
  3117. + return -ENOMEM;
  3118. + }
  3119. +
  3120. + /*
  3121. + * Return -ENODEV if supplier driver is on its way to be removed. In
  3122. + * this case, the controller won't be around for much longer and the
  3123. + * device link is not going to save us any more, as unbinding is
  3124. + * already in progress.
  3125. + */
  3126. + if (READ_ONCE(link->status) == DL_STATE_SUPPLIER_UNBIND) {
  3127. + ssam_controller_stateunlock(c);
  3128. + return -ENODEV;
  3129. + }
  3130. +
  3131. + ssam_controller_stateunlock(c);
  3132. + return 0;
  3133. +}
  3134. +EXPORT_SYMBOL_GPL(ssam_client_link);
  3135. +
  3136. +/**
  3137. + * ssam_client_bind() - Bind an arbitrary client device to the controller.
  3138. + * @client: The client device.
  3139. + *
  3140. + * Link an arbitrary client device to the controller by creating a device link
  3141. + * between it as consumer and the main controller device as provider. This
  3142. + * function can be used for non-SSAM devices to guarantee that the controller
  3143. + * returned by this function is valid for as long as the driver of the client
  3144. + * device is bound, and that proper suspend and resume ordering is guaranteed.
  3145. + *
  3146. + * This function does essentially the same as ssam_client_link(), except that
  3147. + * it first fetches the main controller reference, then creates the link, and
  3148. + * finally returns this reference. Note that this function does not increment
  3149. + * the reference counter of the controller, as, due to the link, the
  3150. + * controller lifetime is assured as long as the driver of the client device
  3151. + * is bound.
  3152. + *
  3153. + * It is not valid to use the controller reference obtained by this method
  3154. + * outside of the driver bound to the client device at the time of calling
  3155. + * this function, without first incrementing the reference count of the
  3156. + * controller via ssam_controller_get(). Even after doing this, care must be
  3157. + * taken that requests are only submitted and notifiers are only
  3158. + * (un-)registered when the controller is active and not suspended. In other
  3159. + * words: The device link only lives as long as the client driver is bound and
  3160. + * any guarantees enforced by this link (e.g. active controller state) can
  3161. + * only be relied upon as long as this link exists and may need to be enforced
  3162. + * in other ways afterwards.
  3163. + *
  3164. + * The created device link does not have to be destructed manually. It is
  3165. + * removed automatically once the driver of the client device unbinds.
  3166. + *
  3167. + * Return: Returns the controller on success, an error pointer with %-ENODEV
  3168. + * if the controller is not present, not ready or going to be removed soon, or
  3169. + * %-ENOMEM if the device link could not be created for other reasons.
  3170. + */
  3171. +struct ssam_controller *ssam_client_bind(struct device *client)
  3172. +{
  3173. + struct ssam_controller *c;
  3174. + int status;
  3175. +
  3176. + c = ssam_get_controller();
  3177. + if (!c)
  3178. + return ERR_PTR(-ENODEV);
  3179. +
  3180. + status = ssam_client_link(c, client);
  3181. +
  3182. + /*
  3183. + * Note that we can drop our controller reference in both success and
  3184. + * failure cases: On success, we have bound the controller lifetime
  3185. + * inherently to the client driver lifetime, i.e. it the controller is
  3186. + * now guaranteed to outlive the client driver. On failure, we're not
  3187. + * going to use the controller any more.
  3188. + */
  3189. + ssam_controller_put(c);
  3190. +
  3191. + return status >= 0 ? c : ERR_PTR(status);
  3192. +}
  3193. +EXPORT_SYMBOL_GPL(ssam_client_bind);
  3194. +
  3195. +
  3196. +/* -- Glue layer (serdev_device -> ssam_controller). ------------------------ */
  3197. +
  3198. +static int ssam_receive_buf(struct serdev_device *dev, const unsigned char *buf,
  3199. + size_t n)
  3200. +{
  3201. + struct ssam_controller *ctrl;
  3202. +
  3203. + ctrl = serdev_device_get_drvdata(dev);
  3204. + return ssam_controller_receive_buf(ctrl, buf, n);
  3205. +}
  3206. +
  3207. +static void ssam_write_wakeup(struct serdev_device *dev)
  3208. +{
  3209. + ssam_controller_write_wakeup(serdev_device_get_drvdata(dev));
  3210. +}
  3211. +
  3212. +static const struct serdev_device_ops ssam_serdev_ops = {
  3213. + .receive_buf = ssam_receive_buf,
  3214. + .write_wakeup = ssam_write_wakeup,
  3215. +};
  3216. +
  3217. +
  3218. +/* -- SysFS and misc. ------------------------------------------------------- */
  3219. +
  3220. +static int ssam_log_firmware_version(struct ssam_controller *ctrl)
  3221. +{
  3222. + u32 version, a, b, c;
  3223. + int status;
  3224. +
  3225. + status = ssam_get_firmware_version(ctrl, &version);
  3226. + if (status)
  3227. + return status;
  3228. +
  3229. + a = (version >> 24) & 0xff;
  3230. + b = ((version >> 8) & 0xffff);
  3231. + c = version & 0xff;
  3232. +
  3233. + ssam_info(ctrl, "SAM firmware version: %u.%u.%u\n", a, b, c);
  3234. + return 0;
  3235. +}
  3236. +
  3237. +static ssize_t firmware_version_show(struct device *dev,
  3238. + struct device_attribute *attr, char *buf)
  3239. +{
  3240. + struct ssam_controller *ctrl = dev_get_drvdata(dev);
  3241. + u32 version, a, b, c;
  3242. + int status;
  3243. +
  3244. + status = ssam_get_firmware_version(ctrl, &version);
  3245. + if (status < 0)
  3246. + return status;
  3247. +
  3248. + a = (version >> 24) & 0xff;
  3249. + b = ((version >> 8) & 0xffff);
  3250. + c = version & 0xff;
  3251. +
  3252. + return sysfs_emit(buf, "%u.%u.%u\n", a, b, c);
  3253. +}
  3254. +static DEVICE_ATTR_RO(firmware_version);
  3255. +
  3256. +static struct attribute *ssam_sam_attrs[] = {
  3257. + &dev_attr_firmware_version.attr,
  3258. + NULL
  3259. +};
  3260. +
  3261. +static const struct attribute_group ssam_sam_group = {
  3262. + .name = "sam",
  3263. + .attrs = ssam_sam_attrs,
  3264. +};
  3265. +
  3266. +
  3267. +/* -- ACPI based device setup. ---------------------------------------------- */
  3268. +
  3269. +static acpi_status ssam_serdev_setup_via_acpi_crs(struct acpi_resource *rsc,
  3270. + void *ctx)
  3271. +{
  3272. + struct serdev_device *serdev = ctx;
  3273. + struct acpi_resource_common_serialbus *serial;
  3274. + struct acpi_resource_uart_serialbus *uart;
  3275. + bool flow_control;
  3276. + int status = 0;
  3277. +
  3278. + if (rsc->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
  3279. + return AE_OK;
  3280. +
  3281. + serial = &rsc->data.common_serial_bus;
  3282. + if (serial->type != ACPI_RESOURCE_SERIAL_TYPE_UART)
  3283. + return AE_OK;
  3284. +
  3285. + uart = &rsc->data.uart_serial_bus;
  3286. +
  3287. + /* Set up serdev device. */
  3288. + serdev_device_set_baudrate(serdev, uart->default_baud_rate);
  3289. +
  3290. + /* serdev currently only supports RTSCTS flow control. */
  3291. + if (uart->flow_control & (~((u8)ACPI_UART_FLOW_CONTROL_HW))) {
  3292. + dev_warn(&serdev->dev, "setup: unsupported flow control (value: %#04x)\n",
  3293. + uart->flow_control);
  3294. + }
  3295. +
  3296. + /* Set RTSCTS flow control. */
  3297. + flow_control = uart->flow_control & ACPI_UART_FLOW_CONTROL_HW;
  3298. + serdev_device_set_flow_control(serdev, flow_control);
  3299. +
  3300. + /* serdev currently only supports EVEN/ODD parity. */
  3301. + switch (uart->parity) {
  3302. + case ACPI_UART_PARITY_NONE:
  3303. + status = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
  3304. + break;
  3305. + case ACPI_UART_PARITY_EVEN:
  3306. + status = serdev_device_set_parity(serdev, SERDEV_PARITY_EVEN);
  3307. + break;
  3308. + case ACPI_UART_PARITY_ODD:
  3309. + status = serdev_device_set_parity(serdev, SERDEV_PARITY_ODD);
  3310. + break;
  3311. + default:
  3312. + dev_warn(&serdev->dev, "setup: unsupported parity (value: %#04x)\n",
  3313. + uart->parity);
  3314. + break;
  3315. + }
  3316. +
  3317. + if (status) {
  3318. + dev_err(&serdev->dev, "setup: failed to set parity (value: %#04x, error: %d)\n",
  3319. + uart->parity, status);
  3320. + return AE_ERROR;
  3321. + }
  3322. +
  3323. + /* We've found the resource and are done. */
  3324. + return AE_CTRL_TERMINATE;
  3325. +}
  3326. +
  3327. +static acpi_status ssam_serdev_setup_via_acpi(acpi_handle handle,
  3328. + struct serdev_device *serdev)
  3329. +{
  3330. + return acpi_walk_resources(handle, METHOD_NAME__CRS,
  3331. + ssam_serdev_setup_via_acpi_crs, serdev);
  3332. +}
  3333. +
  3334. +
  3335. +/* -- Power management. ----------------------------------------------------- */
  3336. +
  3337. +static void ssam_serial_hub_shutdown(struct device *dev)
  3338. +{
  3339. + struct ssam_controller *c = dev_get_drvdata(dev);
  3340. + int status;
  3341. +
  3342. + /*
  3343. + * Try to disable notifiers, signal display-off and D0-exit, ignore any
  3344. + * errors.
  3345. + *
  3346. + * Note: It has not been established yet if this is actually
  3347. + * necessary/useful for shutdown.
  3348. + */
  3349. +
  3350. + status = ssam_notifier_disable_registered(c);
  3351. + if (status) {
  3352. + ssam_err(c, "pm: failed to disable notifiers for shutdown: %d\n",
  3353. + status);
  3354. + }
  3355. +
  3356. + status = ssam_ctrl_notif_display_off(c);
  3357. + if (status)
  3358. + ssam_err(c, "pm: display-off notification failed: %d\n", status);
  3359. +
  3360. + status = ssam_ctrl_notif_d0_exit(c);
  3361. + if (status)
  3362. + ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
  3363. +}
  3364. +
  3365. +#ifdef CONFIG_PM_SLEEP
  3366. +
  3367. +static int ssam_serial_hub_pm_prepare(struct device *dev)
  3368. +{
  3369. + struct ssam_controller *c = dev_get_drvdata(dev);
  3370. + int status;
  3371. +
  3372. + /*
  3373. + * Try to signal display-off, This will quiesce events.
  3374. + *
  3375. + * Note: Signaling display-off/display-on should normally be done from
  3376. + * some sort of display state notifier. As that is not available,
  3377. + * signal it here.
  3378. + */
  3379. +
  3380. + status = ssam_ctrl_notif_display_off(c);
  3381. + if (status)
  3382. + ssam_err(c, "pm: display-off notification failed: %d\n", status);
  3383. +
  3384. + return status;
  3385. +}
  3386. +
  3387. +static void ssam_serial_hub_pm_complete(struct device *dev)
  3388. +{
  3389. + struct ssam_controller *c = dev_get_drvdata(dev);
  3390. + int status;
  3391. +
  3392. + /*
  3393. + * Try to signal display-on. This will restore events.
  3394. + *
  3395. + * Note: Signaling display-off/display-on should normally be done from
  3396. + * some sort of display state notifier. As that is not available,
  3397. + * signal it here.
  3398. + */
  3399. +
  3400. + status = ssam_ctrl_notif_display_on(c);
  3401. + if (status)
  3402. + ssam_err(c, "pm: display-on notification failed: %d\n", status);
  3403. +}
  3404. +
  3405. +static int ssam_serial_hub_pm_suspend(struct device *dev)
  3406. +{
  3407. + struct ssam_controller *c = dev_get_drvdata(dev);
  3408. + int status;
  3409. +
  3410. + /*
  3411. + * Try to signal D0-exit, enable IRQ wakeup if specified. Abort on
  3412. + * error.
  3413. + */
  3414. +
  3415. + status = ssam_ctrl_notif_d0_exit(c);
  3416. + if (status) {
  3417. + ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
  3418. + goto err_notif;
  3419. + }
  3420. +
  3421. + status = ssam_irq_arm_for_wakeup(c);
  3422. + if (status)
  3423. + goto err_irq;
  3424. +
  3425. + WARN_ON(ssam_controller_suspend(c));
  3426. + return 0;
  3427. +
  3428. +err_irq:
  3429. + ssam_ctrl_notif_d0_entry(c);
  3430. +err_notif:
  3431. + ssam_ctrl_notif_display_on(c);
  3432. + return status;
  3433. +}
  3434. +
  3435. +static int ssam_serial_hub_pm_resume(struct device *dev)
  3436. +{
  3437. + struct ssam_controller *c = dev_get_drvdata(dev);
  3438. + int status;
  3439. +
  3440. + WARN_ON(ssam_controller_resume(c));
  3441. +
  3442. + /*
  3443. + * Try to disable IRQ wakeup (if specified) and signal D0-entry. In
  3444. + * case of errors, log them and try to restore normal operation state
  3445. + * as far as possible.
  3446. + *
  3447. + * Note: Signaling display-off/display-on should normally be done from
  3448. + * some sort of display state notifier. As that is not available,
  3449. + * signal it here.
  3450. + */
  3451. +
  3452. + ssam_irq_disarm_wakeup(c);
  3453. +
  3454. + status = ssam_ctrl_notif_d0_entry(c);
  3455. + if (status)
  3456. + ssam_err(c, "pm: D0-entry notification failed: %d\n", status);
  3457. +
  3458. + return 0;
  3459. +}
  3460. +
  3461. +static int ssam_serial_hub_pm_freeze(struct device *dev)
  3462. +{
  3463. + struct ssam_controller *c = dev_get_drvdata(dev);
  3464. + int status;
  3465. +
  3466. + /*
  3467. + * During hibernation image creation, we only have to ensure that the
  3468. + * EC doesn't send us any events. This is done via the display-off
  3469. + * and D0-exit notifications. Note that this sets up the wakeup IRQ
  3470. + * on the EC side, however, we have disabled it by default on our side
  3471. + * and won't enable it here.
  3472. + *
  3473. + * See ssam_serial_hub_poweroff() for more details on the hibernation
  3474. + * process.
  3475. + */
  3476. +
  3477. + status = ssam_ctrl_notif_d0_exit(c);
  3478. + if (status) {
  3479. + ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
  3480. + ssam_ctrl_notif_display_on(c);
  3481. + return status;
  3482. + }
  3483. +
  3484. + WARN_ON(ssam_controller_suspend(c));
  3485. + return 0;
  3486. +}
  3487. +
  3488. +static int ssam_serial_hub_pm_thaw(struct device *dev)
  3489. +{
  3490. + struct ssam_controller *c = dev_get_drvdata(dev);
  3491. + int status;
  3492. +
  3493. + WARN_ON(ssam_controller_resume(c));
  3494. +
  3495. + status = ssam_ctrl_notif_d0_entry(c);
  3496. + if (status)
  3497. + ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
  3498. +
  3499. + return status;
  3500. +}
  3501. +
  3502. +static int ssam_serial_hub_pm_poweroff(struct device *dev)
  3503. +{
  3504. + struct ssam_controller *c = dev_get_drvdata(dev);
  3505. + int status;
  3506. +
  3507. + /*
  3508. + * When entering hibernation and powering off the system, the EC, at
  3509. + * least on some models, may disable events. Without us taking care of
  3510. + * that, this leads to events not being enabled/restored when the
  3511. + * system resumes from hibernation, resulting SAM-HID subsystem devices
  3512. + * (i.e. keyboard, touchpad) not working, AC-plug/AC-unplug events being
  3513. + * gone, etc.
  3514. + *
  3515. + * To avoid these issues, we disable all registered events here (this is
  3516. + * likely not actually required) and restore them during the drivers PM
  3517. + * restore callback.
  3518. + *
  3519. + * Wakeup from the EC interrupt is not supported during hibernation,
  3520. + * so don't arm the IRQ here.
  3521. + */
  3522. +
  3523. + status = ssam_notifier_disable_registered(c);
  3524. + if (status) {
  3525. + ssam_err(c, "pm: failed to disable notifiers for hibernation: %d\n",
  3526. + status);
  3527. + return status;
  3528. + }
  3529. +
  3530. + status = ssam_ctrl_notif_d0_exit(c);
  3531. + if (status) {
  3532. + ssam_err(c, "pm: D0-exit notification failed: %d\n", status);
  3533. + ssam_notifier_restore_registered(c);
  3534. + return status;
  3535. + }
  3536. +
  3537. + WARN_ON(ssam_controller_suspend(c));
  3538. + return 0;
  3539. +}
  3540. +
  3541. +static int ssam_serial_hub_pm_restore(struct device *dev)
  3542. +{
  3543. + struct ssam_controller *c = dev_get_drvdata(dev);
  3544. + int status;
  3545. +
  3546. + /*
  3547. + * Ignore but log errors, try to restore state as much as possible in
  3548. + * case of failures. See ssam_serial_hub_poweroff() for more details on
  3549. + * the hibernation process.
  3550. + */
  3551. +
  3552. + WARN_ON(ssam_controller_resume(c));
  3553. +
  3554. + status = ssam_ctrl_notif_d0_entry(c);
  3555. + if (status)
  3556. + ssam_err(c, "pm: D0-entry notification failed: %d\n", status);
  3557. +
  3558. + ssam_notifier_restore_registered(c);
  3559. + return 0;
  3560. +}
  3561. +
  3562. +static const struct dev_pm_ops ssam_serial_hub_pm_ops = {
  3563. + .prepare = ssam_serial_hub_pm_prepare,
  3564. + .complete = ssam_serial_hub_pm_complete,
  3565. + .suspend = ssam_serial_hub_pm_suspend,
  3566. + .resume = ssam_serial_hub_pm_resume,
  3567. + .freeze = ssam_serial_hub_pm_freeze,
  3568. + .thaw = ssam_serial_hub_pm_thaw,
  3569. + .poweroff = ssam_serial_hub_pm_poweroff,
  3570. + .restore = ssam_serial_hub_pm_restore,
  3571. +};
  3572. +
  3573. +#else /* CONFIG_PM_SLEEP */
  3574. +
  3575. +static const struct dev_pm_ops ssam_serial_hub_pm_ops = { };
  3576. +
  3577. +#endif /* CONFIG_PM_SLEEP */
  3578. +
  3579. +
  3580. +/* -- Device/driver setup. -------------------------------------------------- */
  3581. +
  3582. +static const struct acpi_gpio_params gpio_ssam_wakeup_int = { 0, 0, false };
  3583. +static const struct acpi_gpio_params gpio_ssam_wakeup = { 1, 0, false };
  3584. +
  3585. +static const struct acpi_gpio_mapping ssam_acpi_gpios[] = {
  3586. + { "ssam_wakeup-int-gpio", &gpio_ssam_wakeup_int, 1 },
  3587. + { "ssam_wakeup-gpio", &gpio_ssam_wakeup, 1 },
  3588. + { },
  3589. +};
  3590. +
  3591. +static int ssam_serial_hub_probe(struct serdev_device *serdev)
  3592. +{
  3593. + struct ssam_controller *ctrl;
  3594. + acpi_handle *ssh = ACPI_HANDLE(&serdev->dev);
  3595. + acpi_status astatus;
  3596. + int status;
  3597. +
  3598. + if (gpiod_count(&serdev->dev, NULL) < 0)
  3599. + return -ENODEV;
  3600. +
  3601. + status = devm_acpi_dev_add_driver_gpios(&serdev->dev, ssam_acpi_gpios);
  3602. + if (status)
  3603. + return status;
  3604. +
  3605. + /* Allocate controller. */
  3606. + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
  3607. + if (!ctrl)
  3608. + return -ENOMEM;
  3609. +
  3610. + /* Initialize controller. */
  3611. + status = ssam_controller_init(ctrl, serdev);
  3612. + if (status)
  3613. + goto err_ctrl_init;
  3614. +
  3615. + ssam_controller_lock(ctrl);
  3616. +
  3617. + /* Set up serdev device. */
  3618. + serdev_device_set_drvdata(serdev, ctrl);
  3619. + serdev_device_set_client_ops(serdev, &ssam_serdev_ops);
  3620. + status = serdev_device_open(serdev);
  3621. + if (status)
  3622. + goto err_devopen;
  3623. +
  3624. + astatus = ssam_serdev_setup_via_acpi(ssh, serdev);
  3625. + if (ACPI_FAILURE(astatus)) {
  3626. + status = -ENXIO;
  3627. + goto err_devinit;
  3628. + }
  3629. +
  3630. + /* Start controller. */
  3631. + status = ssam_controller_start(ctrl);
  3632. + if (status)
  3633. + goto err_devinit;
  3634. +
  3635. + ssam_controller_unlock(ctrl);
  3636. +
  3637. + /*
  3638. + * Initial SAM requests: Log version and notify default/init power
  3639. + * states.
  3640. + */
  3641. + status = ssam_log_firmware_version(ctrl);
  3642. + if (status)
  3643. + goto err_initrq;
  3644. +
  3645. + status = ssam_ctrl_notif_d0_entry(ctrl);
  3646. + if (status)
  3647. + goto err_initrq;
  3648. +
  3649. + status = ssam_ctrl_notif_display_on(ctrl);
  3650. + if (status)
  3651. + goto err_initrq;
  3652. +
  3653. + status = sysfs_create_group(&serdev->dev.kobj, &ssam_sam_group);
  3654. + if (status)
  3655. + goto err_initrq;
  3656. +
  3657. + /* Set up IRQ. */
  3658. + status = ssam_irq_setup(ctrl);
  3659. + if (status)
  3660. + goto err_irq;
  3661. +
  3662. + /* Finally, set main controller reference. */
  3663. + status = ssam_try_set_controller(ctrl);
  3664. + if (WARN_ON(status)) /* Currently, we're the only provider. */
  3665. + goto err_mainref;
  3666. +
  3667. + /*
  3668. + * TODO: The EC can wake up the system via the associated GPIO interrupt
  3669. + * in multiple situations. One of which is the remaining battery
  3670. + * capacity falling below a certain threshold. Normally, we should
  3671. + * use the device_init_wakeup function, however, the EC also seems
  3672. + * to have other reasons for waking up the system and it seems
  3673. + * that Windows has additional checks whether the system should be
  3674. + * resumed. In short, this causes some spurious unwanted wake-ups.
  3675. + * For now let's thus default power/wakeup to false.
  3676. + */
  3677. + device_set_wakeup_capable(&serdev->dev, true);
  3678. + acpi_walk_dep_device_list(ssh);
  3679. +
  3680. + return 0;
  3681. +
  3682. +err_mainref:
  3683. + ssam_irq_free(ctrl);
  3684. +err_irq:
  3685. + sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group);
  3686. +err_initrq:
  3687. + ssam_controller_lock(ctrl);
  3688. + ssam_controller_shutdown(ctrl);
  3689. +err_devinit:
  3690. + serdev_device_close(serdev);
  3691. +err_devopen:
  3692. + ssam_controller_destroy(ctrl);
  3693. + ssam_controller_unlock(ctrl);
  3694. +err_ctrl_init:
  3695. + kfree(ctrl);
  3696. + return status;
  3697. +}
  3698. +
  3699. +static void ssam_serial_hub_remove(struct serdev_device *serdev)
  3700. +{
  3701. + struct ssam_controller *ctrl = serdev_device_get_drvdata(serdev);
  3702. + int status;
  3703. +
  3704. + /* Clear static reference so that no one else can get a new one. */
  3705. + ssam_clear_controller();
  3706. +
  3707. + /* Disable and free IRQ. */
  3708. + ssam_irq_free(ctrl);
  3709. +
  3710. + sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group);
  3711. + ssam_controller_lock(ctrl);
  3712. +
  3713. + /* Act as if suspending to silence events. */
  3714. + status = ssam_ctrl_notif_display_off(ctrl);
  3715. + if (status) {
  3716. + dev_err(&serdev->dev, "display-off notification failed: %d\n",
  3717. + status);
  3718. + }
  3719. +
  3720. + status = ssam_ctrl_notif_d0_exit(ctrl);
  3721. + if (status) {
  3722. + dev_err(&serdev->dev, "D0-exit notification failed: %d\n",
  3723. + status);
  3724. + }
  3725. +
  3726. + /* Shut down controller and remove serdev device reference from it. */
  3727. + ssam_controller_shutdown(ctrl);
  3728. +
  3729. + /* Shut down actual transport. */
  3730. + serdev_device_wait_until_sent(serdev, 0);
  3731. + serdev_device_close(serdev);
  3732. +
  3733. + /* Drop our controller reference. */
  3734. + ssam_controller_unlock(ctrl);
  3735. + ssam_controller_put(ctrl);
  3736. +
  3737. + device_set_wakeup_capable(&serdev->dev, false);
  3738. +}
  3739. +
  3740. +static const struct acpi_device_id ssam_serial_hub_match[] = {
  3741. + { "MSHW0084", 0 },
  3742. + { },
  3743. +};
  3744. +MODULE_DEVICE_TABLE(acpi, ssam_serial_hub_match);
  3745. +
  3746. +static struct serdev_device_driver ssam_serial_hub = {
  3747. + .probe = ssam_serial_hub_probe,
  3748. + .remove = ssam_serial_hub_remove,
  3749. + .driver = {
  3750. + .name = "surface_serial_hub",
  3751. + .acpi_match_table = ssam_serial_hub_match,
  3752. + .pm = &ssam_serial_hub_pm_ops,
  3753. + .shutdown = ssam_serial_hub_shutdown,
  3754. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  3755. + },
  3756. +};
  3757. +module_serdev_device_driver(ssam_serial_hub);
  3758. +
  3759. +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  3760. +MODULE_DESCRIPTION("Subsystem and Surface Serial Hub driver for Surface System Aggregator Module");
  3761. +MODULE_LICENSE("GPL");
  3762. diff --git a/drivers/platform/surface/aggregator/ssh_msgb.h b/drivers/platform/surface/aggregator/ssh_msgb.h
  3763. new file mode 100644
  3764. index 000000000000..1221f642dda1
  3765. --- /dev/null
  3766. +++ b/drivers/platform/surface/aggregator/ssh_msgb.h
  3767. @@ -0,0 +1,205 @@
  3768. +/* SPDX-License-Identifier: GPL-2.0+ */
  3769. +/*
  3770. + * SSH message builder functions.
  3771. + *
  3772. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  3773. + */
  3774. +
  3775. +#ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H
  3776. +#define _SURFACE_AGGREGATOR_SSH_MSGB_H
  3777. +
  3778. +#include <asm/unaligned.h>
  3779. +#include <linux/types.h>
  3780. +
  3781. +#include <linux/surface_aggregator/controller.h>
  3782. +#include <linux/surface_aggregator/serial_hub.h>
  3783. +
  3784. +/**
  3785. + * struct msgbuf - Buffer struct to construct SSH messages.
  3786. + * @begin: Pointer to the beginning of the allocated buffer space.
  3787. + * @end: Pointer to the end (one past last element) of the allocated buffer
  3788. + * space.
  3789. + * @ptr: Pointer to the first free element in the buffer.
  3790. + */
  3791. +struct msgbuf {
  3792. + u8 *begin;
  3793. + u8 *end;
  3794. + u8 *ptr;
  3795. +};
  3796. +
  3797. +/**
  3798. + * msgb_init() - Initialize the given message buffer struct.
  3799. + * @msgb: The buffer struct to initialize
  3800. + * @ptr: Pointer to the underlying memory by which the buffer will be backed.
  3801. + * @cap: Size of the underlying memory.
  3802. + *
  3803. + * Initialize the given message buffer struct using the provided memory as
  3804. + * backing.
  3805. + */
  3806. +static inline void msgb_init(struct msgbuf *msgb, u8 *ptr, size_t cap)
  3807. +{
  3808. + msgb->begin = ptr;
  3809. + msgb->end = ptr + cap;
  3810. + msgb->ptr = ptr;
  3811. +}
  3812. +
  3813. +/**
  3814. + * msgb_bytes_used() - Return the current number of bytes used in the buffer.
  3815. + * @msgb: The message buffer.
  3816. + */
  3817. +static inline size_t msgb_bytes_used(const struct msgbuf *msgb)
  3818. +{
  3819. + return msgb->ptr - msgb->begin;
  3820. +}
  3821. +
  3822. +static inline void __msgb_push_u8(struct msgbuf *msgb, u8 value)
  3823. +{
  3824. + *msgb->ptr = value;
  3825. + msgb->ptr += sizeof(u8);
  3826. +}
  3827. +
  3828. +static inline void __msgb_push_u16(struct msgbuf *msgb, u16 value)
  3829. +{
  3830. + put_unaligned_le16(value, msgb->ptr);
  3831. + msgb->ptr += sizeof(u16);
  3832. +}
  3833. +
  3834. +/**
  3835. + * msgb_push_u16() - Push a u16 value to the buffer.
  3836. + * @msgb: The message buffer.
  3837. + * @value: The value to push to the buffer.
  3838. + */
  3839. +static inline void msgb_push_u16(struct msgbuf *msgb, u16 value)
  3840. +{
  3841. + if (WARN_ON(msgb->ptr + sizeof(u16) > msgb->end))
  3842. + return;
  3843. +
  3844. + __msgb_push_u16(msgb, value);
  3845. +}
  3846. +
  3847. +/**
  3848. + * msgb_push_syn() - Push SSH SYN bytes to the buffer.
  3849. + * @msgb: The message buffer.
  3850. + */
  3851. +static inline void msgb_push_syn(struct msgbuf *msgb)
  3852. +{
  3853. + msgb_push_u16(msgb, SSH_MSG_SYN);
  3854. +}
  3855. +
  3856. +/**
  3857. + * msgb_push_buf() - Push raw data to the buffer.
  3858. + * @msgb: The message buffer.
  3859. + * @buf: The data to push to the buffer.
  3860. + * @len: The length of the data to push to the buffer.
  3861. + */
  3862. +static inline void msgb_push_buf(struct msgbuf *msgb, const u8 *buf, size_t len)
  3863. +{
  3864. + msgb->ptr = memcpy(msgb->ptr, buf, len) + len;
  3865. +}
  3866. +
  3867. +/**
  3868. + * msgb_push_crc() - Compute CRC and push it to the buffer.
  3869. + * @msgb: The message buffer.
  3870. + * @buf: The data for which the CRC should be computed.
  3871. + * @len: The length of the data for which the CRC should be computed.
  3872. + */
  3873. +static inline void msgb_push_crc(struct msgbuf *msgb, const u8 *buf, size_t len)
  3874. +{
  3875. + msgb_push_u16(msgb, ssh_crc(buf, len));
  3876. +}
  3877. +
  3878. +/**
  3879. + * msgb_push_frame() - Push a SSH message frame header to the buffer.
  3880. + * @msgb: The message buffer
  3881. + * @ty: The type of the frame.
  3882. + * @len: The length of the payload of the frame.
  3883. + * @seq: The sequence ID of the frame/packet.
  3884. + */
  3885. +static inline void msgb_push_frame(struct msgbuf *msgb, u8 ty, u16 len, u8 seq)
  3886. +{
  3887. + u8 *const begin = msgb->ptr;
  3888. +
  3889. + if (WARN_ON(msgb->ptr + sizeof(struct ssh_frame) > msgb->end))
  3890. + return;
  3891. +
  3892. + __msgb_push_u8(msgb, ty); /* Frame type. */
  3893. + __msgb_push_u16(msgb, len); /* Frame payload length. */
  3894. + __msgb_push_u8(msgb, seq); /* Frame sequence ID. */
  3895. +
  3896. + msgb_push_crc(msgb, begin, msgb->ptr - begin);
  3897. +}
  3898. +
  3899. +/**
  3900. + * msgb_push_ack() - Push a SSH ACK frame to the buffer.
  3901. + * @msgb: The message buffer
  3902. + * @seq: The sequence ID of the frame/packet to be ACKed.
  3903. + */
  3904. +static inline void msgb_push_ack(struct msgbuf *msgb, u8 seq)
  3905. +{
  3906. + /* SYN. */
  3907. + msgb_push_syn(msgb);
  3908. +
  3909. + /* ACK-type frame + CRC. */
  3910. + msgb_push_frame(msgb, SSH_FRAME_TYPE_ACK, 0x00, seq);
  3911. +
  3912. + /* Payload CRC (ACK-type frames do not have a payload). */
  3913. + msgb_push_crc(msgb, msgb->ptr, 0);
  3914. +}
  3915. +
  3916. +/**
  3917. + * msgb_push_nak() - Push a SSH NAK frame to the buffer.
  3918. + * @msgb: The message buffer
  3919. + */
  3920. +static inline void msgb_push_nak(struct msgbuf *msgb)
  3921. +{
  3922. + /* SYN. */
  3923. + msgb_push_syn(msgb);
  3924. +
  3925. + /* NAK-type frame + CRC. */
  3926. + msgb_push_frame(msgb, SSH_FRAME_TYPE_NAK, 0x00, 0x00);
  3927. +
  3928. + /* Payload CRC (ACK-type frames do not have a payload). */
  3929. + msgb_push_crc(msgb, msgb->ptr, 0);
  3930. +}
  3931. +
  3932. +/**
  3933. + * msgb_push_cmd() - Push a SSH command frame with payload to the buffer.
  3934. + * @msgb: The message buffer.
  3935. + * @seq: The sequence ID (SEQ) of the frame/packet.
  3936. + * @rqid: The request ID (RQID) of the request contained in the frame.
  3937. + * @rqst: The request to wrap in the frame.
  3938. + */
  3939. +static inline void msgb_push_cmd(struct msgbuf *msgb, u8 seq, u16 rqid,
  3940. + const struct ssam_request *rqst)
  3941. +{
  3942. + const u8 type = SSH_FRAME_TYPE_DATA_SEQ;
  3943. + u8 *cmd;
  3944. +
  3945. + /* SYN. */
  3946. + msgb_push_syn(msgb);
  3947. +
  3948. + /* Command frame + CRC. */
  3949. + msgb_push_frame(msgb, type, sizeof(struct ssh_command) + rqst->length, seq);
  3950. +
  3951. + /* Frame payload: Command struct + payload. */
  3952. + if (WARN_ON(msgb->ptr + sizeof(struct ssh_command) > msgb->end))
  3953. + return;
  3954. +
  3955. + cmd = msgb->ptr;
  3956. +
  3957. + __msgb_push_u8(msgb, SSH_PLD_TYPE_CMD); /* Payload type. */
  3958. + __msgb_push_u8(msgb, rqst->target_category); /* Target category. */
  3959. + __msgb_push_u8(msgb, rqst->target_id); /* Target ID (out). */
  3960. + __msgb_push_u8(msgb, 0x00); /* Target ID (in). */
  3961. + __msgb_push_u8(msgb, rqst->instance_id); /* Instance ID. */
  3962. + __msgb_push_u16(msgb, rqid); /* Request ID. */
  3963. + __msgb_push_u8(msgb, rqst->command_id); /* Command ID. */
  3964. +
  3965. + /* Command payload. */
  3966. + msgb_push_buf(msgb, rqst->payload, rqst->length);
  3967. +
  3968. + /* CRC for command struct + payload. */
  3969. + msgb_push_crc(msgb, cmd, msgb->ptr - cmd);
  3970. +}
  3971. +
  3972. +#endif /* _SURFACE_AGGREGATOR_SSH_MSGB_H */
  3973. diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c
  3974. new file mode 100644
  3975. index 000000000000..66e38fdc7963
  3976. --- /dev/null
  3977. +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c
  3978. @@ -0,0 +1,1710 @@
  3979. +// SPDX-License-Identifier: GPL-2.0+
  3980. +/*
  3981. + * SSH packet transport layer.
  3982. + *
  3983. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  3984. + */
  3985. +
  3986. +#include <asm/unaligned.h>
  3987. +#include <linux/atomic.h>
  3988. +#include <linux/jiffies.h>
  3989. +#include <linux/kfifo.h>
  3990. +#include <linux/kref.h>
  3991. +#include <linux/kthread.h>
  3992. +#include <linux/ktime.h>
  3993. +#include <linux/limits.h>
  3994. +#include <linux/list.h>
  3995. +#include <linux/lockdep.h>
  3996. +#include <linux/serdev.h>
  3997. +#include <linux/slab.h>
  3998. +#include <linux/spinlock.h>
  3999. +#include <linux/workqueue.h>
  4000. +
  4001. +#include <linux/surface_aggregator/serial_hub.h>
  4002. +
  4003. +#include "ssh_msgb.h"
  4004. +#include "ssh_packet_layer.h"
  4005. +#include "ssh_parser.h"
  4006. +
  4007. +/*
  4008. + * To simplify reasoning about the code below, we define a few concepts. The
  4009. + * system below is similar to a state-machine for packets, however, there are
  4010. + * too many states to explicitly write them down. To (somewhat) manage the
  4011. + * states and packets we rely on flags, reference counting, and some simple
  4012. + * concepts. State transitions are triggered by actions.
  4013. + *
  4014. + * >> Actions <<
  4015. + *
  4016. + * - submit
  4017. + * - transmission start (process next item in queue)
  4018. + * - transmission finished (guaranteed to never be parallel to transmission
  4019. + * start)
  4020. + * - ACK received
  4021. + * - NAK received (this is equivalent to issuing re-submit for all pending
  4022. + * packets)
  4023. + * - timeout (this is equivalent to re-issuing a submit or canceling)
  4024. + * - cancel (non-pending and pending)
  4025. + *
  4026. + * >> Data Structures, Packet Ownership, General Overview <<
  4027. + *
  4028. + * The code below employs two main data structures: The packet queue,
  4029. + * containing all packets scheduled for transmission, and the set of pending
  4030. + * packets, containing all packets awaiting an ACK.
  4031. + *
  4032. + * Shared ownership of a packet is controlled via reference counting. Inside
  4033. + * the transport system are a total of five packet owners:
  4034. + *
  4035. + * - the packet queue,
  4036. + * - the pending set,
  4037. + * - the transmitter thread,
  4038. + * - the receiver thread (via ACKing), and
  4039. + * - the timeout work item.
  4040. + *
  4041. + * Normal operation is as follows: The initial reference of the packet is
  4042. + * obtained by submitting the packet and queuing it. The receiver thread takes
  4043. + * packets from the queue. By doing this, it does not increment the refcount
  4044. + * but takes over the reference (removing it from the queue). If the packet is
  4045. + * sequenced (i.e. needs to be ACKed by the client), the transmitter thread
  4046. + * sets-up the timeout and adds the packet to the pending set before starting
  4047. + * to transmit it. As the timeout is handled by a reaper task, no additional
  4048. + * reference for it is needed. After the transmit is done, the reference held
  4049. + * by the transmitter thread is dropped. If the packet is unsequenced (i.e.
  4050. + * does not need an ACK), the packet is completed by the transmitter thread
  4051. + * before dropping that reference.
  4052. + *
  4053. + * On receival of an ACK, the receiver thread removes and obtains the
  4054. + * reference to the packet from the pending set. The receiver thread will then
  4055. + * complete the packet and drop its reference.
  4056. + *
  4057. + * On receival of a NAK, the receiver thread re-submits all currently pending
  4058. + * packets.
  4059. + *
  4060. + * Packet timeouts are detected by the timeout reaper. This is a task,
  4061. + * scheduled depending on the earliest packet timeout expiration date,
  4062. + * checking all currently pending packets if their timeout has expired. If the
  4063. + * timeout of a packet has expired, it is re-submitted and the number of tries
  4064. + * of this packet is incremented. If this number reaches its limit, the packet
  4065. + * will be completed with a failure.
  4066. + *
  4067. + * On transmission failure (such as repeated packet timeouts), the completion
  4068. + * callback is immediately run by on thread on which the error was detected.
  4069. + *
  4070. + * To ensure that a packet eventually leaves the system it is marked as
  4071. + * "locked" directly before it is going to be completed or when it is
  4072. + * canceled. Marking a packet as "locked" has the effect that passing and
  4073. + * creating new references of the packet is disallowed. This means that the
  4074. + * packet cannot be added to the queue, the pending set, and the timeout, or
  4075. + * be picked up by the transmitter thread or receiver thread. To remove a
  4076. + * packet from the system it has to be marked as locked and subsequently all
  4077. + * references from the data structures (queue, pending) have to be removed.
  4078. + * References held by threads will eventually be dropped automatically as
  4079. + * their execution progresses.
  4080. + *
  4081. + * Note that the packet completion callback is, in case of success and for a
  4082. + * sequenced packet, guaranteed to run on the receiver thread, thus providing
  4083. + * a way to reliably identify responses to the packet. The packet completion
  4084. + * callback is only run once and it does not indicate that the packet has
  4085. + * fully left the system (for this, one should rely on the release method,
  4086. + * triggered when the reference count of the packet reaches zero). In case of
  4087. + * re-submission (and with somewhat unlikely timing), it may be possible that
  4088. + * the packet is being re-transmitted while the completion callback runs.
  4089. + * Completion will occur both on success and internal error, as well as when
  4090. + * the packet is canceled.
  4091. + *
  4092. + * >> Flags <<
  4093. + *
  4094. + * Flags are used to indicate the state and progression of a packet. Some flags
  4095. + * have stricter guarantees than other:
  4096. + *
  4097. + * - locked
  4098. + * Indicates if the packet is locked. If the packet is locked, passing and/or
  4099. + * creating additional references to the packet is forbidden. The packet thus
  4100. + * may not be queued, dequeued, or removed or added to the pending set. Note
  4101. + * that the packet state flags may still change (e.g. it may be marked as
  4102. + * ACKed, transmitted, ...).
  4103. + *
  4104. + * - completed
  4105. + * Indicates if the packet completion callback has been executed or is about
  4106. + * to be executed. This flag is used to ensure that the packet completion
  4107. + * callback is only run once.
  4108. + *
  4109. + * - queued
  4110. + * Indicates if a packet is present in the submission queue or not. This flag
  4111. + * must only be modified with the queue lock held, and must be coherent to the
  4112. + * presence of the packet in the queue.
  4113. + *
  4114. + * - pending
  4115. + * Indicates if a packet is present in the set of pending packets or not.
  4116. + * This flag must only be modified with the pending lock held, and must be
  4117. + * coherent to the presence of the packet in the pending set.
  4118. + *
  4119. + * - transmitting
  4120. + * Indicates if the packet is currently transmitting. In case of
  4121. + * re-transmissions, it is only safe to wait on the "transmitted" completion
  4122. + * after this flag has been set. The completion will be set both in success
  4123. + * and error case.
  4124. + *
  4125. + * - transmitted
  4126. + * Indicates if the packet has been transmitted. This flag is not cleared by
  4127. + * the system, thus it indicates the first transmission only.
  4128. + *
  4129. + * - acked
  4130. + * Indicates if the packet has been acknowledged by the client. There are no
  4131. + * other guarantees given. For example, the packet may still be canceled
  4132. + * and/or the completion may be triggered an error even though this bit is
  4133. + * set. Rely on the status provided to the completion callback instead.
  4134. + *
  4135. + * - canceled
  4136. + * Indicates if the packet has been canceled from the outside. There are no
  4137. + * other guarantees given. Specifically, the packet may be completed by
  4138. + * another part of the system before the cancellation attempts to complete it.
  4139. + *
  4140. + * >> General Notes <<
  4141. + *
  4142. + * - To avoid deadlocks, if both queue and pending locks are required, the
  4143. + * pending lock must be acquired before the queue lock.
  4144. + *
  4145. + * - The packet priority must be accessed only while holding the queue lock.
  4146. + *
  4147. + * - The packet timestamp must be accessed only while holding the pending
  4148. + * lock.
  4149. + */
  4150. +
  4151. +/*
  4152. + * SSH_PTL_MAX_PACKET_TRIES - Maximum transmission attempts for packet.
  4153. + *
  4154. + * Maximum number of transmission attempts per sequenced packet in case of
  4155. + * time-outs. Must be smaller than 16. If the packet times out after this
  4156. + * amount of tries, the packet will be completed with %-ETIMEDOUT as status
  4157. + * code.
  4158. + */
  4159. +#define SSH_PTL_MAX_PACKET_TRIES 3
  4160. +
  4161. +/*
  4162. + * SSH_PTL_TX_TIMEOUT - Packet transmission timeout.
  4163. + *
  4164. + * Timeout in jiffies for packet transmission via the underlying serial
  4165. + * device. If transmitting the packet takes longer than this timeout, the
  4166. + * packet will be completed with -ETIMEDOUT. It will not be re-submitted.
  4167. + */
  4168. +#define SSH_PTL_TX_TIMEOUT HZ
  4169. +
  4170. +/*
  4171. + * SSH_PTL_PACKET_TIMEOUT - Packet response timeout.
  4172. + *
  4173. + * Timeout as ktime_t delta for ACKs. If we have not received an ACK in this
  4174. + * time-frame after starting transmission, the packet will be re-submitted.
  4175. + */
  4176. +#define SSH_PTL_PACKET_TIMEOUT ms_to_ktime(1000)
  4177. +
  4178. +/*
  4179. + * SSH_PTL_PACKET_TIMEOUT_RESOLUTION - Packet timeout granularity.
  4180. + *
  4181. + * Time-resolution for timeouts. Should be larger than one jiffy to avoid
  4182. + * direct re-scheduling of reaper work_struct.
  4183. + */
  4184. +#define SSH_PTL_PACKET_TIMEOUT_RESOLUTION ms_to_ktime(max(2000 / HZ, 50))
  4185. +
  4186. +/*
  4187. + * SSH_PTL_MAX_PENDING - Maximum number of pending packets.
  4188. + *
  4189. + * Maximum number of sequenced packets concurrently waiting for an ACK.
  4190. + * Packets marked as blocking will not be transmitted while this limit is
  4191. + * reached.
  4192. + */
  4193. +#define SSH_PTL_MAX_PENDING 1
  4194. +
  4195. +/*
  4196. + * SSH_PTL_RX_BUF_LEN - Evaluation-buffer size in bytes.
  4197. + */
  4198. +#define SSH_PTL_RX_BUF_LEN 4096
  4199. +
  4200. +/*
  4201. + * SSH_PTL_RX_FIFO_LEN - Fifo input-buffer size in bytes.
  4202. + */
  4203. +#define SSH_PTL_RX_FIFO_LEN 4096
  4204. +
  4205. +static void __ssh_ptl_packet_release(struct kref *kref)
  4206. +{
  4207. + struct ssh_packet *p = container_of(kref, struct ssh_packet, refcnt);
  4208. +
  4209. + ptl_dbg_cond(p->ptl, "ptl: releasing packet %p\n", p);
  4210. + p->ops->release(p);
  4211. +}
  4212. +
  4213. +/**
  4214. + * ssh_packet_get() - Increment reference count of packet.
  4215. + * @packet: The packet to increment the reference count of.
  4216. + *
  4217. + * Increments the reference count of the given packet. See ssh_packet_put()
  4218. + * for the counter-part of this function.
  4219. + *
  4220. + * Return: Returns the packet provided as input.
  4221. + */
  4222. +struct ssh_packet *ssh_packet_get(struct ssh_packet *packet)
  4223. +{
  4224. + if (packet)
  4225. + kref_get(&packet->refcnt);
  4226. + return packet;
  4227. +}
  4228. +EXPORT_SYMBOL_GPL(ssh_packet_get);
  4229. +
  4230. +/**
  4231. + * ssh_packet_put() - Decrement reference count of packet.
  4232. + * @packet: The packet to decrement the reference count of.
  4233. + *
  4234. + * If the reference count reaches zero, the ``release`` callback specified in
  4235. + * the packet's &struct ssh_packet_ops, i.e. ``packet->ops->release``, will be
  4236. + * called.
  4237. + *
  4238. + * See ssh_packet_get() for the counter-part of this function.
  4239. + */
  4240. +void ssh_packet_put(struct ssh_packet *packet)
  4241. +{
  4242. + if (packet)
  4243. + kref_put(&packet->refcnt, __ssh_ptl_packet_release);
  4244. +}
  4245. +EXPORT_SYMBOL_GPL(ssh_packet_put);
  4246. +
  4247. +static u8 ssh_packet_get_seq(struct ssh_packet *packet)
  4248. +{
  4249. + return packet->data.ptr[SSH_MSGOFFSET_FRAME(seq)];
  4250. +}
  4251. +
  4252. +/**
  4253. + * ssh_packet_init() - Initialize SSH packet.
  4254. + * @packet: The packet to initialize.
  4255. + * @type: Type-flags of the packet.
  4256. + * @priority: Priority of the packet. See SSH_PACKET_PRIORITY() for details.
  4257. + * @ops: Packet operations.
  4258. + *
  4259. + * Initializes the given SSH packet. Sets the transmission buffer pointer to
  4260. + * %NULL and the transmission buffer length to zero. For data-type packets,
  4261. + * this buffer has to be set separately via ssh_packet_set_data() before
  4262. + * submission, and must contain a valid SSH message, i.e. frame with optional
  4263. + * payload of any type.
  4264. + */
  4265. +void ssh_packet_init(struct ssh_packet *packet, unsigned long type,
  4266. + u8 priority, const struct ssh_packet_ops *ops)
  4267. +{
  4268. + kref_init(&packet->refcnt);
  4269. +
  4270. + packet->ptl = NULL;
  4271. + INIT_LIST_HEAD(&packet->queue_node);
  4272. + INIT_LIST_HEAD(&packet->pending_node);
  4273. +
  4274. + packet->state = type & SSH_PACKET_FLAGS_TY_MASK;
  4275. + packet->priority = priority;
  4276. + packet->timestamp = KTIME_MAX;
  4277. +
  4278. + packet->data.ptr = NULL;
  4279. + packet->data.len = 0;
  4280. +
  4281. + packet->ops = ops;
  4282. +}
  4283. +
  4284. +/**
  4285. + * ssh_ctrl_packet_alloc() - Allocate control packet.
  4286. + * @packet: Where the pointer to the newly allocated packet should be stored.
  4287. + * @buffer: The buffer corresponding to this packet.
  4288. + * @flags: Flags used for allocation.
  4289. + *
  4290. + * Allocates a packet and corresponding transport buffer. Sets the packet's
  4291. + * buffer reference to the allocated buffer. The packet must be freed via
  4292. + * ssh_ctrl_packet_free(), which will also free the corresponding buffer. The
  4293. + * corresponding buffer must not be freed separately. Intended to be used with
  4294. + * %ssh_ptl_ctrl_packet_ops as packet operations.
  4295. + *
  4296. + * Return: Returns zero on success, %-ENOMEM if the allocation failed.
  4297. + */
  4298. +static int ssh_ctrl_packet_alloc(struct ssh_packet **packet,
  4299. + struct ssam_span *buffer, gfp_t flags)
  4300. +{
  4301. + *packet = kzalloc(sizeof(**packet) + SSH_MSG_LEN_CTRL, flags);
  4302. + if (!*packet)
  4303. + return -ENOMEM;
  4304. +
  4305. + buffer->ptr = (u8 *)(*packet + 1);
  4306. + buffer->len = SSH_MSG_LEN_CTRL;
  4307. +
  4308. + return 0;
  4309. +}
  4310. +
  4311. +/**
  4312. + * ssh_ctrl_packet_free() - Free control packet.
  4313. + * @p: The packet to free.
  4314. + */
  4315. +static void ssh_ctrl_packet_free(struct ssh_packet *p)
  4316. +{
  4317. + kfree(p);
  4318. +}
  4319. +
  4320. +static const struct ssh_packet_ops ssh_ptl_ctrl_packet_ops = {
  4321. + .complete = NULL,
  4322. + .release = ssh_ctrl_packet_free,
  4323. +};
  4324. +
  4325. +static void ssh_ptl_timeout_reaper_mod(struct ssh_ptl *ptl, ktime_t now,
  4326. + ktime_t expires)
  4327. +{
  4328. + unsigned long delta = msecs_to_jiffies(ktime_ms_delta(expires, now));
  4329. + ktime_t aexp = ktime_add(expires, SSH_PTL_PACKET_TIMEOUT_RESOLUTION);
  4330. +
  4331. + spin_lock(&ptl->rtx_timeout.lock);
  4332. +
  4333. + /* Re-adjust / schedule reaper only if it is above resolution delta. */
  4334. + if (ktime_before(aexp, ptl->rtx_timeout.expires)) {
  4335. + ptl->rtx_timeout.expires = expires;
  4336. + mod_delayed_work(system_wq, &ptl->rtx_timeout.reaper, delta);
  4337. + }
  4338. +
  4339. + spin_unlock(&ptl->rtx_timeout.lock);
  4340. +}
  4341. +
  4342. +/* Must be called with queue lock held. */
  4343. +static void ssh_packet_next_try(struct ssh_packet *p)
  4344. +{
  4345. + u8 base = ssh_packet_priority_get_base(p->priority);
  4346. + u8 try = ssh_packet_priority_get_try(p->priority);
  4347. +
  4348. + lockdep_assert_held(&p->ptl->queue.lock);
  4349. +
  4350. + p->priority = __SSH_PACKET_PRIORITY(base, try + 1);
  4351. +}
  4352. +
  4353. +/* Must be called with queue lock held. */
  4354. +static struct list_head *__ssh_ptl_queue_find_entrypoint(struct ssh_packet *p)
  4355. +{
  4356. + struct list_head *head;
  4357. + struct ssh_packet *q;
  4358. +
  4359. + lockdep_assert_held(&p->ptl->queue.lock);
  4360. +
  4361. + /*
  4362. + * We generally assume that there are less control (ACK/NAK) packets
  4363. + * and re-submitted data packets as there are normal data packets (at
  4364. + * least in situations in which many packets are queued; if there
  4365. + * aren't many packets queued the decision on how to iterate should be
  4366. + * basically irrelevant; the number of control/data packets is more or
  4367. + * less limited via the maximum number of pending packets). Thus, when
  4368. + * inserting a control or re-submitted data packet, (determined by
  4369. + * their priority), we search from front to back. Normal data packets
  4370. + * are, usually queued directly at the tail of the queue, so for those
  4371. + * search from back to front.
  4372. + */
  4373. +
  4374. + if (p->priority > SSH_PACKET_PRIORITY(DATA, 0)) {
  4375. + list_for_each(head, &p->ptl->queue.head) {
  4376. + q = list_entry(head, struct ssh_packet, queue_node);
  4377. +
  4378. + if (q->priority < p->priority)
  4379. + break;
  4380. + }
  4381. + } else {
  4382. + list_for_each_prev(head, &p->ptl->queue.head) {
  4383. + q = list_entry(head, struct ssh_packet, queue_node);
  4384. +
  4385. + if (q->priority >= p->priority) {
  4386. + head = head->next;
  4387. + break;
  4388. + }
  4389. + }
  4390. + }
  4391. +
  4392. + return head;
  4393. +}
  4394. +
  4395. +/* Must be called with queue lock held. */
  4396. +static int __ssh_ptl_queue_push(struct ssh_packet *packet)
  4397. +{
  4398. + struct ssh_ptl *ptl = packet->ptl;
  4399. + struct list_head *head;
  4400. +
  4401. + lockdep_assert_held(&ptl->queue.lock);
  4402. +
  4403. + if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state))
  4404. + return -ESHUTDOWN;
  4405. +
  4406. + /* Avoid further transitions when canceling/completing. */
  4407. + if (test_bit(SSH_PACKET_SF_LOCKED_BIT, &packet->state))
  4408. + return -EINVAL;
  4409. +
  4410. + /* If this packet has already been queued, do not add it. */
  4411. + if (test_and_set_bit(SSH_PACKET_SF_QUEUED_BIT, &packet->state))
  4412. + return -EALREADY;
  4413. +
  4414. + head = __ssh_ptl_queue_find_entrypoint(packet);
  4415. +
  4416. + list_add_tail(&ssh_packet_get(packet)->queue_node, head);
  4417. + return 0;
  4418. +}
  4419. +
  4420. +static int ssh_ptl_queue_push(struct ssh_packet *packet)
  4421. +{
  4422. + int status;
  4423. +
  4424. + spin_lock(&packet->ptl->queue.lock);
  4425. + status = __ssh_ptl_queue_push(packet);
  4426. + spin_unlock(&packet->ptl->queue.lock);
  4427. +
  4428. + return status;
  4429. +}
  4430. +
  4431. +static void ssh_ptl_queue_remove(struct ssh_packet *packet)
  4432. +{
  4433. + struct ssh_ptl *ptl = packet->ptl;
  4434. +
  4435. + spin_lock(&ptl->queue.lock);
  4436. +
  4437. + if (!test_and_clear_bit(SSH_PACKET_SF_QUEUED_BIT, &packet->state)) {
  4438. + spin_unlock(&ptl->queue.lock);
  4439. + return;
  4440. + }
  4441. +
  4442. + list_del(&packet->queue_node);
  4443. +
  4444. + spin_unlock(&ptl->queue.lock);
  4445. + ssh_packet_put(packet);
  4446. +}
  4447. +
  4448. +static void ssh_ptl_pending_push(struct ssh_packet *p)
  4449. +{
  4450. + struct ssh_ptl *ptl = p->ptl;
  4451. + const ktime_t timestamp = ktime_get_coarse_boottime();
  4452. + const ktime_t timeout = ptl->rtx_timeout.timeout;
  4453. +
  4454. + /*
  4455. + * Note: We can get the time for the timestamp before acquiring the
  4456. + * lock as this is the only place we're setting it and this function
  4457. + * is called only from the transmitter thread. Thus it is not possible
  4458. + * to overwrite the timestamp with an outdated value below.
  4459. + */
  4460. +
  4461. + spin_lock(&ptl->pending.lock);
  4462. +
  4463. + /* If we are canceling/completing this packet, do not add it. */
  4464. + if (test_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state)) {
  4465. + spin_unlock(&ptl->pending.lock);
  4466. + return;
  4467. + }
  4468. +
  4469. + /*
  4470. + * On re-submission, the packet has already been added the pending
  4471. + * set. We still need to update the timestamp as the packet timeout is
  4472. + * reset for each (re-)submission.
  4473. + */
  4474. + p->timestamp = timestamp;
  4475. +
  4476. + /* In case it is already pending (e.g. re-submission), do not add it. */
  4477. + if (!test_and_set_bit(SSH_PACKET_SF_PENDING_BIT, &p->state)) {
  4478. + atomic_inc(&ptl->pending.count);
  4479. + list_add_tail(&ssh_packet_get(p)->pending_node, &ptl->pending.head);
  4480. + }
  4481. +
  4482. + spin_unlock(&ptl->pending.lock);
  4483. +
  4484. + /* Arm/update timeout reaper. */
  4485. + ssh_ptl_timeout_reaper_mod(ptl, timestamp, timestamp + timeout);
  4486. +}
  4487. +
  4488. +static void ssh_ptl_pending_remove(struct ssh_packet *packet)
  4489. +{
  4490. + struct ssh_ptl *ptl = packet->ptl;
  4491. +
  4492. + spin_lock(&ptl->pending.lock);
  4493. +
  4494. + if (!test_and_clear_bit(SSH_PACKET_SF_PENDING_BIT, &packet->state)) {
  4495. + spin_unlock(&ptl->pending.lock);
  4496. + return;
  4497. + }
  4498. +
  4499. + list_del(&packet->pending_node);
  4500. + atomic_dec(&ptl->pending.count);
  4501. +
  4502. + spin_unlock(&ptl->pending.lock);
  4503. +
  4504. + ssh_packet_put(packet);
  4505. +}
  4506. +
  4507. +/* Warning: Does not check/set "completed" bit. */
  4508. +static void __ssh_ptl_complete(struct ssh_packet *p, int status)
  4509. +{
  4510. + struct ssh_ptl *ptl = READ_ONCE(p->ptl);
  4511. +
  4512. + ptl_dbg_cond(ptl, "ptl: completing packet %p (status: %d)\n", p, status);
  4513. +
  4514. + if (p->ops->complete)
  4515. + p->ops->complete(p, status);
  4516. +}
  4517. +
  4518. +static void ssh_ptl_remove_and_complete(struct ssh_packet *p, int status)
  4519. +{
  4520. + /*
  4521. + * A call to this function should in general be preceded by
  4522. + * set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->flags) to avoid re-adding the
  4523. + * packet to the structures it's going to be removed from.
  4524. + *
  4525. + * The set_bit call does not need explicit memory barriers as the
  4526. + * implicit barrier of the test_and_set_bit() call below ensure that the
  4527. + * flag is visible before we actually attempt to remove the packet.
  4528. + */
  4529. +
  4530. + if (test_and_set_bit(SSH_PACKET_SF_COMPLETED_BIT, &p->state))
  4531. + return;
  4532. +
  4533. + ssh_ptl_queue_remove(p);
  4534. + ssh_ptl_pending_remove(p);
  4535. +
  4536. + __ssh_ptl_complete(p, status);
  4537. +}
  4538. +
  4539. +static bool ssh_ptl_tx_can_process(struct ssh_packet *packet)
  4540. +{
  4541. + struct ssh_ptl *ptl = packet->ptl;
  4542. +
  4543. + if (test_bit(SSH_PACKET_TY_FLUSH_BIT, &packet->state))
  4544. + return !atomic_read(&ptl->pending.count);
  4545. +
  4546. + /* We can always process non-blocking packets. */
  4547. + if (!test_bit(SSH_PACKET_TY_BLOCKING_BIT, &packet->state))
  4548. + return true;
  4549. +
  4550. + /* If we are already waiting for this packet, send it again. */
  4551. + if (test_bit(SSH_PACKET_SF_PENDING_BIT, &packet->state))
  4552. + return true;
  4553. +
  4554. + /* Otherwise: Check if we have the capacity to send. */
  4555. + return atomic_read(&ptl->pending.count) < SSH_PTL_MAX_PENDING;
  4556. +}
  4557. +
  4558. +static struct ssh_packet *ssh_ptl_tx_pop(struct ssh_ptl *ptl)
  4559. +{
  4560. + struct ssh_packet *packet = ERR_PTR(-ENOENT);
  4561. + struct ssh_packet *p, *n;
  4562. +
  4563. + spin_lock(&ptl->queue.lock);
  4564. + list_for_each_entry_safe(p, n, &ptl->queue.head, queue_node) {
  4565. + /*
  4566. + * If we are canceling or completing this packet, ignore it.
  4567. + * It's going to be removed from this queue shortly.
  4568. + */
  4569. + if (test_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state))
  4570. + continue;
  4571. +
  4572. + /*
  4573. + * Packets should be ordered non-blocking/to-be-resent first.
  4574. + * If we cannot process this packet, assume that we can't
  4575. + * process any following packet either and abort.
  4576. + */
  4577. + if (!ssh_ptl_tx_can_process(p)) {
  4578. + packet = ERR_PTR(-EBUSY);
  4579. + break;
  4580. + }
  4581. +
  4582. + /*
  4583. + * We are allowed to change the state now. Remove it from the
  4584. + * queue and mark it as being transmitted.
  4585. + */
  4586. +
  4587. + list_del(&p->queue_node);
  4588. +
  4589. + set_bit(SSH_PACKET_SF_TRANSMITTING_BIT, &p->state);
  4590. + /* Ensure that state never gets zero. */
  4591. + smp_mb__before_atomic();
  4592. + clear_bit(SSH_PACKET_SF_QUEUED_BIT, &p->state);
  4593. +
  4594. + /*
  4595. + * Update number of tries. This directly influences the
  4596. + * priority in case the packet is re-submitted (e.g. via
  4597. + * timeout/NAK). Note that all reads and writes to the
  4598. + * priority after the first submission are guarded by the
  4599. + * queue lock.
  4600. + */
  4601. + ssh_packet_next_try(p);
  4602. +
  4603. + packet = p;
  4604. + break;
  4605. + }
  4606. + spin_unlock(&ptl->queue.lock);
  4607. +
  4608. + return packet;
  4609. +}
  4610. +
  4611. +static struct ssh_packet *ssh_ptl_tx_next(struct ssh_ptl *ptl)
  4612. +{
  4613. + struct ssh_packet *p;
  4614. +
  4615. + p = ssh_ptl_tx_pop(ptl);
  4616. + if (IS_ERR(p))
  4617. + return p;
  4618. +
  4619. + if (test_bit(SSH_PACKET_TY_SEQUENCED_BIT, &p->state)) {
  4620. + ptl_dbg(ptl, "ptl: transmitting sequenced packet %p\n", p);
  4621. + ssh_ptl_pending_push(p);
  4622. + } else {
  4623. + ptl_dbg(ptl, "ptl: transmitting non-sequenced packet %p\n", p);
  4624. + }
  4625. +
  4626. + return p;
  4627. +}
  4628. +
  4629. +static void ssh_ptl_tx_compl_success(struct ssh_packet *packet)
  4630. +{
  4631. + struct ssh_ptl *ptl = packet->ptl;
  4632. +
  4633. + ptl_dbg(ptl, "ptl: successfully transmitted packet %p\n", packet);
  4634. +
  4635. + /* Transition state to "transmitted". */
  4636. + set_bit(SSH_PACKET_SF_TRANSMITTED_BIT, &packet->state);
  4637. + /* Ensure that state never gets zero. */
  4638. + smp_mb__before_atomic();
  4639. + clear_bit(SSH_PACKET_SF_TRANSMITTING_BIT, &packet->state);
  4640. +
  4641. + /* If the packet is unsequenced, we're done: Lock and complete. */
  4642. + if (!test_bit(SSH_PACKET_TY_SEQUENCED_BIT, &packet->state)) {
  4643. + set_bit(SSH_PACKET_SF_LOCKED_BIT, &packet->state);
  4644. + ssh_ptl_remove_and_complete(packet, 0);
  4645. + }
  4646. +
  4647. + /*
  4648. + * Notify that a packet transmission has finished. In general we're only
  4649. + * waiting for one packet (if any), so wake_up_all should be fine.
  4650. + */
  4651. + wake_up_all(&ptl->tx.packet_wq);
  4652. +}
  4653. +
  4654. +static void ssh_ptl_tx_compl_error(struct ssh_packet *packet, int status)
  4655. +{
  4656. + /* Transmission failure: Lock the packet and try to complete it. */
  4657. + set_bit(SSH_PACKET_SF_LOCKED_BIT, &packet->state);
  4658. + /* Ensure that state never gets zero. */
  4659. + smp_mb__before_atomic();
  4660. + clear_bit(SSH_PACKET_SF_TRANSMITTING_BIT, &packet->state);
  4661. +
  4662. + ptl_err(packet->ptl, "ptl: transmission error: %d\n", status);
  4663. + ptl_dbg(packet->ptl, "ptl: failed to transmit packet: %p\n", packet);
  4664. +
  4665. + ssh_ptl_remove_and_complete(packet, status);
  4666. +
  4667. + /*
  4668. + * Notify that a packet transmission has finished. In general we're only
  4669. + * waiting for one packet (if any), so wake_up_all should be fine.
  4670. + */
  4671. + wake_up_all(&packet->ptl->tx.packet_wq);
  4672. +}
  4673. +
  4674. +static long ssh_ptl_tx_wait_packet(struct ssh_ptl *ptl)
  4675. +{
  4676. + int status;
  4677. +
  4678. + status = wait_for_completion_interruptible(&ptl->tx.thread_cplt_pkt);
  4679. + reinit_completion(&ptl->tx.thread_cplt_pkt);
  4680. +
  4681. + /*
  4682. + * Ensure completion is cleared before continuing to avoid lost update
  4683. + * problems.
  4684. + */
  4685. + smp_mb__after_atomic();
  4686. +
  4687. + return status;
  4688. +}
  4689. +
  4690. +static long ssh_ptl_tx_wait_transfer(struct ssh_ptl *ptl, long timeout)
  4691. +{
  4692. + long status;
  4693. +
  4694. + status = wait_for_completion_interruptible_timeout(&ptl->tx.thread_cplt_tx,
  4695. + timeout);
  4696. + reinit_completion(&ptl->tx.thread_cplt_tx);
  4697. +
  4698. + /*
  4699. + * Ensure completion is cleared before continuing to avoid lost update
  4700. + * problems.
  4701. + */
  4702. + smp_mb__after_atomic();
  4703. +
  4704. + return status;
  4705. +}
  4706. +
  4707. +static int ssh_ptl_tx_packet(struct ssh_ptl *ptl, struct ssh_packet *packet)
  4708. +{
  4709. + long timeout = SSH_PTL_TX_TIMEOUT;
  4710. + size_t offset = 0;
  4711. +
  4712. + /* Note: Flush-packets don't have any data. */
  4713. + if (unlikely(!packet->data.ptr))
  4714. + return 0;
  4715. +
  4716. + ptl_dbg(ptl, "tx: sending data (length: %zu)\n", packet->data.len);
  4717. + print_hex_dump_debug("tx: ", DUMP_PREFIX_OFFSET, 16, 1,
  4718. + packet->data.ptr, packet->data.len, false);
  4719. +
  4720. + do {
  4721. + ssize_t status, len;
  4722. + u8 *buf;
  4723. +
  4724. + buf = packet->data.ptr + offset;
  4725. + len = packet->data.len - offset;
  4726. +
  4727. + status = serdev_device_write_buf(ptl->serdev, buf, len);
  4728. + if (status < 0)
  4729. + return status;
  4730. +
  4731. + if (status == len)
  4732. + return 0;
  4733. +
  4734. + offset += status;
  4735. +
  4736. + timeout = ssh_ptl_tx_wait_transfer(ptl, timeout);
  4737. + if (kthread_should_stop() || !atomic_read(&ptl->tx.running))
  4738. + return -ESHUTDOWN;
  4739. +
  4740. + if (timeout < 0)
  4741. + return -EINTR;
  4742. +
  4743. + if (timeout == 0)
  4744. + return -ETIMEDOUT;
  4745. + } while (true);
  4746. +}
  4747. +
  4748. +static int ssh_ptl_tx_threadfn(void *data)
  4749. +{
  4750. + struct ssh_ptl *ptl = data;
  4751. +
  4752. + while (!kthread_should_stop() && atomic_read(&ptl->tx.running)) {
  4753. + struct ssh_packet *packet;
  4754. + int status;
  4755. +
  4756. + /* Try to get the next packet. */
  4757. + packet = ssh_ptl_tx_next(ptl);
  4758. +
  4759. + /* If no packet can be processed, we are done. */
  4760. + if (IS_ERR(packet)) {
  4761. + ssh_ptl_tx_wait_packet(ptl);
  4762. + continue;
  4763. + }
  4764. +
  4765. + /* Transfer and complete packet. */
  4766. + status = ssh_ptl_tx_packet(ptl, packet);
  4767. + if (status)
  4768. + ssh_ptl_tx_compl_error(packet, status);
  4769. + else
  4770. + ssh_ptl_tx_compl_success(packet);
  4771. +
  4772. + ssh_packet_put(packet);
  4773. + }
  4774. +
  4775. + return 0;
  4776. +}
  4777. +
  4778. +/**
  4779. + * ssh_ptl_tx_wakeup_packet() - Wake up packet transmitter thread for new
  4780. + * packet.
  4781. + * @ptl: The packet transport layer.
  4782. + *
  4783. + * Wakes up the packet transmitter thread, notifying it that a new packet has
  4784. + * arrived and is ready for transfer. If the packet transport layer has been
  4785. + * shut down, calls to this function will be ignored.
  4786. + */
  4787. +static void ssh_ptl_tx_wakeup_packet(struct ssh_ptl *ptl)
  4788. +{
  4789. + if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state))
  4790. + return;
  4791. +
  4792. + complete(&ptl->tx.thread_cplt_pkt);
  4793. +}
  4794. +
  4795. +/**
  4796. + * ssh_ptl_tx_start() - Start packet transmitter thread.
  4797. + * @ptl: The packet transport layer.
  4798. + *
  4799. + * Return: Returns zero on success, a negative error code on failure.
  4800. + */
  4801. +int ssh_ptl_tx_start(struct ssh_ptl *ptl)
  4802. +{
  4803. + atomic_set_release(&ptl->tx.running, 1);
  4804. +
  4805. + ptl->tx.thread = kthread_run(ssh_ptl_tx_threadfn, ptl, "ssam_serial_hub-tx");
  4806. + if (IS_ERR(ptl->tx.thread))
  4807. + return PTR_ERR(ptl->tx.thread);
  4808. +
  4809. + return 0;
  4810. +}
  4811. +
  4812. +/**
  4813. + * ssh_ptl_tx_stop() - Stop packet transmitter thread.
  4814. + * @ptl: The packet transport layer.
  4815. + *
  4816. + * Return: Returns zero on success, a negative error code on failure.
  4817. + */
  4818. +int ssh_ptl_tx_stop(struct ssh_ptl *ptl)
  4819. +{
  4820. + int status = 0;
  4821. +
  4822. + if (!IS_ERR_OR_NULL(ptl->tx.thread)) {
  4823. + /* Tell thread to stop. */
  4824. + atomic_set_release(&ptl->tx.running, 0);
  4825. +
  4826. + /*
  4827. + * Wake up thread in case it is paused. Do not use wakeup
  4828. + * helpers as this may be called when the shutdown bit has
  4829. + * already been set.
  4830. + */
  4831. + complete(&ptl->tx.thread_cplt_pkt);
  4832. + complete(&ptl->tx.thread_cplt_tx);
  4833. +
  4834. + /* Finally, wait for thread to stop. */
  4835. + status = kthread_stop(ptl->tx.thread);
  4836. + ptl->tx.thread = NULL;
  4837. + }
  4838. +
  4839. + return status;
  4840. +}
  4841. +
  4842. +static struct ssh_packet *ssh_ptl_ack_pop(struct ssh_ptl *ptl, u8 seq_id)
  4843. +{
  4844. + struct ssh_packet *packet = ERR_PTR(-ENOENT);
  4845. + struct ssh_packet *p, *n;
  4846. +
  4847. + spin_lock(&ptl->pending.lock);
  4848. + list_for_each_entry_safe(p, n, &ptl->pending.head, pending_node) {
  4849. + /*
  4850. + * We generally expect packets to be in order, so first packet
  4851. + * to be added to pending is first to be sent, is first to be
  4852. + * ACKed.
  4853. + */
  4854. + if (unlikely(ssh_packet_get_seq(p) != seq_id))
  4855. + continue;
  4856. +
  4857. + /*
  4858. + * In case we receive an ACK while handling a transmission
  4859. + * error completion. The packet will be removed shortly.
  4860. + */
  4861. + if (unlikely(test_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state))) {
  4862. + packet = ERR_PTR(-EPERM);
  4863. + break;
  4864. + }
  4865. +
  4866. + /*
  4867. + * Mark the packet as ACKed and remove it from pending by
  4868. + * removing its node and decrementing the pending counter.
  4869. + */
  4870. + set_bit(SSH_PACKET_SF_ACKED_BIT, &p->state);
  4871. + /* Ensure that state never gets zero. */
  4872. + smp_mb__before_atomic();
  4873. + clear_bit(SSH_PACKET_SF_PENDING_BIT, &p->state);
  4874. +
  4875. + atomic_dec(&ptl->pending.count);
  4876. + list_del(&p->pending_node);
  4877. + packet = p;
  4878. +
  4879. + break;
  4880. + }
  4881. + spin_unlock(&ptl->pending.lock);
  4882. +
  4883. + return packet;
  4884. +}
  4885. +
  4886. +static void ssh_ptl_wait_until_transmitted(struct ssh_packet *packet)
  4887. +{
  4888. + wait_event(packet->ptl->tx.packet_wq,
  4889. + test_bit(SSH_PACKET_SF_TRANSMITTED_BIT, &packet->state) ||
  4890. + test_bit(SSH_PACKET_SF_LOCKED_BIT, &packet->state));
  4891. +}
  4892. +
  4893. +static void ssh_ptl_acknowledge(struct ssh_ptl *ptl, u8 seq)
  4894. +{
  4895. + struct ssh_packet *p;
  4896. +
  4897. + p = ssh_ptl_ack_pop(ptl, seq);
  4898. + if (IS_ERR(p)) {
  4899. + if (PTR_ERR(p) == -ENOENT) {
  4900. + /*
  4901. + * The packet has not been found in the set of pending
  4902. + * packets.
  4903. + */
  4904. + ptl_warn(ptl, "ptl: received ACK for non-pending packet\n");
  4905. + } else {
  4906. + /*
  4907. + * The packet is pending, but we are not allowed to take
  4908. + * it because it has been locked.
  4909. + */
  4910. + WARN_ON(PTR_ERR(p) != -EPERM);
  4911. + }
  4912. + return;
  4913. + }
  4914. +
  4915. + ptl_dbg(ptl, "ptl: received ACK for packet %p\n", p);
  4916. +
  4917. + /*
  4918. + * It is possible that the packet has been transmitted, but the state
  4919. + * has not been updated from "transmitting" to "transmitted" yet.
  4920. + * In that case, we need to wait for this transition to occur in order
  4921. + * to determine between success or failure.
  4922. + *
  4923. + * On transmission failure, the packet will be locked after this call.
  4924. + * On success, the transmitted bit will be set.
  4925. + */
  4926. + ssh_ptl_wait_until_transmitted(p);
  4927. +
  4928. + /*
  4929. + * The packet will already be locked in case of a transmission error or
  4930. + * cancellation. Let the transmitter or cancellation issuer complete the
  4931. + * packet.
  4932. + */
  4933. + if (unlikely(test_and_set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state))) {
  4934. + if (unlikely(!test_bit(SSH_PACKET_SF_TRANSMITTED_BIT, &p->state)))
  4935. + ptl_err(ptl, "ptl: received ACK before packet had been fully transmitted\n");
  4936. +
  4937. + ssh_packet_put(p);
  4938. + return;
  4939. + }
  4940. +
  4941. + ssh_ptl_remove_and_complete(p, 0);
  4942. + ssh_packet_put(p);
  4943. +
  4944. + if (atomic_read(&ptl->pending.count) < SSH_PTL_MAX_PENDING)
  4945. + ssh_ptl_tx_wakeup_packet(ptl);
  4946. +}
  4947. +
  4948. +/**
  4949. + * ssh_ptl_submit() - Submit a packet to the transport layer.
  4950. + * @ptl: The packet transport layer to submit the packet to.
  4951. + * @p: The packet to submit.
  4952. + *
  4953. + * Submits a new packet to the transport layer, queuing it to be sent. This
  4954. + * function should not be used for re-submission.
  4955. + *
  4956. + * Return: Returns zero on success, %-EINVAL if a packet field is invalid or
  4957. + * the packet has been canceled prior to submission, %-EALREADY if the packet
  4958. + * has already been submitted, or %-ESHUTDOWN if the packet transport layer
  4959. + * has been shut down.
  4960. + */
  4961. +int ssh_ptl_submit(struct ssh_ptl *ptl, struct ssh_packet *p)
  4962. +{
  4963. + struct ssh_ptl *ptl_old;
  4964. + int status;
  4965. +
  4966. + /* Validate packet fields. */
  4967. + if (test_bit(SSH_PACKET_TY_FLUSH_BIT, &p->state)) {
  4968. + if (p->data.ptr || test_bit(SSH_PACKET_TY_SEQUENCED_BIT, &p->state))
  4969. + return -EINVAL;
  4970. + } else if (!p->data.ptr) {
  4971. + return -EINVAL;
  4972. + }
  4973. +
  4974. + /*
  4975. + * The ptl reference only gets set on or before the first submission.
  4976. + * After the first submission, it has to be read-only.
  4977. + *
  4978. + * Note that ptl may already be set from upper-layer request
  4979. + * submission, thus we cannot expect it to be NULL.
  4980. + */
  4981. + ptl_old = READ_ONCE(p->ptl);
  4982. + if (!ptl_old)
  4983. + WRITE_ONCE(p->ptl, ptl);
  4984. + else if (WARN_ON(ptl_old != ptl))
  4985. + return -EALREADY; /* Submitted on different PTL. */
  4986. +
  4987. + status = ssh_ptl_queue_push(p);
  4988. + if (status)
  4989. + return status;
  4990. +
  4991. + if (!test_bit(SSH_PACKET_TY_BLOCKING_BIT, &p->state) ||
  4992. + (atomic_read(&ptl->pending.count) < SSH_PTL_MAX_PENDING))
  4993. + ssh_ptl_tx_wakeup_packet(ptl);
  4994. +
  4995. + return 0;
  4996. +}
  4997. +
  4998. +/*
  4999. + * __ssh_ptl_resubmit() - Re-submit a packet to the transport layer.
  5000. + * @packet: The packet to re-submit.
  5001. + *
  5002. + * Re-submits the given packet: Checks if it can be re-submitted and queues it
  5003. + * if it can, resetting the packet timestamp in the process. Must be called
  5004. + * with the pending lock held.
  5005. + *
  5006. + * Return: Returns %-ECANCELED if the packet has exceeded its number of tries,
  5007. + * %-EINVAL if the packet has been locked, %-EALREADY if the packet is already
  5008. + * on the queue, and %-ESHUTDOWN if the transmission layer has been shut down.
  5009. + */
  5010. +static int __ssh_ptl_resubmit(struct ssh_packet *packet)
  5011. +{
  5012. + int status;
  5013. + u8 try;
  5014. +
  5015. + lockdep_assert_held(&packet->ptl->pending.lock);
  5016. +
  5017. + spin_lock(&packet->ptl->queue.lock);
  5018. +
  5019. + /* Check if the packet is out of tries. */
  5020. + try = ssh_packet_priority_get_try(packet->priority);
  5021. + if (try >= SSH_PTL_MAX_PACKET_TRIES) {
  5022. + spin_unlock(&packet->ptl->queue.lock);
  5023. + return -ECANCELED;
  5024. + }
  5025. +
  5026. + status = __ssh_ptl_queue_push(packet);
  5027. + if (status) {
  5028. + /*
  5029. + * An error here indicates that the packet has either already
  5030. + * been queued, been locked, or the transport layer is being
  5031. + * shut down. In all cases: Ignore the error.
  5032. + */
  5033. + spin_unlock(&packet->ptl->queue.lock);
  5034. + return status;
  5035. + }
  5036. +
  5037. + packet->timestamp = KTIME_MAX;
  5038. +
  5039. + spin_unlock(&packet->ptl->queue.lock);
  5040. + return 0;
  5041. +}
  5042. +
  5043. +static void ssh_ptl_resubmit_pending(struct ssh_ptl *ptl)
  5044. +{
  5045. + struct ssh_packet *p;
  5046. + bool resub = false;
  5047. +
  5048. + /*
  5049. + * Note: We deliberately do not remove/attempt to cancel and complete
  5050. + * packets that are out of tires in this function. The packet will be
  5051. + * eventually canceled and completed by the timeout. Removing the packet
  5052. + * here could lead to overly eager cancellation if the packet has not
  5053. + * been re-transmitted yet but the tries-counter already updated (i.e
  5054. + * ssh_ptl_tx_next() removed the packet from the queue and updated the
  5055. + * counter, but re-transmission for the last try has not actually
  5056. + * started yet).
  5057. + */
  5058. +
  5059. + spin_lock(&ptl->pending.lock);
  5060. +
  5061. + /* Re-queue all pending packets. */
  5062. + list_for_each_entry(p, &ptl->pending.head, pending_node) {
  5063. + /*
  5064. + * Re-submission fails if the packet is out of tries, has been
  5065. + * locked, is already queued, or the layer is being shut down.
  5066. + * No need to re-schedule tx-thread in those cases.
  5067. + */
  5068. + if (!__ssh_ptl_resubmit(p))
  5069. + resub = true;
  5070. + }
  5071. +
  5072. + spin_unlock(&ptl->pending.lock);
  5073. +
  5074. + if (resub)
  5075. + ssh_ptl_tx_wakeup_packet(ptl);
  5076. +}
  5077. +
  5078. +/**
  5079. + * ssh_ptl_cancel() - Cancel a packet.
  5080. + * @p: The packet to cancel.
  5081. + *
  5082. + * Cancels a packet. There are no guarantees on when completion and release
  5083. + * callbacks will be called. This may occur during execution of this function
  5084. + * or may occur at any point later.
  5085. + *
  5086. + * Note that it is not guaranteed that the packet will actually be canceled if
  5087. + * the packet is concurrently completed by another process. The only guarantee
  5088. + * of this function is that the packet will be completed (with success,
  5089. + * failure, or cancellation) and released from the transport layer in a
  5090. + * reasonable time-frame.
  5091. + *
  5092. + * May be called before the packet has been submitted, in which case any later
  5093. + * packet submission fails.
  5094. + */
  5095. +void ssh_ptl_cancel(struct ssh_packet *p)
  5096. +{
  5097. + if (test_and_set_bit(SSH_PACKET_SF_CANCELED_BIT, &p->state))
  5098. + return;
  5099. +
  5100. + /*
  5101. + * Lock packet and commit with memory barrier. If this packet has
  5102. + * already been locked, it's going to be removed and completed by
  5103. + * another party, which should have precedence.
  5104. + */
  5105. + if (test_and_set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state))
  5106. + return;
  5107. +
  5108. + /*
  5109. + * By marking the packet as locked and employing the implicit memory
  5110. + * barrier of test_and_set_bit, we have guaranteed that, at this point,
  5111. + * the packet cannot be added to the queue any more.
  5112. + *
  5113. + * In case the packet has never been submitted, packet->ptl is NULL. If
  5114. + * the packet is currently being submitted, packet->ptl may be NULL or
  5115. + * non-NULL. Due marking the packet as locked above and committing with
  5116. + * the memory barrier, we have guaranteed that, if packet->ptl is NULL,
  5117. + * the packet will never be added to the queue. If packet->ptl is
  5118. + * non-NULL, we don't have any guarantees.
  5119. + */
  5120. +
  5121. + if (READ_ONCE(p->ptl)) {
  5122. + ssh_ptl_remove_and_complete(p, -ECANCELED);
  5123. +
  5124. + if (atomic_read(&p->ptl->pending.count) < SSH_PTL_MAX_PENDING)
  5125. + ssh_ptl_tx_wakeup_packet(p->ptl);
  5126. +
  5127. + } else if (!test_and_set_bit(SSH_PACKET_SF_COMPLETED_BIT, &p->state)) {
  5128. + __ssh_ptl_complete(p, -ECANCELED);
  5129. + }
  5130. +}
  5131. +
  5132. +/* Must be called with pending lock held */
  5133. +static ktime_t ssh_packet_get_expiration(struct ssh_packet *p, ktime_t timeout)
  5134. +{
  5135. + lockdep_assert_held(&p->ptl->pending.lock);
  5136. +
  5137. + if (p->timestamp != KTIME_MAX)
  5138. + return ktime_add(p->timestamp, timeout);
  5139. + else
  5140. + return KTIME_MAX;
  5141. +}
  5142. +
  5143. +static void ssh_ptl_timeout_reap(struct work_struct *work)
  5144. +{
  5145. + struct ssh_ptl *ptl = to_ssh_ptl(work, rtx_timeout.reaper.work);
  5146. + struct ssh_packet *p, *n;
  5147. + LIST_HEAD(claimed);
  5148. + ktime_t now = ktime_get_coarse_boottime();
  5149. + ktime_t timeout = ptl->rtx_timeout.timeout;
  5150. + ktime_t next = KTIME_MAX;
  5151. + bool resub = false;
  5152. + int status;
  5153. +
  5154. + /*
  5155. + * Mark reaper as "not pending". This is done before checking any
  5156. + * packets to avoid lost-update type problems.
  5157. + */
  5158. + spin_lock(&ptl->rtx_timeout.lock);
  5159. + ptl->rtx_timeout.expires = KTIME_MAX;
  5160. + spin_unlock(&ptl->rtx_timeout.lock);
  5161. +
  5162. + spin_lock(&ptl->pending.lock);
  5163. +
  5164. + list_for_each_entry_safe(p, n, &ptl->pending.head, pending_node) {
  5165. + ktime_t expires = ssh_packet_get_expiration(p, timeout);
  5166. +
  5167. + /*
  5168. + * Check if the timeout hasn't expired yet. Find out next
  5169. + * expiration date to be handled after this run.
  5170. + */
  5171. + if (ktime_after(expires, now)) {
  5172. + next = ktime_before(expires, next) ? expires : next;
  5173. + continue;
  5174. + }
  5175. +
  5176. + status = __ssh_ptl_resubmit(p);
  5177. +
  5178. + /*
  5179. + * Re-submission fails if the packet is out of tries, has been
  5180. + * locked, is already queued, or the layer is being shut down.
  5181. + * No need to re-schedule tx-thread in those cases.
  5182. + */
  5183. + if (!status)
  5184. + resub = true;
  5185. +
  5186. + /* Go to next packet if this packet is not out of tries. */
  5187. + if (status != -ECANCELED)
  5188. + continue;
  5189. +
  5190. + /* No more tries left: Cancel the packet. */
  5191. +
  5192. + /*
  5193. + * If someone else has locked the packet already, don't use it
  5194. + * and let the other party complete it.
  5195. + */
  5196. + if (test_and_set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state))
  5197. + continue;
  5198. +
  5199. + /*
  5200. + * We have now marked the packet as locked. Thus it cannot be
  5201. + * added to the pending list again after we've removed it here.
  5202. + * We can therefore re-use the pending_node of this packet
  5203. + * temporarily.
  5204. + */
  5205. +
  5206. + clear_bit(SSH_PACKET_SF_PENDING_BIT, &p->state);
  5207. +
  5208. + atomic_dec(&ptl->pending.count);
  5209. + list_del(&p->pending_node);
  5210. +
  5211. + list_add_tail(&p->pending_node, &claimed);
  5212. + }
  5213. +
  5214. + spin_unlock(&ptl->pending.lock);
  5215. +
  5216. + /* Cancel and complete the packet. */
  5217. + list_for_each_entry_safe(p, n, &claimed, pending_node) {
  5218. + if (!test_and_set_bit(SSH_PACKET_SF_COMPLETED_BIT, &p->state)) {
  5219. + ssh_ptl_queue_remove(p);
  5220. + __ssh_ptl_complete(p, -ETIMEDOUT);
  5221. + }
  5222. +
  5223. + /*
  5224. + * Drop the reference we've obtained by removing it from
  5225. + * the pending set.
  5226. + */
  5227. + list_del(&p->pending_node);
  5228. + ssh_packet_put(p);
  5229. + }
  5230. +
  5231. + /* Ensure that reaper doesn't run again immediately. */
  5232. + next = max(next, ktime_add(now, SSH_PTL_PACKET_TIMEOUT_RESOLUTION));
  5233. + if (next != KTIME_MAX)
  5234. + ssh_ptl_timeout_reaper_mod(ptl, now, next);
  5235. +
  5236. + if (resub)
  5237. + ssh_ptl_tx_wakeup_packet(ptl);
  5238. +}
  5239. +
  5240. +static bool ssh_ptl_rx_retransmit_check(struct ssh_ptl *ptl, u8 seq)
  5241. +{
  5242. + int i;
  5243. +
  5244. + /*
  5245. + * Check if SEQ has been seen recently (i.e. packet was
  5246. + * re-transmitted and we should ignore it).
  5247. + */
  5248. + for (i = 0; i < ARRAY_SIZE(ptl->rx.blocked.seqs); i++) {
  5249. + if (likely(ptl->rx.blocked.seqs[i] != seq))
  5250. + continue;
  5251. +
  5252. + ptl_dbg(ptl, "ptl: ignoring repeated data packet\n");
  5253. + return true;
  5254. + }
  5255. +
  5256. + /* Update list of blocked sequence IDs. */
  5257. + ptl->rx.blocked.seqs[ptl->rx.blocked.offset] = seq;
  5258. + ptl->rx.blocked.offset = (ptl->rx.blocked.offset + 1)
  5259. + % ARRAY_SIZE(ptl->rx.blocked.seqs);
  5260. +
  5261. + return false;
  5262. +}
  5263. +
  5264. +static void ssh_ptl_rx_dataframe(struct ssh_ptl *ptl,
  5265. + const struct ssh_frame *frame,
  5266. + const struct ssam_span *payload)
  5267. +{
  5268. + if (ssh_ptl_rx_retransmit_check(ptl, frame->seq))
  5269. + return;
  5270. +
  5271. + ptl->ops.data_received(ptl, payload);
  5272. +}
  5273. +
  5274. +static void ssh_ptl_send_ack(struct ssh_ptl *ptl, u8 seq)
  5275. +{
  5276. + struct ssh_packet *packet;
  5277. + struct ssam_span buf;
  5278. + struct msgbuf msgb;
  5279. + int status;
  5280. +
  5281. + status = ssh_ctrl_packet_alloc(&packet, &buf, GFP_KERNEL);
  5282. + if (status) {
  5283. + ptl_err(ptl, "ptl: failed to allocate ACK packet\n");
  5284. + return;
  5285. + }
  5286. +
  5287. + ssh_packet_init(packet, 0, SSH_PACKET_PRIORITY(ACK, 0),
  5288. + &ssh_ptl_ctrl_packet_ops);
  5289. +
  5290. + msgb_init(&msgb, buf.ptr, buf.len);
  5291. + msgb_push_ack(&msgb, seq);
  5292. + ssh_packet_set_data(packet, msgb.begin, msgb_bytes_used(&msgb));
  5293. +
  5294. + ssh_ptl_submit(ptl, packet);
  5295. + ssh_packet_put(packet);
  5296. +}
  5297. +
  5298. +static void ssh_ptl_send_nak(struct ssh_ptl *ptl)
  5299. +{
  5300. + struct ssh_packet *packet;
  5301. + struct ssam_span buf;
  5302. + struct msgbuf msgb;
  5303. + int status;
  5304. +
  5305. + status = ssh_ctrl_packet_alloc(&packet, &buf, GFP_KERNEL);
  5306. + if (status) {
  5307. + ptl_err(ptl, "ptl: failed to allocate NAK packet\n");
  5308. + return;
  5309. + }
  5310. +
  5311. + ssh_packet_init(packet, 0, SSH_PACKET_PRIORITY(NAK, 0),
  5312. + &ssh_ptl_ctrl_packet_ops);
  5313. +
  5314. + msgb_init(&msgb, buf.ptr, buf.len);
  5315. + msgb_push_nak(&msgb);
  5316. + ssh_packet_set_data(packet, msgb.begin, msgb_bytes_used(&msgb));
  5317. +
  5318. + ssh_ptl_submit(ptl, packet);
  5319. + ssh_packet_put(packet);
  5320. +}
  5321. +
  5322. +static size_t ssh_ptl_rx_eval(struct ssh_ptl *ptl, struct ssam_span *source)
  5323. +{
  5324. + struct ssh_frame *frame;
  5325. + struct ssam_span payload;
  5326. + struct ssam_span aligned;
  5327. + bool syn_found;
  5328. + int status;
  5329. +
  5330. + /* Find SYN. */
  5331. + syn_found = sshp_find_syn(source, &aligned);
  5332. +
  5333. + if (unlikely(aligned.ptr - source->ptr) > 0) {
  5334. + ptl_warn(ptl, "rx: parser: invalid start of frame, skipping\n");
  5335. +
  5336. + /*
  5337. + * Notes:
  5338. + * - This might send multiple NAKs in case the communication
  5339. + * starts with an invalid SYN and is broken down into multiple
  5340. + * pieces. This should generally be handled fine, we just
  5341. + * might receive duplicate data in this case, which is
  5342. + * detected when handling data frames.
  5343. + * - This path will also be executed on invalid CRCs: When an
  5344. + * invalid CRC is encountered, the code below will skip data
  5345. + * until directly after the SYN. This causes the search for
  5346. + * the next SYN, which is generally not placed directly after
  5347. + * the last one.
  5348. + *
  5349. + * Open question: Should we send this in case of invalid
  5350. + * payload CRCs if the frame-type is non-sequential (current
  5351. + * implementation) or should we drop that frame without
  5352. + * telling the EC?
  5353. + */
  5354. + ssh_ptl_send_nak(ptl);
  5355. + }
  5356. +
  5357. + if (unlikely(!syn_found))
  5358. + return aligned.ptr - source->ptr;
  5359. +
  5360. + /* Parse and validate frame. */
  5361. + status = sshp_parse_frame(&ptl->serdev->dev, &aligned, &frame, &payload,
  5362. + SSH_PTL_RX_BUF_LEN);
  5363. + if (status) /* Invalid frame: skip to next SYN. */
  5364. + return aligned.ptr - source->ptr + sizeof(u16);
  5365. + if (!frame) /* Not enough data. */
  5366. + return aligned.ptr - source->ptr;
  5367. +
  5368. + switch (frame->type) {
  5369. + case SSH_FRAME_TYPE_ACK:
  5370. + ssh_ptl_acknowledge(ptl, frame->seq);
  5371. + break;
  5372. +
  5373. + case SSH_FRAME_TYPE_NAK:
  5374. + ssh_ptl_resubmit_pending(ptl);
  5375. + break;
  5376. +
  5377. + case SSH_FRAME_TYPE_DATA_SEQ:
  5378. + ssh_ptl_send_ack(ptl, frame->seq);
  5379. + fallthrough;
  5380. +
  5381. + case SSH_FRAME_TYPE_DATA_NSQ:
  5382. + ssh_ptl_rx_dataframe(ptl, frame, &payload);
  5383. + break;
  5384. +
  5385. + default:
  5386. + ptl_warn(ptl, "ptl: received frame with unknown type %#04x\n",
  5387. + frame->type);
  5388. + break;
  5389. + }
  5390. +
  5391. + return aligned.ptr - source->ptr + SSH_MESSAGE_LENGTH(frame->len);
  5392. +}
  5393. +
  5394. +static int ssh_ptl_rx_threadfn(void *data)
  5395. +{
  5396. + struct ssh_ptl *ptl = data;
  5397. +
  5398. + while (true) {
  5399. + struct ssam_span span;
  5400. + size_t offs = 0;
  5401. + size_t n;
  5402. +
  5403. + wait_event_interruptible(ptl->rx.wq,
  5404. + !kfifo_is_empty(&ptl->rx.fifo) ||
  5405. + kthread_should_stop());
  5406. + if (kthread_should_stop())
  5407. + break;
  5408. +
  5409. + /* Copy from fifo to evaluation buffer. */
  5410. + n = sshp_buf_read_from_fifo(&ptl->rx.buf, &ptl->rx.fifo);
  5411. +
  5412. + ptl_dbg(ptl, "rx: received data (size: %zu)\n", n);
  5413. + print_hex_dump_debug("rx: ", DUMP_PREFIX_OFFSET, 16, 1,
  5414. + ptl->rx.buf.ptr + ptl->rx.buf.len - n,
  5415. + n, false);
  5416. +
  5417. + /* Parse until we need more bytes or buffer is empty. */
  5418. + while (offs < ptl->rx.buf.len) {
  5419. + sshp_buf_span_from(&ptl->rx.buf, offs, &span);
  5420. + n = ssh_ptl_rx_eval(ptl, &span);
  5421. + if (n == 0)
  5422. + break; /* Need more bytes. */
  5423. +
  5424. + offs += n;
  5425. + }
  5426. +
  5427. + /* Throw away the evaluated parts. */
  5428. + sshp_buf_drop(&ptl->rx.buf, offs);
  5429. + }
  5430. +
  5431. + return 0;
  5432. +}
  5433. +
  5434. +static void ssh_ptl_rx_wakeup(struct ssh_ptl *ptl)
  5435. +{
  5436. + wake_up(&ptl->rx.wq);
  5437. +}
  5438. +
  5439. +/**
  5440. + * ssh_ptl_rx_start() - Start packet transport layer receiver thread.
  5441. + * @ptl: The packet transport layer.
  5442. + *
  5443. + * Return: Returns zero on success, a negative error code on failure.
  5444. + */
  5445. +int ssh_ptl_rx_start(struct ssh_ptl *ptl)
  5446. +{
  5447. + if (ptl->rx.thread)
  5448. + return 0;
  5449. +
  5450. + ptl->rx.thread = kthread_run(ssh_ptl_rx_threadfn, ptl,
  5451. + "ssam_serial_hub-rx");
  5452. + if (IS_ERR(ptl->rx.thread))
  5453. + return PTR_ERR(ptl->rx.thread);
  5454. +
  5455. + return 0;
  5456. +}
  5457. +
  5458. +/**
  5459. + * ssh_ptl_rx_stop() - Stop packet transport layer receiver thread.
  5460. + * @ptl: The packet transport layer.
  5461. + *
  5462. + * Return: Returns zero on success, a negative error code on failure.
  5463. + */
  5464. +int ssh_ptl_rx_stop(struct ssh_ptl *ptl)
  5465. +{
  5466. + int status = 0;
  5467. +
  5468. + if (ptl->rx.thread) {
  5469. + status = kthread_stop(ptl->rx.thread);
  5470. + ptl->rx.thread = NULL;
  5471. + }
  5472. +
  5473. + return status;
  5474. +}
  5475. +
  5476. +/**
  5477. + * ssh_ptl_rx_rcvbuf() - Push data from lower-layer transport to the packet
  5478. + * layer.
  5479. + * @ptl: The packet transport layer.
  5480. + * @buf: Pointer to the data to push to the layer.
  5481. + * @n: Size of the data to push to the layer, in bytes.
  5482. + *
  5483. + * Pushes data from a lower-layer transport to the receiver fifo buffer of the
  5484. + * packet layer and notifies the receiver thread. Calls to this function are
  5485. + * ignored once the packet layer has been shut down.
  5486. + *
  5487. + * Return: Returns the number of bytes transferred (positive or zero) on
  5488. + * success. Returns %-ESHUTDOWN if the packet layer has been shut down.
  5489. + */
  5490. +int ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n)
  5491. +{
  5492. + int used;
  5493. +
  5494. + if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state))
  5495. + return -ESHUTDOWN;
  5496. +
  5497. + used = kfifo_in(&ptl->rx.fifo, buf, n);
  5498. + if (used)
  5499. + ssh_ptl_rx_wakeup(ptl);
  5500. +
  5501. + return used;
  5502. +}
  5503. +
  5504. +/**
  5505. + * ssh_ptl_shutdown() - Shut down the packet transport layer.
  5506. + * @ptl: The packet transport layer.
  5507. + *
  5508. + * Shuts down the packet transport layer, removing and canceling all queued
  5509. + * and pending packets. Packets canceled by this operation will be completed
  5510. + * with %-ESHUTDOWN as status. Receiver and transmitter threads will be
  5511. + * stopped.
  5512. + *
  5513. + * As a result of this function, the transport layer will be marked as shut
  5514. + * down. Submission of packets after the transport layer has been shut down
  5515. + * will fail with %-ESHUTDOWN.
  5516. + */
  5517. +void ssh_ptl_shutdown(struct ssh_ptl *ptl)
  5518. +{
  5519. + LIST_HEAD(complete_q);
  5520. + LIST_HEAD(complete_p);
  5521. + struct ssh_packet *p, *n;
  5522. + int status;
  5523. +
  5524. + /* Ensure that no new packets (including ACK/NAK) can be submitted. */
  5525. + set_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state);
  5526. + /*
  5527. + * Ensure that the layer gets marked as shut-down before actually
  5528. + * stopping it. In combination with the check in ssh_ptl_queue_push(),
  5529. + * this guarantees that no new packets can be added and all already
  5530. + * queued packets are properly canceled. In combination with the check
  5531. + * in ssh_ptl_rx_rcvbuf(), this guarantees that received data is
  5532. + * properly cut off.
  5533. + */
  5534. + smp_mb__after_atomic();
  5535. +
  5536. + status = ssh_ptl_rx_stop(ptl);
  5537. + if (status)
  5538. + ptl_err(ptl, "ptl: failed to stop receiver thread\n");
  5539. +
  5540. + status = ssh_ptl_tx_stop(ptl);
  5541. + if (status)
  5542. + ptl_err(ptl, "ptl: failed to stop transmitter thread\n");
  5543. +
  5544. + cancel_delayed_work_sync(&ptl->rtx_timeout.reaper);
  5545. +
  5546. + /*
  5547. + * At this point, all threads have been stopped. This means that the
  5548. + * only references to packets from inside the system are in the queue
  5549. + * and pending set.
  5550. + *
  5551. + * Note: We still need locks here because someone could still be
  5552. + * canceling packets.
  5553. + *
  5554. + * Note 2: We can re-use queue_node (or pending_node) if we mark the
  5555. + * packet as locked an then remove it from the queue (or pending set
  5556. + * respectively). Marking the packet as locked avoids re-queuing
  5557. + * (which should already be prevented by having stopped the treads...)
  5558. + * and not setting QUEUED_BIT (or PENDING_BIT) prevents removal from a
  5559. + * new list via other threads (e.g. cancellation).
  5560. + *
  5561. + * Note 3: There may be overlap between complete_p and complete_q.
  5562. + * This is handled via test_and_set_bit() on the "completed" flag
  5563. + * (also handles cancellation).
  5564. + */
  5565. +
  5566. + /* Mark queued packets as locked and move them to complete_q. */
  5567. + spin_lock(&ptl->queue.lock);
  5568. + list_for_each_entry_safe(p, n, &ptl->queue.head, queue_node) {
  5569. + set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state);
  5570. + /* Ensure that state does not get zero. */
  5571. + smp_mb__before_atomic();
  5572. + clear_bit(SSH_PACKET_SF_QUEUED_BIT, &p->state);
  5573. +
  5574. + list_del(&p->queue_node);
  5575. + list_add_tail(&p->queue_node, &complete_q);
  5576. + }
  5577. + spin_unlock(&ptl->queue.lock);
  5578. +
  5579. + /* Mark pending packets as locked and move them to complete_p. */
  5580. + spin_lock(&ptl->pending.lock);
  5581. + list_for_each_entry_safe(p, n, &ptl->pending.head, pending_node) {
  5582. + set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state);
  5583. + /* Ensure that state does not get zero. */
  5584. + smp_mb__before_atomic();
  5585. + clear_bit(SSH_PACKET_SF_PENDING_BIT, &p->state);
  5586. +
  5587. + list_del(&p->pending_node);
  5588. + list_add_tail(&p->pending_node, &complete_q);
  5589. + }
  5590. + atomic_set(&ptl->pending.count, 0);
  5591. + spin_unlock(&ptl->pending.lock);
  5592. +
  5593. + /* Complete and drop packets on complete_q. */
  5594. + list_for_each_entry(p, &complete_q, queue_node) {
  5595. + if (!test_and_set_bit(SSH_PACKET_SF_COMPLETED_BIT, &p->state))
  5596. + __ssh_ptl_complete(p, -ESHUTDOWN);
  5597. +
  5598. + ssh_packet_put(p);
  5599. + }
  5600. +
  5601. + /* Complete and drop packets on complete_p. */
  5602. + list_for_each_entry(p, &complete_p, pending_node) {
  5603. + if (!test_and_set_bit(SSH_PACKET_SF_COMPLETED_BIT, &p->state))
  5604. + __ssh_ptl_complete(p, -ESHUTDOWN);
  5605. +
  5606. + ssh_packet_put(p);
  5607. + }
  5608. +
  5609. + /*
  5610. + * At this point we have guaranteed that the system doesn't reference
  5611. + * any packets any more.
  5612. + */
  5613. +}
  5614. +
  5615. +/**
  5616. + * ssh_ptl_init() - Initialize packet transport layer.
  5617. + * @ptl: The packet transport layer to initialize.
  5618. + * @serdev: The underlying serial device, i.e. the lower-level transport.
  5619. + * @ops: Packet layer operations.
  5620. + *
  5621. + * Initializes the given packet transport layer. Transmitter and receiver
  5622. + * threads must be started separately via ssh_ptl_tx_start() and
  5623. + * ssh_ptl_rx_start(), after the packet-layer has been initialized and the
  5624. + * lower-level transport layer has been set up.
  5625. + *
  5626. + * Return: Returns zero on success and a nonzero error code on failure.
  5627. + */
  5628. +int ssh_ptl_init(struct ssh_ptl *ptl, struct serdev_device *serdev,
  5629. + struct ssh_ptl_ops *ops)
  5630. +{
  5631. + int i, status;
  5632. +
  5633. + ptl->serdev = serdev;
  5634. + ptl->state = 0;
  5635. +
  5636. + spin_lock_init(&ptl->queue.lock);
  5637. + INIT_LIST_HEAD(&ptl->queue.head);
  5638. +
  5639. + spin_lock_init(&ptl->pending.lock);
  5640. + INIT_LIST_HEAD(&ptl->pending.head);
  5641. + atomic_set_release(&ptl->pending.count, 0);
  5642. +
  5643. + ptl->tx.thread = NULL;
  5644. + atomic_set(&ptl->tx.running, 0);
  5645. + init_completion(&ptl->tx.thread_cplt_pkt);
  5646. + init_completion(&ptl->tx.thread_cplt_tx);
  5647. + init_waitqueue_head(&ptl->tx.packet_wq);
  5648. +
  5649. + ptl->rx.thread = NULL;
  5650. + init_waitqueue_head(&ptl->rx.wq);
  5651. +
  5652. + spin_lock_init(&ptl->rtx_timeout.lock);
  5653. + ptl->rtx_timeout.timeout = SSH_PTL_PACKET_TIMEOUT;
  5654. + ptl->rtx_timeout.expires = KTIME_MAX;
  5655. + INIT_DELAYED_WORK(&ptl->rtx_timeout.reaper, ssh_ptl_timeout_reap);
  5656. +
  5657. + ptl->ops = *ops;
  5658. +
  5659. + /* Initialize list of recent/blocked SEQs with invalid sequence IDs. */
  5660. + for (i = 0; i < ARRAY_SIZE(ptl->rx.blocked.seqs); i++)
  5661. + ptl->rx.blocked.seqs[i] = U16_MAX;
  5662. + ptl->rx.blocked.offset = 0;
  5663. +
  5664. + status = kfifo_alloc(&ptl->rx.fifo, SSH_PTL_RX_FIFO_LEN, GFP_KERNEL);
  5665. + if (status)
  5666. + return status;
  5667. +
  5668. + status = sshp_buf_alloc(&ptl->rx.buf, SSH_PTL_RX_BUF_LEN, GFP_KERNEL);
  5669. + if (status)
  5670. + kfifo_free(&ptl->rx.fifo);
  5671. +
  5672. + return status;
  5673. +}
  5674. +
  5675. +/**
  5676. + * ssh_ptl_destroy() - Deinitialize packet transport layer.
  5677. + * @ptl: The packet transport layer to deinitialize.
  5678. + *
  5679. + * Deinitializes the given packet transport layer and frees resources
  5680. + * associated with it. If receiver and/or transmitter threads have been
  5681. + * started, the layer must first be shut down via ssh_ptl_shutdown() before
  5682. + * this function can be called.
  5683. + */
  5684. +void ssh_ptl_destroy(struct ssh_ptl *ptl)
  5685. +{
  5686. + kfifo_free(&ptl->rx.fifo);
  5687. + sshp_buf_free(&ptl->rx.buf);
  5688. +}
  5689. diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.h b/drivers/platform/surface/aggregator/ssh_packet_layer.h
  5690. new file mode 100644
  5691. index 000000000000..058f111292ca
  5692. --- /dev/null
  5693. +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.h
  5694. @@ -0,0 +1,187 @@
  5695. +/* SPDX-License-Identifier: GPL-2.0+ */
  5696. +/*
  5697. + * SSH packet transport layer.
  5698. + *
  5699. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  5700. + */
  5701. +
  5702. +#ifndef _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H
  5703. +#define _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H
  5704. +
  5705. +#include <linux/atomic.h>
  5706. +#include <linux/kfifo.h>
  5707. +#include <linux/ktime.h>
  5708. +#include <linux/list.h>
  5709. +#include <linux/serdev.h>
  5710. +#include <linux/spinlock.h>
  5711. +#include <linux/types.h>
  5712. +#include <linux/wait.h>
  5713. +#include <linux/workqueue.h>
  5714. +
  5715. +#include <linux/surface_aggregator/serial_hub.h>
  5716. +#include "ssh_parser.h"
  5717. +
  5718. +/**
  5719. + * enum ssh_ptl_state_flags - State-flags for &struct ssh_ptl.
  5720. + *
  5721. + * @SSH_PTL_SF_SHUTDOWN_BIT:
  5722. + * Indicates that the packet transport layer has been shut down or is
  5723. + * being shut down and should not accept any new packets/data.
  5724. + */
  5725. +enum ssh_ptl_state_flags {
  5726. + SSH_PTL_SF_SHUTDOWN_BIT,
  5727. +};
  5728. +
  5729. +/**
  5730. + * struct ssh_ptl_ops - Callback operations for packet transport layer.
  5731. + * @data_received: Function called when a data-packet has been received. Both,
  5732. + * the packet layer on which the packet has been received and
  5733. + * the packet's payload data are provided to this function.
  5734. + */
  5735. +struct ssh_ptl_ops {
  5736. + void (*data_received)(struct ssh_ptl *p, const struct ssam_span *data);
  5737. +};
  5738. +
  5739. +/**
  5740. + * struct ssh_ptl - SSH packet transport layer.
  5741. + * @serdev: Serial device providing the underlying data transport.
  5742. + * @state: State(-flags) of the transport layer.
  5743. + * @queue: Packet submission queue.
  5744. + * @queue.lock: Lock for modifying the packet submission queue.
  5745. + * @queue.head: List-head of the packet submission queue.
  5746. + * @pending: Set/list of pending packets.
  5747. + * @pending.lock: Lock for modifying the pending set.
  5748. + * @pending.head: List-head of the pending set/list.
  5749. + * @pending.count: Number of currently pending packets.
  5750. + * @tx: Transmitter subsystem.
  5751. + * @tx.running: Flag indicating (desired) transmitter thread state.
  5752. + * @tx.thread: Transmitter thread.
  5753. + * @tx.thread_cplt_tx: Completion for transmitter thread waiting on transfer.
  5754. + * @tx.thread_cplt_pkt: Completion for transmitter thread waiting on packets.
  5755. + * @tx.packet_wq: Waitqueue-head for packet transmit completion.
  5756. + * @rx: Receiver subsystem.
  5757. + * @rx.thread: Receiver thread.
  5758. + * @rx.wq: Waitqueue-head for receiver thread.
  5759. + * @rx.fifo: Buffer for receiving data/pushing data to receiver thread.
  5760. + * @rx.buf: Buffer for evaluating data on receiver thread.
  5761. + * @rx.blocked: List of recent/blocked sequence IDs to detect retransmission.
  5762. + * @rx.blocked.seqs: Array of blocked sequence IDs.
  5763. + * @rx.blocked.offset: Offset indicating where a new ID should be inserted.
  5764. + * @rtx_timeout: Retransmission timeout subsystem.
  5765. + * @rtx_timeout.lock: Lock for modifying the retransmission timeout reaper.
  5766. + * @rtx_timeout.timeout: Timeout interval for retransmission.
  5767. + * @rtx_timeout.expires: Time specifying when the reaper work is next scheduled.
  5768. + * @rtx_timeout.reaper: Work performing timeout checks and subsequent actions.
  5769. + * @ops: Packet layer operations.
  5770. + */
  5771. +struct ssh_ptl {
  5772. + struct serdev_device *serdev;
  5773. + unsigned long state;
  5774. +
  5775. + struct {
  5776. + spinlock_t lock;
  5777. + struct list_head head;
  5778. + } queue;
  5779. +
  5780. + struct {
  5781. + spinlock_t lock;
  5782. + struct list_head head;
  5783. + atomic_t count;
  5784. + } pending;
  5785. +
  5786. + struct {
  5787. + atomic_t running;
  5788. + struct task_struct *thread;
  5789. + struct completion thread_cplt_tx;
  5790. + struct completion thread_cplt_pkt;
  5791. + struct wait_queue_head packet_wq;
  5792. + } tx;
  5793. +
  5794. + struct {
  5795. + struct task_struct *thread;
  5796. + struct wait_queue_head wq;
  5797. + struct kfifo fifo;
  5798. + struct sshp_buf buf;
  5799. +
  5800. + struct {
  5801. + u16 seqs[8];
  5802. + u16 offset;
  5803. + } blocked;
  5804. + } rx;
  5805. +
  5806. + struct {
  5807. + spinlock_t lock;
  5808. + ktime_t timeout;
  5809. + ktime_t expires;
  5810. + struct delayed_work reaper;
  5811. + } rtx_timeout;
  5812. +
  5813. + struct ssh_ptl_ops ops;
  5814. +};
  5815. +
  5816. +#define __ssam_prcond(func, p, fmt, ...) \
  5817. + do { \
  5818. + typeof(p) __p = (p); \
  5819. + \
  5820. + if (__p) \
  5821. + func(__p, fmt, ##__VA_ARGS__); \
  5822. + } while (0)
  5823. +
  5824. +#define ptl_dbg(p, fmt, ...) dev_dbg(&(p)->serdev->dev, fmt, ##__VA_ARGS__)
  5825. +#define ptl_info(p, fmt, ...) dev_info(&(p)->serdev->dev, fmt, ##__VA_ARGS__)
  5826. +#define ptl_warn(p, fmt, ...) dev_warn(&(p)->serdev->dev, fmt, ##__VA_ARGS__)
  5827. +#define ptl_err(p, fmt, ...) dev_err(&(p)->serdev->dev, fmt, ##__VA_ARGS__)
  5828. +#define ptl_dbg_cond(p, fmt, ...) __ssam_prcond(ptl_dbg, p, fmt, ##__VA_ARGS__)
  5829. +
  5830. +#define to_ssh_ptl(ptr, member) \
  5831. + container_of(ptr, struct ssh_ptl, member)
  5832. +
  5833. +int ssh_ptl_init(struct ssh_ptl *ptl, struct serdev_device *serdev,
  5834. + struct ssh_ptl_ops *ops);
  5835. +
  5836. +void ssh_ptl_destroy(struct ssh_ptl *ptl);
  5837. +
  5838. +/**
  5839. + * ssh_ptl_get_device() - Get device associated with packet transport layer.
  5840. + * @ptl: The packet transport layer.
  5841. + *
  5842. + * Return: Returns the device on which the given packet transport layer builds
  5843. + * upon.
  5844. + */
  5845. +static inline struct device *ssh_ptl_get_device(struct ssh_ptl *ptl)
  5846. +{
  5847. + return ptl->serdev ? &ptl->serdev->dev : NULL;
  5848. +}
  5849. +
  5850. +int ssh_ptl_tx_start(struct ssh_ptl *ptl);
  5851. +int ssh_ptl_tx_stop(struct ssh_ptl *ptl);
  5852. +int ssh_ptl_rx_start(struct ssh_ptl *ptl);
  5853. +int ssh_ptl_rx_stop(struct ssh_ptl *ptl);
  5854. +void ssh_ptl_shutdown(struct ssh_ptl *ptl);
  5855. +
  5856. +int ssh_ptl_submit(struct ssh_ptl *ptl, struct ssh_packet *p);
  5857. +void ssh_ptl_cancel(struct ssh_packet *p);
  5858. +
  5859. +int ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n);
  5860. +
  5861. +/**
  5862. + * ssh_ptl_tx_wakeup_transfer() - Wake up packet transmitter thread for
  5863. + * transfer.
  5864. + * @ptl: The packet transport layer.
  5865. + *
  5866. + * Wakes up the packet transmitter thread, notifying it that the underlying
  5867. + * transport has more space for data to be transmitted. If the packet
  5868. + * transport layer has been shut down, calls to this function will be ignored.
  5869. + */
  5870. +static inline void ssh_ptl_tx_wakeup_transfer(struct ssh_ptl *ptl)
  5871. +{
  5872. + if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state))
  5873. + return;
  5874. +
  5875. + complete(&ptl->tx.thread_cplt_tx);
  5876. +}
  5877. +
  5878. +void ssh_packet_init(struct ssh_packet *packet, unsigned long type,
  5879. + u8 priority, const struct ssh_packet_ops *ops);
  5880. +
  5881. +#endif /* _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H */
  5882. diff --git a/drivers/platform/surface/aggregator/ssh_parser.c b/drivers/platform/surface/aggregator/ssh_parser.c
  5883. new file mode 100644
  5884. index 000000000000..e2dead8de94a
  5885. --- /dev/null
  5886. +++ b/drivers/platform/surface/aggregator/ssh_parser.c
  5887. @@ -0,0 +1,228 @@
  5888. +// SPDX-License-Identifier: GPL-2.0+
  5889. +/*
  5890. + * SSH message parser.
  5891. + *
  5892. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  5893. + */
  5894. +
  5895. +#include <asm/unaligned.h>
  5896. +#include <linux/compiler.h>
  5897. +#include <linux/device.h>
  5898. +#include <linux/types.h>
  5899. +
  5900. +#include <linux/surface_aggregator/serial_hub.h>
  5901. +#include "ssh_parser.h"
  5902. +
  5903. +/**
  5904. + * sshp_validate_crc() - Validate a CRC in raw message data.
  5905. + * @src: The span of data over which the CRC should be computed.
  5906. + * @crc: The pointer to the expected u16 CRC value.
  5907. + *
  5908. + * Computes the CRC of the provided data span (@src), compares it to the CRC
  5909. + * stored at the given address (@crc), and returns the result of this
  5910. + * comparison, i.e. %true if equal. This function is intended to run on raw
  5911. + * input/message data.
  5912. + *
  5913. + * Return: Returns %true if the computed CRC matches the stored CRC, %false
  5914. + * otherwise.
  5915. + */
  5916. +static bool sshp_validate_crc(const struct ssam_span *src, const u8 *crc)
  5917. +{
  5918. + u16 actual = ssh_crc(src->ptr, src->len);
  5919. + u16 expected = get_unaligned_le16(crc);
  5920. +
  5921. + return actual == expected;
  5922. +}
  5923. +
  5924. +/**
  5925. + * sshp_starts_with_syn() - Check if the given data starts with SSH SYN bytes.
  5926. + * @src: The data span to check the start of.
  5927. + */
  5928. +static bool sshp_starts_with_syn(const struct ssam_span *src)
  5929. +{
  5930. + return src->len >= 2 && get_unaligned_le16(src->ptr) == SSH_MSG_SYN;
  5931. +}
  5932. +
  5933. +/**
  5934. + * sshp_find_syn() - Find SSH SYN bytes in the given data span.
  5935. + * @src: The data span to search in.
  5936. + * @rem: The span (output) indicating the remaining data, starting with SSH
  5937. + * SYN bytes, if found.
  5938. + *
  5939. + * Search for SSH SYN bytes in the given source span. If found, set the @rem
  5940. + * span to the remaining data, starting with the first SYN bytes and capped by
  5941. + * the source span length, and return %true. This function does not copy any
  5942. + * data, but rather only sets pointers to the respective start addresses and
  5943. + * length values.
  5944. + *
  5945. + * If no SSH SYN bytes could be found, set the @rem span to the zero-length
  5946. + * span at the end of the source span and return %false.
  5947. + *
  5948. + * If partial SSH SYN bytes could be found at the end of the source span, set
  5949. + * the @rem span to cover these partial SYN bytes, capped by the end of the
  5950. + * source span, and return %false. This function should then be re-run once
  5951. + * more data is available.
  5952. + *
  5953. + * Return: Returns %true if a complete SSH SYN sequence could be found,
  5954. + * %false otherwise.
  5955. + */
  5956. +bool sshp_find_syn(const struct ssam_span *src, struct ssam_span *rem)
  5957. +{
  5958. + size_t i;
  5959. +
  5960. + for (i = 0; i < src->len - 1; i++) {
  5961. + if (likely(get_unaligned_le16(src->ptr + i) == SSH_MSG_SYN)) {
  5962. + rem->ptr = src->ptr + i;
  5963. + rem->len = src->len - i;
  5964. + return true;
  5965. + }
  5966. + }
  5967. +
  5968. + if (unlikely(src->ptr[src->len - 1] == (SSH_MSG_SYN & 0xff))) {
  5969. + rem->ptr = src->ptr + src->len - 1;
  5970. + rem->len = 1;
  5971. + return false;
  5972. + }
  5973. +
  5974. + rem->ptr = src->ptr + src->len;
  5975. + rem->len = 0;
  5976. + return false;
  5977. +}
  5978. +
  5979. +/**
  5980. + * sshp_parse_frame() - Parse SSH frame.
  5981. + * @dev: The device used for logging.
  5982. + * @source: The source to parse from.
  5983. + * @frame: The parsed frame (output).
  5984. + * @payload: The parsed payload (output).
  5985. + * @maxlen: The maximum supported message length.
  5986. + *
  5987. + * Parses and validates a SSH frame, including its payload, from the given
  5988. + * source. Sets the provided @frame pointer to the start of the frame and
  5989. + * writes the limits of the frame payload to the provided @payload span
  5990. + * pointer.
  5991. + *
  5992. + * This function does not copy any data, but rather only validates the message
  5993. + * data and sets pointers (and length values) to indicate the respective parts.
  5994. + *
  5995. + * If no complete SSH frame could be found, the frame pointer will be set to
  5996. + * the %NULL pointer and the payload span will be set to the null span (start
  5997. + * pointer %NULL, size zero).
  5998. + *
  5999. + * Return: Returns zero on success or if the frame is incomplete, %-ENOMSG if
  6000. + * the start of the message is invalid, %-EBADMSG if any (frame-header or
  6001. + * payload) CRC is invalid, or %-EMSGSIZE if the SSH message is bigger than
  6002. + * the maximum message length specified in the @maxlen parameter.
  6003. + */
  6004. +int sshp_parse_frame(const struct device *dev, const struct ssam_span *source,
  6005. + struct ssh_frame **frame, struct ssam_span *payload,
  6006. + size_t maxlen)
  6007. +{
  6008. + struct ssam_span sf;
  6009. + struct ssam_span sp;
  6010. +
  6011. + /* Initialize output. */
  6012. + *frame = NULL;
  6013. + payload->ptr = NULL;
  6014. + payload->len = 0;
  6015. +
  6016. + if (!sshp_starts_with_syn(source)) {
  6017. + dev_warn(dev, "rx: parser: invalid start of frame\n");
  6018. + return -ENOMSG;
  6019. + }
  6020. +
  6021. + /* Check for minimum packet length. */
  6022. + if (unlikely(source->len < SSH_MESSAGE_LENGTH(0))) {
  6023. + dev_dbg(dev, "rx: parser: not enough data for frame\n");
  6024. + return 0;
  6025. + }
  6026. +
  6027. + /* Pin down frame. */
  6028. + sf.ptr = source->ptr + sizeof(u16);
  6029. + sf.len = sizeof(struct ssh_frame);
  6030. +
  6031. + /* Validate frame CRC. */
  6032. + if (unlikely(!sshp_validate_crc(&sf, sf.ptr + sf.len))) {
  6033. + dev_warn(dev, "rx: parser: invalid frame CRC\n");
  6034. + return -EBADMSG;
  6035. + }
  6036. +
  6037. + /* Ensure packet does not exceed maximum length. */
  6038. + sp.len = get_unaligned_le16(&((struct ssh_frame *)sf.ptr)->len);
  6039. + if (unlikely(SSH_MESSAGE_LENGTH(sp.len) > maxlen)) {
  6040. + dev_warn(dev, "rx: parser: frame too large: %llu bytes\n",
  6041. + SSH_MESSAGE_LENGTH(sp.len));
  6042. + return -EMSGSIZE;
  6043. + }
  6044. +
  6045. + /* Pin down payload. */
  6046. + sp.ptr = sf.ptr + sf.len + sizeof(u16);
  6047. +
  6048. + /* Check for frame + payload length. */
  6049. + if (source->len < SSH_MESSAGE_LENGTH(sp.len)) {
  6050. + dev_dbg(dev, "rx: parser: not enough data for payload\n");
  6051. + return 0;
  6052. + }
  6053. +
  6054. + /* Validate payload CRC. */
  6055. + if (unlikely(!sshp_validate_crc(&sp, sp.ptr + sp.len))) {
  6056. + dev_warn(dev, "rx: parser: invalid payload CRC\n");
  6057. + return -EBADMSG;
  6058. + }
  6059. +
  6060. + *frame = (struct ssh_frame *)sf.ptr;
  6061. + *payload = sp;
  6062. +
  6063. + dev_dbg(dev, "rx: parser: valid frame found (type: %#04x, len: %u)\n",
  6064. + (*frame)->type, (*frame)->len);
  6065. +
  6066. + return 0;
  6067. +}
  6068. +
  6069. +/**
  6070. + * sshp_parse_command() - Parse SSH command frame payload.
  6071. + * @dev: The device used for logging.
  6072. + * @source: The source to parse from.
  6073. + * @command: The parsed command (output).
  6074. + * @command_data: The parsed command data/payload (output).
  6075. + *
  6076. + * Parses and validates a SSH command frame payload. Sets the @command pointer
  6077. + * to the command header and the @command_data span to the command data (i.e.
  6078. + * payload of the command). This will result in a zero-length span if the
  6079. + * command does not have any associated data/payload. This function does not
  6080. + * check the frame-payload-type field, which should be checked by the caller
  6081. + * before calling this function.
  6082. + *
  6083. + * The @source parameter should be the complete frame payload, e.g. returned
  6084. + * by the sshp_parse_frame() command.
  6085. + *
  6086. + * This function does not copy any data, but rather only validates the frame
  6087. + * payload data and sets pointers (and length values) to indicate the
  6088. + * respective parts.
  6089. + *
  6090. + * Return: Returns zero on success or %-ENOMSG if @source does not represent a
  6091. + * valid command-type frame payload, i.e. is too short.
  6092. + */
  6093. +int sshp_parse_command(const struct device *dev, const struct ssam_span *source,
  6094. + struct ssh_command **command,
  6095. + struct ssam_span *command_data)
  6096. +{
  6097. + /* Check for minimum length. */
  6098. + if (unlikely(source->len < sizeof(struct ssh_command))) {
  6099. + *command = NULL;
  6100. + command_data->ptr = NULL;
  6101. + command_data->len = 0;
  6102. +
  6103. + dev_err(dev, "rx: parser: command payload is too short\n");
  6104. + return -ENOMSG;
  6105. + }
  6106. +
  6107. + *command = (struct ssh_command *)source->ptr;
  6108. + command_data->ptr = source->ptr + sizeof(struct ssh_command);
  6109. + command_data->len = source->len - sizeof(struct ssh_command);
  6110. +
  6111. + dev_dbg(dev, "rx: parser: valid command found (tc: %#04x, cid: %#04x)\n",
  6112. + (*command)->tc, (*command)->cid);
  6113. +
  6114. + return 0;
  6115. +}
  6116. diff --git a/drivers/platform/surface/aggregator/ssh_parser.h b/drivers/platform/surface/aggregator/ssh_parser.h
  6117. new file mode 100644
  6118. index 000000000000..63c38d350988
  6119. --- /dev/null
  6120. +++ b/drivers/platform/surface/aggregator/ssh_parser.h
  6121. @@ -0,0 +1,154 @@
  6122. +/* SPDX-License-Identifier: GPL-2.0+ */
  6123. +/*
  6124. + * SSH message parser.
  6125. + *
  6126. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  6127. + */
  6128. +
  6129. +#ifndef _SURFACE_AGGREGATOR_SSH_PARSER_H
  6130. +#define _SURFACE_AGGREGATOR_SSH_PARSER_H
  6131. +
  6132. +#include <linux/device.h>
  6133. +#include <linux/kfifo.h>
  6134. +#include <linux/slab.h>
  6135. +#include <linux/types.h>
  6136. +
  6137. +#include <linux/surface_aggregator/serial_hub.h>
  6138. +
  6139. +/**
  6140. + * struct sshp_buf - Parser buffer for SSH messages.
  6141. + * @ptr: Pointer to the beginning of the buffer.
  6142. + * @len: Number of bytes used in the buffer.
  6143. + * @cap: Maximum capacity of the buffer.
  6144. + */
  6145. +struct sshp_buf {
  6146. + u8 *ptr;
  6147. + size_t len;
  6148. + size_t cap;
  6149. +};
  6150. +
  6151. +/**
  6152. + * sshp_buf_init() - Initialize a SSH parser buffer.
  6153. + * @buf: The buffer to initialize.
  6154. + * @ptr: The memory backing the buffer.
  6155. + * @cap: The length of the memory backing the buffer, i.e. its capacity.
  6156. + *
  6157. + * Initializes the buffer with the given memory as backing and set its used
  6158. + * length to zero.
  6159. + */
  6160. +static inline void sshp_buf_init(struct sshp_buf *buf, u8 *ptr, size_t cap)
  6161. +{
  6162. + buf->ptr = ptr;
  6163. + buf->len = 0;
  6164. + buf->cap = cap;
  6165. +}
  6166. +
  6167. +/**
  6168. + * sshp_buf_alloc() - Allocate and initialize a SSH parser buffer.
  6169. + * @buf: The buffer to initialize/allocate to.
  6170. + * @cap: The desired capacity of the buffer.
  6171. + * @flags: The flags used for allocating the memory.
  6172. + *
  6173. + * Allocates @cap bytes and initializes the provided buffer struct with the
  6174. + * allocated memory.
  6175. + *
  6176. + * Return: Returns zero on success and %-ENOMEM if allocation failed.
  6177. + */
  6178. +static inline int sshp_buf_alloc(struct sshp_buf *buf, size_t cap, gfp_t flags)
  6179. +{
  6180. + u8 *ptr;
  6181. +
  6182. + ptr = kzalloc(cap, flags);
  6183. + if (!ptr)
  6184. + return -ENOMEM;
  6185. +
  6186. + sshp_buf_init(buf, ptr, cap);
  6187. + return 0;
  6188. +}
  6189. +
  6190. +/**
  6191. + * sshp_buf_free() - Free a SSH parser buffer.
  6192. + * @buf: The buffer to free.
  6193. + *
  6194. + * Frees a SSH parser buffer by freeing the memory backing it and then
  6195. + * resetting its pointer to %NULL and length and capacity to zero. Intended to
  6196. + * free a buffer previously allocated with sshp_buf_alloc().
  6197. + */
  6198. +static inline void sshp_buf_free(struct sshp_buf *buf)
  6199. +{
  6200. + kfree(buf->ptr);
  6201. + buf->ptr = NULL;
  6202. + buf->len = 0;
  6203. + buf->cap = 0;
  6204. +}
  6205. +
  6206. +/**
  6207. + * sshp_buf_drop() - Drop data from the beginning of the buffer.
  6208. + * @buf: The buffer to drop data from.
  6209. + * @n: The number of bytes to drop.
  6210. + *
  6211. + * Drops the first @n bytes from the buffer. Re-aligns any remaining data to
  6212. + * the beginning of the buffer.
  6213. + */
  6214. +static inline void sshp_buf_drop(struct sshp_buf *buf, size_t n)
  6215. +{
  6216. + memmove(buf->ptr, buf->ptr + n, buf->len - n);
  6217. + buf->len -= n;
  6218. +}
  6219. +
  6220. +/**
  6221. + * sshp_buf_read_from_fifo() - Transfer data from a fifo to the buffer.
  6222. + * @buf: The buffer to write the data into.
  6223. + * @fifo: The fifo to read the data from.
  6224. + *
  6225. + * Transfers the data contained in the fifo to the buffer, removing it from
  6226. + * the fifo. This function will try to transfer as much data as possible,
  6227. + * limited either by the remaining space in the buffer or by the number of
  6228. + * bytes available in the fifo.
  6229. + *
  6230. + * Return: Returns the number of bytes transferred.
  6231. + */
  6232. +static inline size_t sshp_buf_read_from_fifo(struct sshp_buf *buf,
  6233. + struct kfifo *fifo)
  6234. +{
  6235. + size_t n;
  6236. +
  6237. + n = kfifo_out(fifo, buf->ptr + buf->len, buf->cap - buf->len);
  6238. + buf->len += n;
  6239. +
  6240. + return n;
  6241. +}
  6242. +
  6243. +/**
  6244. + * sshp_buf_span_from() - Initialize a span from the given buffer and offset.
  6245. + * @buf: The buffer to create the span from.
  6246. + * @offset: The offset in the buffer at which the span should start.
  6247. + * @span: The span to initialize (output).
  6248. + *
  6249. + * Initializes the provided span to point to the memory at the given offset in
  6250. + * the buffer, with the length of the span being capped by the number of bytes
  6251. + * used in the buffer after the offset (i.e. bytes remaining after the
  6252. + * offset).
  6253. + *
  6254. + * Warning: This function does not validate that @offset is less than or equal
  6255. + * to the number of bytes used in the buffer or the buffer capacity. This must
  6256. + * be guaranteed by the caller.
  6257. + */
  6258. +static inline void sshp_buf_span_from(struct sshp_buf *buf, size_t offset,
  6259. + struct ssam_span *span)
  6260. +{
  6261. + span->ptr = buf->ptr + offset;
  6262. + span->len = buf->len - offset;
  6263. +}
  6264. +
  6265. +bool sshp_find_syn(const struct ssam_span *src, struct ssam_span *rem);
  6266. +
  6267. +int sshp_parse_frame(const struct device *dev, const struct ssam_span *source,
  6268. + struct ssh_frame **frame, struct ssam_span *payload,
  6269. + size_t maxlen);
  6270. +
  6271. +int sshp_parse_command(const struct device *dev, const struct ssam_span *source,
  6272. + struct ssh_command **command,
  6273. + struct ssam_span *command_data);
  6274. +
  6275. +#endif /* _SURFACE_AGGREGATOR_SSH_PARSER_h */
  6276. diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c
  6277. new file mode 100644
  6278. index 000000000000..66c839a995f3
  6279. --- /dev/null
  6280. +++ b/drivers/platform/surface/aggregator/ssh_request_layer.c
  6281. @@ -0,0 +1,1211 @@
  6282. +// SPDX-License-Identifier: GPL-2.0+
  6283. +/*
  6284. + * SSH request transport layer.
  6285. + *
  6286. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  6287. + */
  6288. +
  6289. +#include <asm/unaligned.h>
  6290. +#include <linux/atomic.h>
  6291. +#include <linux/completion.h>
  6292. +#include <linux/ktime.h>
  6293. +#include <linux/limits.h>
  6294. +#include <linux/list.h>
  6295. +#include <linux/slab.h>
  6296. +#include <linux/spinlock.h>
  6297. +#include <linux/types.h>
  6298. +#include <linux/workqueue.h>
  6299. +
  6300. +#include <linux/surface_aggregator/serial_hub.h>
  6301. +#include <linux/surface_aggregator/controller.h>
  6302. +
  6303. +#include "ssh_packet_layer.h"
  6304. +#include "ssh_request_layer.h"
  6305. +
  6306. +/*
  6307. + * SSH_RTL_REQUEST_TIMEOUT - Request timeout.
  6308. + *
  6309. + * Timeout as ktime_t delta for request responses. If we have not received a
  6310. + * response in this time-frame after finishing the underlying packet
  6311. + * transmission, the request will be completed with %-ETIMEDOUT as status
  6312. + * code.
  6313. + */
  6314. +#define SSH_RTL_REQUEST_TIMEOUT ms_to_ktime(3000)
  6315. +
  6316. +/*
  6317. + * SSH_RTL_REQUEST_TIMEOUT_RESOLUTION - Request timeout granularity.
  6318. + *
  6319. + * Time-resolution for timeouts. Should be larger than one jiffy to avoid
  6320. + * direct re-scheduling of reaper work_struct.
  6321. + */
  6322. +#define SSH_RTL_REQUEST_TIMEOUT_RESOLUTION ms_to_ktime(max(2000 / HZ, 50))
  6323. +
  6324. +/*
  6325. + * SSH_RTL_MAX_PENDING - Maximum number of pending requests.
  6326. + *
  6327. + * Maximum number of requests concurrently waiting to be completed (i.e.
  6328. + * waiting for the corresponding packet transmission to finish if they don't
  6329. + * have a response or waiting for a response if they have one).
  6330. + */
  6331. +#define SSH_RTL_MAX_PENDING 3
  6332. +
  6333. +/*
  6334. + * SSH_RTL_TX_BATCH - Maximum number of requests processed per work execution.
  6335. + * Used to prevent livelocking of the workqueue. Value chosen via educated
  6336. + * guess, may be adjusted.
  6337. + */
  6338. +#define SSH_RTL_TX_BATCH 10
  6339. +
  6340. +static u16 ssh_request_get_rqid(struct ssh_request *rqst)
  6341. +{
  6342. + return get_unaligned_le16(rqst->packet.data.ptr
  6343. + + SSH_MSGOFFSET_COMMAND(rqid));
  6344. +}
  6345. +
  6346. +static u32 ssh_request_get_rqid_safe(struct ssh_request *rqst)
  6347. +{
  6348. + if (!rqst->packet.data.ptr)
  6349. + return U32_MAX;
  6350. +
  6351. + return ssh_request_get_rqid(rqst);
  6352. +}
  6353. +
  6354. +static void ssh_rtl_queue_remove(struct ssh_request *rqst)
  6355. +{
  6356. + struct ssh_rtl *rtl = ssh_request_rtl(rqst);
  6357. +
  6358. + spin_lock(&rtl->queue.lock);
  6359. +
  6360. + if (!test_and_clear_bit(SSH_REQUEST_SF_QUEUED_BIT, &rqst->state)) {
  6361. + spin_unlock(&rtl->queue.lock);
  6362. + return;
  6363. + }
  6364. +
  6365. + list_del(&rqst->node);
  6366. +
  6367. + spin_unlock(&rtl->queue.lock);
  6368. + ssh_request_put(rqst);
  6369. +}
  6370. +
  6371. +static bool ssh_rtl_queue_empty(struct ssh_rtl *rtl)
  6372. +{
  6373. + bool empty;
  6374. +
  6375. + spin_lock(&rtl->queue.lock);
  6376. + empty = list_empty(&rtl->queue.head);
  6377. + spin_unlock(&rtl->queue.lock);
  6378. +
  6379. + return empty;
  6380. +}
  6381. +
  6382. +static void ssh_rtl_pending_remove(struct ssh_request *rqst)
  6383. +{
  6384. + struct ssh_rtl *rtl = ssh_request_rtl(rqst);
  6385. +
  6386. + spin_lock(&rtl->pending.lock);
  6387. +
  6388. + if (!test_and_clear_bit(SSH_REQUEST_SF_PENDING_BIT, &rqst->state)) {
  6389. + spin_unlock(&rtl->pending.lock);
  6390. + return;
  6391. + }
  6392. +
  6393. + atomic_dec(&rtl->pending.count);
  6394. + list_del(&rqst->node);
  6395. +
  6396. + spin_unlock(&rtl->pending.lock);
  6397. +
  6398. + ssh_request_put(rqst);
  6399. +}
  6400. +
  6401. +static int ssh_rtl_tx_pending_push(struct ssh_request *rqst)
  6402. +{
  6403. + struct ssh_rtl *rtl = ssh_request_rtl(rqst);
  6404. +
  6405. + spin_lock(&rtl->pending.lock);
  6406. +
  6407. + if (test_bit(SSH_REQUEST_SF_LOCKED_BIT, &rqst->state)) {
  6408. + spin_unlock(&rtl->pending.lock);
  6409. + return -EINVAL;
  6410. + }
  6411. +
  6412. + if (test_and_set_bit(SSH_REQUEST_SF_PENDING_BIT, &rqst->state)) {
  6413. + spin_unlock(&rtl->pending.lock);
  6414. + return -EALREADY;
  6415. + }
  6416. +
  6417. + atomic_inc(&rtl->pending.count);
  6418. + list_add_tail(&ssh_request_get(rqst)->node, &rtl->pending.head);
  6419. +
  6420. + spin_unlock(&rtl->pending.lock);
  6421. + return 0;
  6422. +}
  6423. +
  6424. +static void ssh_rtl_complete_with_status(struct ssh_request *rqst, int status)
  6425. +{
  6426. + struct ssh_rtl *rtl = ssh_request_rtl(rqst);
  6427. +
  6428. + /* rtl/ptl may not be set if we're canceling before submitting. */
  6429. + rtl_dbg_cond(rtl, "rtl: completing request (rqid: %#06x, status: %d)\n",
  6430. + ssh_request_get_rqid_safe(rqst), status);
  6431. +
  6432. + rqst->ops->complete(rqst, NULL, NULL, status);
  6433. +}
  6434. +
  6435. +static void ssh_rtl_complete_with_rsp(struct ssh_request *rqst,
  6436. + const struct ssh_command *cmd,
  6437. + const struct ssam_span *data)
  6438. +{
  6439. + struct ssh_rtl *rtl = ssh_request_rtl(rqst);
  6440. +
  6441. + rtl_dbg(rtl, "rtl: completing request with response (rqid: %#06x)\n",
  6442. + ssh_request_get_rqid(rqst));
  6443. +
  6444. + rqst->ops->complete(rqst, cmd, data, 0);
  6445. +}
  6446. +
  6447. +static bool ssh_rtl_tx_can_process(struct ssh_request *rqst)
  6448. +{
  6449. + struct ssh_rtl *rtl = ssh_request_rtl(rqst);
  6450. +
  6451. + if (test_bit(SSH_REQUEST_TY_FLUSH_BIT, &rqst->state))
  6452. + return !atomic_read(&rtl->pending.count);
  6453. +
  6454. + return atomic_read(&rtl->pending.count) < SSH_RTL_MAX_PENDING;
  6455. +}
  6456. +
  6457. +static struct ssh_request *ssh_rtl_tx_next(struct ssh_rtl *rtl)
  6458. +{
  6459. + struct ssh_request *rqst = ERR_PTR(-ENOENT);
  6460. + struct ssh_request *p, *n;
  6461. +
  6462. + spin_lock(&rtl->queue.lock);
  6463. +
  6464. + /* Find first non-locked request and remove it. */
  6465. + list_for_each_entry_safe(p, n, &rtl->queue.head, node) {
  6466. + if (unlikely(test_bit(SSH_REQUEST_SF_LOCKED_BIT, &p->state)))
  6467. + continue;
  6468. +
  6469. + if (!ssh_rtl_tx_can_process(p)) {
  6470. + rqst = ERR_PTR(-EBUSY);
  6471. + break;
  6472. + }
  6473. +
  6474. + /* Remove from queue and mark as transmitting. */
  6475. + set_bit(SSH_REQUEST_SF_TRANSMITTING_BIT, &p->state);
  6476. + /* Ensure state never gets zero. */
  6477. + smp_mb__before_atomic();
  6478. + clear_bit(SSH_REQUEST_SF_QUEUED_BIT, &p->state);
  6479. +
  6480. + list_del(&p->node);
  6481. +
  6482. + rqst = p;
  6483. + break;
  6484. + }
  6485. +
  6486. + spin_unlock(&rtl->queue.lock);
  6487. + return rqst;
  6488. +}
  6489. +
  6490. +static int ssh_rtl_tx_try_process_one(struct ssh_rtl *rtl)
  6491. +{
  6492. + struct ssh_request *rqst;
  6493. + int status;
  6494. +
  6495. + /* Get and prepare next request for transmit. */
  6496. + rqst = ssh_rtl_tx_next(rtl);
  6497. + if (IS_ERR(rqst))
  6498. + return PTR_ERR(rqst);
  6499. +
  6500. + /* Add it to/mark it as pending. */
  6501. + status = ssh_rtl_tx_pending_push(rqst);
  6502. + if (status) {
  6503. + ssh_request_put(rqst);
  6504. + return -EAGAIN;
  6505. + }
  6506. +
  6507. + /* Submit packet. */
  6508. + status = ssh_ptl_submit(&rtl->ptl, &rqst->packet);
  6509. + if (status == -ESHUTDOWN) {
  6510. + /*
  6511. + * Packet has been refused due to the packet layer shutting
  6512. + * down. Complete it here.
  6513. + */
  6514. + set_bit(SSH_REQUEST_SF_LOCKED_BIT, &rqst->state);
  6515. + /*
  6516. + * Note: A barrier is not required here, as there are only two
  6517. + * references in the system at this point: The one that we have,
  6518. + * and the other one that belongs to the pending set. Due to the
  6519. + * request being marked as "transmitting", our process is the
  6520. + * only one allowed to remove the pending node and change the
  6521. + * state. Normally, the task would fall to the packet callback,
  6522. + * but as this is a path where submission failed, this callback
  6523. + * will never be executed.
  6524. + */
  6525. +
  6526. + ssh_rtl_pending_remove(rqst);
  6527. + ssh_rtl_complete_with_status(rqst, -ESHUTDOWN);
  6528. +
  6529. + ssh_request_put(rqst);
  6530. + return -ESHUTDOWN;
  6531. +
  6532. + } else if (status) {
  6533. + /*
  6534. + * If submitting the packet failed and the packet layer isn't
  6535. + * shutting down, the packet has either been submitted/queued
  6536. + * before (-EALREADY, which cannot happen as we have
  6537. + * guaranteed that requests cannot be re-submitted), or the
  6538. + * packet was marked as locked (-EINVAL). To mark the packet
  6539. + * locked at this stage, the request, and thus the packets
  6540. + * itself, had to have been canceled. Simply drop the
  6541. + * reference. Cancellation itself will remove it from the set
  6542. + * of pending requests.
  6543. + */
  6544. +
  6545. + WARN_ON(status != -EINVAL);
  6546. +
  6547. + ssh_request_put(rqst);
  6548. + return -EAGAIN;
  6549. + }
  6550. +
  6551. + ssh_request_put(rqst);
  6552. + return 0;
  6553. +}
  6554. +
  6555. +static bool ssh_rtl_tx_schedule(struct ssh_rtl *rtl)
  6556. +{
  6557. + if (atomic_read(&rtl->pending.count) >= SSH_RTL_MAX_PENDING)
  6558. + return false;
  6559. +
  6560. + if (ssh_rtl_queue_empty(rtl))
  6561. + return false;
  6562. +
  6563. + return schedule_work(&rtl->tx.work);
  6564. +}
  6565. +
  6566. +static void ssh_rtl_tx_work_fn(struct work_struct *work)
  6567. +{
  6568. + struct ssh_rtl *rtl = to_ssh_rtl(work, tx.work);
  6569. + unsigned int iterations = SSH_RTL_TX_BATCH;
  6570. + int status;
  6571. +
  6572. + /*
  6573. + * Try to be nice and not block/live-lock the workqueue: Run a maximum
  6574. + * of 10 tries, then re-submit if necessary. This should not be
  6575. + * necessary for normal execution, but guarantee it anyway.
  6576. + */
  6577. + do {
  6578. + status = ssh_rtl_tx_try_process_one(rtl);
  6579. + if (status == -ENOENT || status == -EBUSY)
  6580. + return; /* No more requests to process. */
  6581. +
  6582. + if (status == -ESHUTDOWN) {
  6583. + /*
  6584. + * Packet system shutting down. No new packets can be
  6585. + * transmitted. Return silently, the party initiating
  6586. + * the shutdown should handle the rest.
  6587. + */
  6588. + return;
  6589. + }
  6590. +
  6591. + WARN_ON(status != 0 && status != -EAGAIN);
  6592. + } while (--iterations);
  6593. +
  6594. + /* Out of tries, reschedule. */
  6595. + ssh_rtl_tx_schedule(rtl);
  6596. +}
  6597. +
  6598. +/**
  6599. + * ssh_rtl_submit() - Submit a request to the transport layer.
  6600. + * @rtl: The request transport layer.
  6601. + * @rqst: The request to submit.
  6602. + *
  6603. + * Submits a request to the transport layer. A single request may not be
  6604. + * submitted multiple times without reinitializing it.
  6605. + *
  6606. + * Return: Returns zero on success, %-EINVAL if the request type is invalid or
  6607. + * the request has been canceled prior to submission, %-EALREADY if the
  6608. + * request has already been submitted, or %-ESHUTDOWN in case the request
  6609. + * transport layer has been shut down.
  6610. + */
  6611. +int ssh_rtl_submit(struct ssh_rtl *rtl, struct ssh_request *rqst)
  6612. +{
  6613. + /*
  6614. + * Ensure that requests expecting a response are sequenced. If this
  6615. + * invariant ever changes, see the comment in ssh_rtl_complete() on what
  6616. + * is required to be changed in the code.
  6617. + */
  6618. + if (test_bit(SSH_REQUEST_TY_HAS_RESPONSE_BIT, &rqst->state))
  6619. + if (!test_bit(SSH_PACKET_TY_SEQUENCED_BIT, &rqst->packet.state))
  6620. + return -EINVAL;
  6621. +
  6622. + spin_lock(&rtl->queue.lock);
  6623. +
  6624. + /*
  6625. + * Try to set ptl and check if this request has already been submitted.
  6626. + *
  6627. + * Must be inside lock as we might run into a lost update problem
  6628. + * otherwise: If this were outside of the lock, cancellation in
  6629. + * ssh_rtl_cancel_nonpending() may run after we've set the ptl
  6630. + * reference but before we enter the lock. In that case, we'd detect
  6631. + * that the request is being added to the queue and would try to remove
  6632. + * it from that, but removal might fail because it hasn't actually been
  6633. + * added yet. By putting this cmpxchg in the critical section, we
  6634. + * ensure that the queuing detection only triggers when we are already
  6635. + * in the critical section and the remove process will wait until the
  6636. + * push operation has been completed (via lock) due to that. Only then,
  6637. + * we can safely try to remove it.
  6638. + */
  6639. + if (cmpxchg(&rqst->packet.ptl, NULL, &rtl->ptl)) {
  6640. + spin_unlock(&rtl->queue.lock);
  6641. + return -EALREADY;
  6642. + }
  6643. +
  6644. + /*
  6645. + * Ensure that we set ptl reference before we continue modifying state.
  6646. + * This is required for non-pending cancellation. This barrier is paired
  6647. + * with the one in ssh_rtl_cancel_nonpending().
  6648. + *
  6649. + * By setting the ptl reference before we test for "locked", we can
  6650. + * check if the "locked" test may have already run. See comments in
  6651. + * ssh_rtl_cancel_nonpending() for more detail.
  6652. + */
  6653. + smp_mb__after_atomic();
  6654. +
  6655. + if (test_bit(SSH_RTL_SF_SHUTDOWN_BIT, &rtl->state)) {
  6656. + spin_unlock(&rtl->queue.lock);
  6657. + return -ESHUTDOWN;
  6658. + }
  6659. +
  6660. + if (test_bit(SSH_REQUEST_SF_LOCKED_BIT, &rqst->state)) {
  6661. + spin_unlock(&rtl->queue.lock);
  6662. + return -EINVAL;
  6663. + }
  6664. +
  6665. + set_bit(SSH_REQUEST_SF_QUEUED_BIT, &rqst->state);
  6666. + list_add_tail(&ssh_request_get(rqst)->node, &rtl->queue.head);
  6667. +
  6668. + spin_unlock(&rtl->queue.lock);
  6669. +
  6670. + ssh_rtl_tx_schedule(rtl);
  6671. + return 0;
  6672. +}
  6673. +
  6674. +static void ssh_rtl_timeout_reaper_mod(struct ssh_rtl *rtl, ktime_t now,
  6675. + ktime_t expires)
  6676. +{
  6677. + unsigned long delta = msecs_to_jiffies(ktime_ms_delta(expires, now));
  6678. + ktime_t aexp = ktime_add(expires, SSH_RTL_REQUEST_TIMEOUT_RESOLUTION);
  6679. +
  6680. + spin_lock(&rtl->rtx_timeout.lock);
  6681. +
  6682. + /* Re-adjust / schedule reaper only if it is above resolution delta. */
  6683. + if (ktime_before(aexp, rtl->rtx_timeout.expires)) {
  6684. + rtl->rtx_timeout.expires = expires;
  6685. + mod_delayed_work(system_wq, &rtl->rtx_timeout.reaper, delta);
  6686. + }
  6687. +
  6688. + spin_unlock(&rtl->rtx_timeout.lock);
  6689. +}
  6690. +
  6691. +static void ssh_rtl_timeout_start(struct ssh_request *rqst)
  6692. +{
  6693. + struct ssh_rtl *rtl = ssh_request_rtl(rqst);
  6694. + ktime_t timestamp = ktime_get_coarse_boottime();
  6695. + ktime_t timeout = rtl->rtx_timeout.timeout;
  6696. +
  6697. + if (test_bit(SSH_REQUEST_SF_LOCKED_BIT, &rqst->state))
  6698. + return;
  6699. +
  6700. + /*
  6701. + * Note: The timestamp gets set only once. This happens on the packet
  6702. + * callback. All other access to it is read-only.
  6703. + */
  6704. + WRITE_ONCE(rqst->timestamp, timestamp);
  6705. + /*
  6706. + * Ensure timestamp is set before starting the reaper. Paired with
  6707. + * implicit barrier following check on ssh_request_get_expiration() in
  6708. + * ssh_rtl_timeout_reap.
  6709. + */
  6710. + smp_mb__after_atomic();
  6711. +
  6712. + ssh_rtl_timeout_reaper_mod(rtl, timestamp, timestamp + timeout);
  6713. +}
  6714. +
  6715. +static void ssh_rtl_complete(struct ssh_rtl *rtl,
  6716. + const struct ssh_command *command,
  6717. + const struct ssam_span *command_data)
  6718. +{
  6719. + struct ssh_request *r = NULL;
  6720. + struct ssh_request *p, *n;
  6721. + u16 rqid = get_unaligned_le16(&command->rqid);
  6722. +
  6723. + /*
  6724. + * Get request from pending based on request ID and mark it as response
  6725. + * received and locked.
  6726. + */
  6727. + spin_lock(&rtl->pending.lock);
  6728. + list_for_each_entry_safe(p, n, &rtl->pending.head, node) {
  6729. + /* We generally expect requests to be processed in order. */
  6730. + if (unlikely(ssh_request_get_rqid(p) != rqid))
  6731. + continue;
  6732. +
  6733. + /*
  6734. + * Mark as "response received" and "locked" as we're going to
  6735. + * complete it.
  6736. + */
  6737. + set_bit(SSH_REQUEST_SF_LOCKED_BIT, &p->state);
  6738. + set_bit(SSH_REQUEST_SF_RSPRCVD_BIT, &p->state);
  6739. + /* Ensure state never gets zero. */
  6740. + smp_mb__before_atomic();
  6741. + clear_bit(SSH_REQUEST_SF_PENDING_BIT, &p->state);
  6742. +
  6743. + atomic_dec(&rtl->pending.count);
  6744. + list_del(&p->node);
  6745. +
  6746. + r = p;
  6747. + break;
  6748. + }
  6749. + spin_unlock(&rtl->pending.lock);
  6750. +
  6751. + if (!r) {
  6752. + rtl_warn(rtl, "rtl: dropping unexpected command message (rqid = %#06x)\n",
  6753. + rqid);
  6754. + return;
  6755. + }
  6756. +
  6757. + /* If the request hasn't been completed yet, we will do this now. */
  6758. + if (test_and_set_bit(SSH_REQUEST_SF_COMPLETED_BIT, &r->state)) {
  6759. + ssh_request_put(r);
  6760. + ssh_rtl_tx_schedule(rtl);
  6761. + return;
  6762. + }
  6763. +
  6764. + /*
  6765. + * Make sure the request has been transmitted. In case of a sequenced
  6766. + * request, we are guaranteed that the completion callback will run on
  6767. + * the receiver thread directly when the ACK for the packet has been
  6768. + * received. Similarly, this function is guaranteed to run on the
  6769. + * receiver thread. Thus we are guaranteed that if the packet has been
  6770. + * successfully transmitted and received an ACK, the transmitted flag
  6771. + * has been set and is visible here.
  6772. + *
  6773. + * We are currently not handling unsequenced packets here, as those
  6774. + * should never expect a response as ensured in ssh_rtl_submit. If this
  6775. + * ever changes, one would have to test for
  6776. + *
  6777. + * (r->state & (transmitting | transmitted))
  6778. + *
  6779. + * on unsequenced packets to determine if they could have been
  6780. + * transmitted. There are no synchronization guarantees as in the
  6781. + * sequenced case, since, in this case, the callback function will not
  6782. + * run on the same thread. Thus an exact determination is impossible.
  6783. + */
  6784. + if (!test_bit(SSH_REQUEST_SF_TRANSMITTED_BIT, &r->state)) {
  6785. + rtl_err(rtl, "rtl: received response before ACK for request (rqid = %#06x)\n",
  6786. + rqid);
  6787. +
  6788. + /*
  6789. + * NB: Timeout has already been canceled, request already been
  6790. + * removed from pending and marked as locked and completed. As
  6791. + * we receive a "false" response, the packet might still be
  6792. + * queued though.
  6793. + */
  6794. + ssh_rtl_queue_remove(r);
  6795. +
  6796. + ssh_rtl_complete_with_status(r, -EREMOTEIO);
  6797. + ssh_request_put(r);
  6798. +
  6799. + ssh_rtl_tx_schedule(rtl);
  6800. + return;
  6801. + }
  6802. +
  6803. + /*
  6804. + * NB: Timeout has already been canceled, request already been
  6805. + * removed from pending and marked as locked and completed. The request
  6806. + * can also not be queued any more, as it has been marked as
  6807. + * transmitting and later transmitted. Thus no need to remove it from
  6808. + * anywhere.
  6809. + */
  6810. +
  6811. + ssh_rtl_complete_with_rsp(r, command, command_data);
  6812. + ssh_request_put(r);
  6813. +
  6814. + ssh_rtl_tx_schedule(rtl);
  6815. +}
  6816. +
  6817. +static bool ssh_rtl_cancel_nonpending(struct ssh_request *r)
  6818. +{
  6819. + struct ssh_rtl *rtl;
  6820. + unsigned long flags, fixed;
  6821. + bool remove;
  6822. +
  6823. + /*
  6824. + * Handle unsubmitted request: Try to mark the packet as locked,
  6825. + * expecting the state to be zero (i.e. unsubmitted). Note that, if
  6826. + * setting the state worked, we might still be adding the packet to the
  6827. + * queue in a currently executing submit call. In that case, however,
  6828. + * ptl reference must have been set previously, as locked is checked
  6829. + * after setting ptl. Furthermore, when the ptl reference is set, the
  6830. + * submission process is guaranteed to have entered the critical
  6831. + * section. Thus only if we successfully locked this request and ptl is
  6832. + * NULL, we have successfully removed the request, i.e. we are
  6833. + * guaranteed that, due to the "locked" check in ssh_rtl_submit(), the
  6834. + * packet will never be added. Otherwise, we need to try and grab it
  6835. + * from the queue, where we are now guaranteed that the packet is or has
  6836. + * been due to the critical section.
  6837. + *
  6838. + * Note that if the cmpxchg() fails, we are guaranteed that ptl has
  6839. + * been set and is non-NULL, as states can only be nonzero after this
  6840. + * has been set. Also note that we need to fetch the static (type)
  6841. + * flags to ensure that they don't cause the cmpxchg() to fail.
  6842. + */
  6843. + fixed = READ_ONCE(r->state) & SSH_REQUEST_FLAGS_TY_MASK;
  6844. + flags = cmpxchg(&r->state, fixed, SSH_REQUEST_SF_LOCKED_BIT);
  6845. +
  6846. + /*
  6847. + * Force correct ordering with regards to state and ptl reference access
  6848. + * to safe-guard cancellation to concurrent submission against a
  6849. + * lost-update problem. First try to exchange state, then also check
  6850. + * ptl if that worked. This barrier is paired with the
  6851. + * one in ssh_rtl_submit().
  6852. + */
  6853. + smp_mb__after_atomic();
  6854. +
  6855. + if (flags == fixed && !READ_ONCE(r->packet.ptl)) {
  6856. + if (test_and_set_bit(SSH_REQUEST_SF_COMPLETED_BIT, &r->state))
  6857. + return true;
  6858. +
  6859. + ssh_rtl_complete_with_status(r, -ECANCELED);
  6860. + return true;
  6861. + }
  6862. +
  6863. + rtl = ssh_request_rtl(r);
  6864. + spin_lock(&rtl->queue.lock);
  6865. +
  6866. + /*
  6867. + * Note: 1) Requests cannot be re-submitted. 2) If a request is
  6868. + * queued, it cannot be "transmitting"/"pending" yet. Thus, if we
  6869. + * successfully remove the request here, we have removed all its
  6870. + * occurrences in the system.
  6871. + */
  6872. +
  6873. + remove = test_and_clear_bit(SSH_REQUEST_SF_QUEUED_BIT, &r->state);
  6874. + if (!remove) {
  6875. + spin_unlock(&rtl->queue.lock);
  6876. + return false;
  6877. + }
  6878. +
  6879. + set_bit(SSH_REQUEST_SF_LOCKED_BIT, &r->state);
  6880. + list_del(&r->node);
  6881. +
  6882. + spin_unlock(&rtl->queue.lock);
  6883. +
  6884. + ssh_request_put(r); /* Drop reference obtained from queue. */
  6885. +
  6886. + if (test_and_set_bit(SSH_REQUEST_SF_COMPLETED_BIT, &r->state))
  6887. + return true;
  6888. +
  6889. + ssh_rtl_complete_with_status(r, -ECANCELED);
  6890. + return true;
  6891. +}
  6892. +
  6893. +static bool ssh_rtl_cancel_pending(struct ssh_request *r)
  6894. +{
  6895. + /* If the packet is already locked, it's going to be removed shortly. */
  6896. + if (test_and_set_bit(SSH_REQUEST_SF_LOCKED_BIT, &r->state))
  6897. + return true;
  6898. +
  6899. + /*
  6900. + * Now that we have locked the packet, we have guaranteed that it can't
  6901. + * be added to the system any more. If ptl is NULL, the locked
  6902. + * check in ssh_rtl_submit() has not been run and any submission,
  6903. + * currently in progress or called later, won't add the packet. Thus we
  6904. + * can directly complete it.
  6905. + *
  6906. + * The implicit memory barrier of test_and_set_bit() should be enough
  6907. + * to ensure that the correct order (first lock, then check ptl) is
  6908. + * ensured. This is paired with the barrier in ssh_rtl_submit().
  6909. + */
  6910. + if (!READ_ONCE(r->packet.ptl)) {
  6911. + if (test_and_set_bit(SSH_REQUEST_SF_COMPLETED_BIT, &r->state))
  6912. + return true;
  6913. +
  6914. + ssh_rtl_complete_with_status(r, -ECANCELED);
  6915. + return true;
  6916. + }
  6917. +
  6918. + /*
  6919. + * Try to cancel the packet. If the packet has not been completed yet,
  6920. + * this will subsequently (and synchronously) call the completion
  6921. + * callback of the packet, which will complete the request.
  6922. + */
  6923. + ssh_ptl_cancel(&r->packet);
  6924. +
  6925. + /*
  6926. + * If the packet has been completed with success, i.e. has not been
  6927. + * canceled by the above call, the request may not have been completed
  6928. + * yet (may be waiting for a response). Check if we need to do this
  6929. + * here.
  6930. + */
  6931. + if (test_and_set_bit(SSH_REQUEST_SF_COMPLETED_BIT, &r->state))
  6932. + return true;
  6933. +
  6934. + ssh_rtl_queue_remove(r);
  6935. + ssh_rtl_pending_remove(r);
  6936. + ssh_rtl_complete_with_status(r, -ECANCELED);
  6937. +
  6938. + return true;
  6939. +}
  6940. +
  6941. +/**
  6942. + * ssh_rtl_cancel() - Cancel request.
  6943. + * @rqst: The request to cancel.
  6944. + * @pending: Whether to also cancel pending requests.
  6945. + *
  6946. + * Cancels the given request. If @pending is %false, this will not cancel
  6947. + * pending requests, i.e. requests that have already been submitted to the
  6948. + * packet layer but not been completed yet. If @pending is %true, this will
  6949. + * cancel the given request regardless of the state it is in.
  6950. + *
  6951. + * If the request has been canceled by calling this function, both completion
  6952. + * and release callbacks of the request will be executed in a reasonable
  6953. + * time-frame. This may happen during execution of this function, however,
  6954. + * there is no guarantee for this. For example, a request currently
  6955. + * transmitting will be canceled/completed only after transmission has
  6956. + * completed, and the respective callbacks will be executed on the transmitter
  6957. + * thread, which may happen during, but also some time after execution of the
  6958. + * cancel function.
  6959. + *
  6960. + * Return: Returns %true if the given request has been canceled or completed,
  6961. + * either by this function or prior to calling this function, %false
  6962. + * otherwise. If @pending is %true, this function will always return %true.
  6963. + */
  6964. +bool ssh_rtl_cancel(struct ssh_request *rqst, bool pending)
  6965. +{
  6966. + struct ssh_rtl *rtl;
  6967. + bool canceled;
  6968. +
  6969. + if (test_and_set_bit(SSH_REQUEST_SF_CANCELED_BIT, &rqst->state))
  6970. + return true;
  6971. +
  6972. + if (pending)
  6973. + canceled = ssh_rtl_cancel_pending(rqst);
  6974. + else
  6975. + canceled = ssh_rtl_cancel_nonpending(rqst);
  6976. +
  6977. + /* Note: rtl may be NULL if request has not been submitted yet. */
  6978. + rtl = ssh_request_rtl(rqst);
  6979. + if (canceled && rtl)
  6980. + ssh_rtl_tx_schedule(rtl);
  6981. +
  6982. + return canceled;
  6983. +}
  6984. +
  6985. +static void ssh_rtl_packet_callback(struct ssh_packet *p, int status)
  6986. +{
  6987. + struct ssh_request *r = to_ssh_request(p);
  6988. +
  6989. + if (unlikely(status)) {
  6990. + set_bit(SSH_REQUEST_SF_LOCKED_BIT, &r->state);
  6991. +
  6992. + if (test_and_set_bit(SSH_REQUEST_SF_COMPLETED_BIT, &r->state))
  6993. + return;
  6994. +
  6995. + /*
  6996. + * The packet may get canceled even though it has not been
  6997. + * submitted yet. The request may still be queued. Check the
  6998. + * queue and remove it if necessary. As the timeout would have
  6999. + * been started in this function on success, there's no need
  7000. + * to cancel it here.
  7001. + */
  7002. + ssh_rtl_queue_remove(r);
  7003. + ssh_rtl_pending_remove(r);
  7004. + ssh_rtl_complete_with_status(r, status);
  7005. +
  7006. + ssh_rtl_tx_schedule(ssh_request_rtl(r));
  7007. + return;
  7008. + }
  7009. +
  7010. + /* Update state: Mark as transmitted and clear transmitting. */
  7011. + set_bit(SSH_REQUEST_SF_TRANSMITTED_BIT, &r->state);
  7012. + /* Ensure state never gets zero. */
  7013. + smp_mb__before_atomic();
  7014. + clear_bit(SSH_REQUEST_SF_TRANSMITTING_BIT, &r->state);
  7015. +
  7016. + /* If we expect a response, we just need to start the timeout. */
  7017. + if (test_bit(SSH_REQUEST_TY_HAS_RESPONSE_BIT, &r->state)) {
  7018. + /*
  7019. + * Note: This is the only place where the timestamp gets set,
  7020. + * all other access to it is read-only.
  7021. + */
  7022. + ssh_rtl_timeout_start(r);
  7023. + return;
  7024. + }
  7025. +
  7026. + /*
  7027. + * If we don't expect a response, lock, remove, and complete the
  7028. + * request. Note that, at this point, the request is guaranteed to have
  7029. + * left the queue and no timeout has been started. Thus we only need to
  7030. + * remove it from pending. If the request has already been completed (it
  7031. + * may have been canceled) return.
  7032. + */
  7033. +
  7034. + set_bit(SSH_REQUEST_SF_LOCKED_BIT, &r->state);
  7035. + if (test_and_set_bit(SSH_REQUEST_SF_COMPLETED_BIT, &r->state))
  7036. + return;
  7037. +
  7038. + ssh_rtl_pending_remove(r);
  7039. + ssh_rtl_complete_with_status(r, 0);
  7040. +
  7041. + ssh_rtl_tx_schedule(ssh_request_rtl(r));
  7042. +}
  7043. +
  7044. +static ktime_t ssh_request_get_expiration(struct ssh_request *r, ktime_t timeout)
  7045. +{
  7046. + ktime_t timestamp = READ_ONCE(r->timestamp);
  7047. +
  7048. + if (timestamp != KTIME_MAX)
  7049. + return ktime_add(timestamp, timeout);
  7050. + else
  7051. + return KTIME_MAX;
  7052. +}
  7053. +
  7054. +static void ssh_rtl_timeout_reap(struct work_struct *work)
  7055. +{
  7056. + struct ssh_rtl *rtl = to_ssh_rtl(work, rtx_timeout.reaper.work);
  7057. + struct ssh_request *r, *n;
  7058. + LIST_HEAD(claimed);
  7059. + ktime_t now = ktime_get_coarse_boottime();
  7060. + ktime_t timeout = rtl->rtx_timeout.timeout;
  7061. + ktime_t next = KTIME_MAX;
  7062. +
  7063. + /*
  7064. + * Mark reaper as "not pending". This is done before checking any
  7065. + * requests to avoid lost-update type problems.
  7066. + */
  7067. + spin_lock(&rtl->rtx_timeout.lock);
  7068. + rtl->rtx_timeout.expires = KTIME_MAX;
  7069. + spin_unlock(&rtl->rtx_timeout.lock);
  7070. +
  7071. + spin_lock(&rtl->pending.lock);
  7072. + list_for_each_entry_safe(r, n, &rtl->pending.head, node) {
  7073. + ktime_t expires = ssh_request_get_expiration(r, timeout);
  7074. +
  7075. + /*
  7076. + * Check if the timeout hasn't expired yet. Find out next
  7077. + * expiration date to be handled after this run.
  7078. + */
  7079. + if (ktime_after(expires, now)) {
  7080. + next = ktime_before(expires, next) ? expires : next;
  7081. + continue;
  7082. + }
  7083. +
  7084. + /* Avoid further transitions if locked. */
  7085. + if (test_and_set_bit(SSH_REQUEST_SF_LOCKED_BIT, &r->state))
  7086. + continue;
  7087. +
  7088. + /*
  7089. + * We have now marked the packet as locked. Thus it cannot be
  7090. + * added to the pending or queued lists again after we've
  7091. + * removed it here. We can therefore re-use the node of this
  7092. + * packet temporarily.
  7093. + */
  7094. +
  7095. + clear_bit(SSH_REQUEST_SF_PENDING_BIT, &r->state);
  7096. +
  7097. + atomic_dec(&rtl->pending.count);
  7098. + list_del(&r->node);
  7099. +
  7100. + list_add_tail(&r->node, &claimed);
  7101. + }
  7102. + spin_unlock(&rtl->pending.lock);
  7103. +
  7104. + /* Cancel and complete the request. */
  7105. + list_for_each_entry_safe(r, n, &claimed, node) {
  7106. + /*
  7107. + * At this point we've removed the packet from pending. This
  7108. + * means that we've obtained the last (only) reference of the
  7109. + * system to it. Thus we can just complete it.
  7110. + */
  7111. + if (!test_and_set_bit(SSH_REQUEST_SF_COMPLETED_BIT, &r->state))
  7112. + ssh_rtl_complete_with_status(r, -ETIMEDOUT);
  7113. +
  7114. + /*
  7115. + * Drop the reference we've obtained by removing it from the
  7116. + * pending set.
  7117. + */
  7118. + list_del(&r->node);
  7119. + ssh_request_put(r);
  7120. + }
  7121. +
  7122. + /* Ensure that the reaper doesn't run again immediately. */
  7123. + next = max(next, ktime_add(now, SSH_RTL_REQUEST_TIMEOUT_RESOLUTION));
  7124. + if (next != KTIME_MAX)
  7125. + ssh_rtl_timeout_reaper_mod(rtl, now, next);
  7126. +
  7127. + ssh_rtl_tx_schedule(rtl);
  7128. +}
  7129. +
  7130. +static void ssh_rtl_rx_event(struct ssh_rtl *rtl, const struct ssh_command *cmd,
  7131. + const struct ssam_span *data)
  7132. +{
  7133. + rtl_dbg(rtl, "rtl: handling event (rqid: %#06x)\n",
  7134. + get_unaligned_le16(&cmd->rqid));
  7135. +
  7136. + rtl->ops.handle_event(rtl, cmd, data);
  7137. +}
  7138. +
  7139. +static void ssh_rtl_rx_command(struct ssh_ptl *p, const struct ssam_span *data)
  7140. +{
  7141. + struct ssh_rtl *rtl = to_ssh_rtl(p, ptl);
  7142. + struct device *dev = &p->serdev->dev;
  7143. + struct ssh_command *command;
  7144. + struct ssam_span command_data;
  7145. +
  7146. + if (sshp_parse_command(dev, data, &command, &command_data))
  7147. + return;
  7148. +
  7149. + if (ssh_rqid_is_event(get_unaligned_le16(&command->rqid)))
  7150. + ssh_rtl_rx_event(rtl, command, &command_data);
  7151. + else
  7152. + ssh_rtl_complete(rtl, command, &command_data);
  7153. +}
  7154. +
  7155. +static void ssh_rtl_rx_data(struct ssh_ptl *p, const struct ssam_span *data)
  7156. +{
  7157. + if (!data->len) {
  7158. + ptl_err(p, "rtl: rx: no data frame payload\n");
  7159. + return;
  7160. + }
  7161. +
  7162. + switch (data->ptr[0]) {
  7163. + case SSH_PLD_TYPE_CMD:
  7164. + ssh_rtl_rx_command(p, data);
  7165. + break;
  7166. +
  7167. + default:
  7168. + ptl_err(p, "rtl: rx: unknown frame payload type (type: %#04x)\n",
  7169. + data->ptr[0]);
  7170. + break;
  7171. + }
  7172. +}
  7173. +
  7174. +static void ssh_rtl_packet_release(struct ssh_packet *p)
  7175. +{
  7176. + struct ssh_request *rqst;
  7177. +
  7178. + rqst = to_ssh_request(p);
  7179. + rqst->ops->release(rqst);
  7180. +}
  7181. +
  7182. +static const struct ssh_packet_ops ssh_rtl_packet_ops = {
  7183. + .complete = ssh_rtl_packet_callback,
  7184. + .release = ssh_rtl_packet_release,
  7185. +};
  7186. +
  7187. +/**
  7188. + * ssh_request_init() - Initialize SSH request.
  7189. + * @rqst: The request to initialize.
  7190. + * @flags: Request flags, determining the type of the request.
  7191. + * @ops: Request operations.
  7192. + *
  7193. + * Initializes the given SSH request and underlying packet. Sets the message
  7194. + * buffer pointer to %NULL and the message buffer length to zero. This buffer
  7195. + * has to be set separately via ssh_request_set_data() before submission and
  7196. + * must contain a valid SSH request message.
  7197. + *
  7198. + * Return: Returns zero on success or %-EINVAL if the given flags are invalid.
  7199. + */
  7200. +int ssh_request_init(struct ssh_request *rqst, enum ssam_request_flags flags,
  7201. + const struct ssh_request_ops *ops)
  7202. +{
  7203. + unsigned long type = BIT(SSH_PACKET_TY_BLOCKING_BIT);
  7204. +
  7205. + /* Unsequenced requests cannot have a response. */
  7206. + if (flags & SSAM_REQUEST_UNSEQUENCED && flags & SSAM_REQUEST_HAS_RESPONSE)
  7207. + return -EINVAL;
  7208. +
  7209. + if (!(flags & SSAM_REQUEST_UNSEQUENCED))
  7210. + type |= BIT(SSH_PACKET_TY_SEQUENCED_BIT);
  7211. +
  7212. + ssh_packet_init(&rqst->packet, type, SSH_PACKET_PRIORITY(DATA, 0),
  7213. + &ssh_rtl_packet_ops);
  7214. +
  7215. + INIT_LIST_HEAD(&rqst->node);
  7216. +
  7217. + rqst->state = 0;
  7218. + if (flags & SSAM_REQUEST_HAS_RESPONSE)
  7219. + rqst->state |= BIT(SSH_REQUEST_TY_HAS_RESPONSE_BIT);
  7220. +
  7221. + rqst->timestamp = KTIME_MAX;
  7222. + rqst->ops = ops;
  7223. +
  7224. + return 0;
  7225. +}
  7226. +
  7227. +/**
  7228. + * ssh_rtl_init() - Initialize request transport layer.
  7229. + * @rtl: The request transport layer to initialize.
  7230. + * @serdev: The underlying serial device, i.e. the lower-level transport.
  7231. + * @ops: Request transport layer operations.
  7232. + *
  7233. + * Initializes the given request transport layer and associated packet
  7234. + * transport layer. Transmitter and receiver threads must be started
  7235. + * separately via ssh_rtl_tx_start() and ssh_rtl_rx_start(), after the
  7236. + * request-layer has been initialized and the lower-level serial device layer
  7237. + * has been set up.
  7238. + *
  7239. + * Return: Returns zero on success and a nonzero error code on failure.
  7240. + */
  7241. +int ssh_rtl_init(struct ssh_rtl *rtl, struct serdev_device *serdev,
  7242. + const struct ssh_rtl_ops *ops)
  7243. +{
  7244. + struct ssh_ptl_ops ptl_ops;
  7245. + int status;
  7246. +
  7247. + ptl_ops.data_received = ssh_rtl_rx_data;
  7248. +
  7249. + status = ssh_ptl_init(&rtl->ptl, serdev, &ptl_ops);
  7250. + if (status)
  7251. + return status;
  7252. +
  7253. + spin_lock_init(&rtl->queue.lock);
  7254. + INIT_LIST_HEAD(&rtl->queue.head);
  7255. +
  7256. + spin_lock_init(&rtl->pending.lock);
  7257. + INIT_LIST_HEAD(&rtl->pending.head);
  7258. + atomic_set_release(&rtl->pending.count, 0);
  7259. +
  7260. + INIT_WORK(&rtl->tx.work, ssh_rtl_tx_work_fn);
  7261. +
  7262. + spin_lock_init(&rtl->rtx_timeout.lock);
  7263. + rtl->rtx_timeout.timeout = SSH_RTL_REQUEST_TIMEOUT;
  7264. + rtl->rtx_timeout.expires = KTIME_MAX;
  7265. + INIT_DELAYED_WORK(&rtl->rtx_timeout.reaper, ssh_rtl_timeout_reap);
  7266. +
  7267. + rtl->ops = *ops;
  7268. +
  7269. + return 0;
  7270. +}
  7271. +
  7272. +/**
  7273. + * ssh_rtl_destroy() - Deinitialize request transport layer.
  7274. + * @rtl: The request transport layer to deinitialize.
  7275. + *
  7276. + * Deinitializes the given request transport layer and frees resources
  7277. + * associated with it. If receiver and/or transmitter threads have been
  7278. + * started, the layer must first be shut down via ssh_rtl_shutdown() before
  7279. + * this function can be called.
  7280. + */
  7281. +void ssh_rtl_destroy(struct ssh_rtl *rtl)
  7282. +{
  7283. + ssh_ptl_destroy(&rtl->ptl);
  7284. +}
  7285. +
  7286. +/**
  7287. + * ssh_rtl_tx_start() - Start request transmitter and receiver.
  7288. + * @rtl: The request transport layer.
  7289. + *
  7290. + * Return: Returns zero on success, a negative error code on failure.
  7291. + */
  7292. +int ssh_rtl_start(struct ssh_rtl *rtl)
  7293. +{
  7294. + int status;
  7295. +
  7296. + status = ssh_ptl_tx_start(&rtl->ptl);
  7297. + if (status)
  7298. + return status;
  7299. +
  7300. + ssh_rtl_tx_schedule(rtl);
  7301. +
  7302. + status = ssh_ptl_rx_start(&rtl->ptl);
  7303. + if (status) {
  7304. + ssh_rtl_flush(rtl, msecs_to_jiffies(5000));
  7305. + ssh_ptl_tx_stop(&rtl->ptl);
  7306. + return status;
  7307. + }
  7308. +
  7309. + return 0;
  7310. +}
  7311. +
  7312. +struct ssh_flush_request {
  7313. + struct ssh_request base;
  7314. + struct completion completion;
  7315. + int status;
  7316. +};
  7317. +
  7318. +static void ssh_rtl_flush_request_complete(struct ssh_request *r,
  7319. + const struct ssh_command *cmd,
  7320. + const struct ssam_span *data,
  7321. + int status)
  7322. +{
  7323. + struct ssh_flush_request *rqst;
  7324. +
  7325. + rqst = container_of(r, struct ssh_flush_request, base);
  7326. + rqst->status = status;
  7327. +}
  7328. +
  7329. +static void ssh_rtl_flush_request_release(struct ssh_request *r)
  7330. +{
  7331. + struct ssh_flush_request *rqst;
  7332. +
  7333. + rqst = container_of(r, struct ssh_flush_request, base);
  7334. + complete_all(&rqst->completion);
  7335. +}
  7336. +
  7337. +static const struct ssh_request_ops ssh_rtl_flush_request_ops = {
  7338. + .complete = ssh_rtl_flush_request_complete,
  7339. + .release = ssh_rtl_flush_request_release,
  7340. +};
  7341. +
  7342. +/**
  7343. + * ssh_rtl_flush() - Flush the request transport layer.
  7344. + * @rtl: request transport layer
  7345. + * @timeout: timeout for the flush operation in jiffies
  7346. + *
  7347. + * Queue a special flush request and wait for its completion. This request
  7348. + * will be completed after all other currently queued and pending requests
  7349. + * have been completed. Instead of a normal data packet, this request submits
  7350. + * a special flush packet, meaning that upon completion, also the underlying
  7351. + * packet transport layer has been flushed.
  7352. + *
  7353. + * Flushing the request layer guarantees that all previously submitted
  7354. + * requests have been fully completed before this call returns. Additionally,
  7355. + * flushing blocks execution of all later submitted requests until the flush
  7356. + * has been completed.
  7357. + *
  7358. + * If the caller ensures that no new requests are submitted after a call to
  7359. + * this function, the request transport layer is guaranteed to have no
  7360. + * remaining requests when this call returns. The same guarantee does not hold
  7361. + * for the packet layer, on which control packets may still be queued after
  7362. + * this call.
  7363. + *
  7364. + * Return: Returns zero on success, %-ETIMEDOUT if the flush timed out and has
  7365. + * been canceled as a result of the timeout, or %-ESHUTDOWN if the packet
  7366. + * and/or request transport layer has been shut down before this call. May
  7367. + * also return %-EINTR if the underlying packet transmission has been
  7368. + * interrupted.
  7369. + */
  7370. +int ssh_rtl_flush(struct ssh_rtl *rtl, unsigned long timeout)
  7371. +{
  7372. + const unsigned int init_flags = SSAM_REQUEST_UNSEQUENCED;
  7373. + struct ssh_flush_request rqst;
  7374. + int status;
  7375. +
  7376. + ssh_request_init(&rqst.base, init_flags, &ssh_rtl_flush_request_ops);
  7377. + rqst.base.packet.state |= BIT(SSH_PACKET_TY_FLUSH_BIT);
  7378. + rqst.base.packet.priority = SSH_PACKET_PRIORITY(FLUSH, 0);
  7379. + rqst.base.state |= BIT(SSH_REQUEST_TY_FLUSH_BIT);
  7380. +
  7381. + init_completion(&rqst.completion);
  7382. +
  7383. + status = ssh_rtl_submit(rtl, &rqst.base);
  7384. + if (status)
  7385. + return status;
  7386. +
  7387. + ssh_request_put(&rqst.base);
  7388. +
  7389. + if (!wait_for_completion_timeout(&rqst.completion, timeout)) {
  7390. + ssh_rtl_cancel(&rqst.base, true);
  7391. + wait_for_completion(&rqst.completion);
  7392. + }
  7393. +
  7394. + WARN_ON(rqst.status != 0 && rqst.status != -ECANCELED &&
  7395. + rqst.status != -ESHUTDOWN && rqst.status != -EINTR);
  7396. +
  7397. + return rqst.status == -ECANCELED ? -ETIMEDOUT : rqst.status;
  7398. +}
  7399. +
  7400. +/**
  7401. + * ssh_rtl_shutdown() - Shut down request transport layer.
  7402. + * @rtl: The request transport layer.
  7403. + *
  7404. + * Shuts down the request transport layer, removing and canceling all queued
  7405. + * and pending requests. Requests canceled by this operation will be completed
  7406. + * with %-ESHUTDOWN as status. Receiver and transmitter threads will be
  7407. + * stopped, the lower-level packet layer will be shutdown.
  7408. + *
  7409. + * As a result of this function, the transport layer will be marked as shut
  7410. + * down. Submission of requests after the transport layer has been shut down
  7411. + * will fail with %-ESHUTDOWN.
  7412. + */
  7413. +void ssh_rtl_shutdown(struct ssh_rtl *rtl)
  7414. +{
  7415. + struct ssh_request *r, *n;
  7416. + LIST_HEAD(claimed);
  7417. + int pending;
  7418. +
  7419. + set_bit(SSH_RTL_SF_SHUTDOWN_BIT, &rtl->state);
  7420. + /*
  7421. + * Ensure that the layer gets marked as shut-down before actually
  7422. + * stopping it. In combination with the check in ssh_rtl_submit(),
  7423. + * this guarantees that no new requests can be added and all already
  7424. + * queued requests are properly canceled.
  7425. + */
  7426. + smp_mb__after_atomic();
  7427. +
  7428. + /* Remove requests from queue. */
  7429. + spin_lock(&rtl->queue.lock);
  7430. + list_for_each_entry_safe(r, n, &rtl->queue.head, node) {
  7431. + set_bit(SSH_REQUEST_SF_LOCKED_BIT, &r->state);
  7432. + /* Ensure state never gets zero. */
  7433. + smp_mb__before_atomic();
  7434. + clear_bit(SSH_REQUEST_SF_QUEUED_BIT, &r->state);
  7435. +
  7436. + list_del(&r->node);
  7437. + list_add_tail(&r->node, &claimed);
  7438. + }
  7439. + spin_unlock(&rtl->queue.lock);
  7440. +
  7441. + /*
  7442. + * We have now guaranteed that the queue is empty and no more new
  7443. + * requests can be submitted (i.e. it will stay empty). This means that
  7444. + * calling ssh_rtl_tx_schedule() will not schedule tx.work any more. So
  7445. + * we can simply call cancel_work_sync() on tx.work here and when that
  7446. + * returns, we've locked it down. This also means that after this call,
  7447. + * we don't submit any more packets to the underlying packet layer, so
  7448. + * we can also shut that down.
  7449. + */
  7450. +
  7451. + cancel_work_sync(&rtl->tx.work);
  7452. + ssh_ptl_shutdown(&rtl->ptl);
  7453. + cancel_delayed_work_sync(&rtl->rtx_timeout.reaper);
  7454. +
  7455. + /*
  7456. + * Shutting down the packet layer should also have canceled all
  7457. + * requests. Thus the pending set should be empty. Attempt to handle
  7458. + * this gracefully anyways, even though this should be dead code.
  7459. + */
  7460. +
  7461. + pending = atomic_read(&rtl->pending.count);
  7462. + if (WARN_ON(pending)) {
  7463. + spin_lock(&rtl->pending.lock);
  7464. + list_for_each_entry_safe(r, n, &rtl->pending.head, node) {
  7465. + set_bit(SSH_REQUEST_SF_LOCKED_BIT, &r->state);
  7466. + /* Ensure state never gets zero. */
  7467. + smp_mb__before_atomic();
  7468. + clear_bit(SSH_REQUEST_SF_PENDING_BIT, &r->state);
  7469. +
  7470. + list_del(&r->node);
  7471. + list_add_tail(&r->node, &claimed);
  7472. + }
  7473. + spin_unlock(&rtl->pending.lock);
  7474. + }
  7475. +
  7476. + /* Finally, cancel and complete the requests we claimed before. */
  7477. + list_for_each_entry_safe(r, n, &claimed, node) {
  7478. + /*
  7479. + * We need test_and_set() because we still might compete with
  7480. + * cancellation.
  7481. + */
  7482. + if (!test_and_set_bit(SSH_REQUEST_SF_COMPLETED_BIT, &r->state))
  7483. + ssh_rtl_complete_with_status(r, -ESHUTDOWN);
  7484. +
  7485. + /*
  7486. + * Drop the reference we've obtained by removing it from the
  7487. + * lists.
  7488. + */
  7489. + list_del(&r->node);
  7490. + ssh_request_put(r);
  7491. + }
  7492. +}
  7493. diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.h b/drivers/platform/surface/aggregator/ssh_request_layer.h
  7494. new file mode 100644
  7495. index 000000000000..cb35815858d1
  7496. --- /dev/null
  7497. +++ b/drivers/platform/surface/aggregator/ssh_request_layer.h
  7498. @@ -0,0 +1,143 @@
  7499. +/* SPDX-License-Identifier: GPL-2.0+ */
  7500. +/*
  7501. + * SSH request transport layer.
  7502. + *
  7503. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  7504. + */
  7505. +
  7506. +#ifndef _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H
  7507. +#define _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H
  7508. +
  7509. +#include <linux/atomic.h>
  7510. +#include <linux/ktime.h>
  7511. +#include <linux/list.h>
  7512. +#include <linux/spinlock.h>
  7513. +#include <linux/workqueue.h>
  7514. +
  7515. +#include <linux/surface_aggregator/serial_hub.h>
  7516. +#include <linux/surface_aggregator/controller.h>
  7517. +
  7518. +#include "ssh_packet_layer.h"
  7519. +
  7520. +/**
  7521. + * enum ssh_rtl_state_flags - State-flags for &struct ssh_rtl.
  7522. + *
  7523. + * @SSH_RTL_SF_SHUTDOWN_BIT:
  7524. + * Indicates that the request transport layer has been shut down or is
  7525. + * being shut down and should not accept any new requests.
  7526. + */
  7527. +enum ssh_rtl_state_flags {
  7528. + SSH_RTL_SF_SHUTDOWN_BIT,
  7529. +};
  7530. +
  7531. +/**
  7532. + * struct ssh_rtl_ops - Callback operations for request transport layer.
  7533. + * @handle_event: Function called when a SSH event has been received. The
  7534. + * specified function takes the request layer, received command
  7535. + * struct, and corresponding payload as arguments. If the event
  7536. + * has no payload, the payload span is empty (not %NULL).
  7537. + */
  7538. +struct ssh_rtl_ops {
  7539. + void (*handle_event)(struct ssh_rtl *rtl, const struct ssh_command *cmd,
  7540. + const struct ssam_span *data);
  7541. +};
  7542. +
  7543. +/**
  7544. + * struct ssh_rtl - SSH request transport layer.
  7545. + * @ptl: Underlying packet transport layer.
  7546. + * @state: State(-flags) of the transport layer.
  7547. + * @queue: Request submission queue.
  7548. + * @queue.lock: Lock for modifying the request submission queue.
  7549. + * @queue.head: List-head of the request submission queue.
  7550. + * @pending: Set/list of pending requests.
  7551. + * @pending.lock: Lock for modifying the request set.
  7552. + * @pending.head: List-head of the pending set/list.
  7553. + * @pending.count: Number of currently pending requests.
  7554. + * @tx: Transmitter subsystem.
  7555. + * @tx.work: Transmitter work item.
  7556. + * @rtx_timeout: Retransmission timeout subsystem.
  7557. + * @rtx_timeout.lock: Lock for modifying the retransmission timeout reaper.
  7558. + * @rtx_timeout.timeout: Timeout interval for retransmission.
  7559. + * @rtx_timeout.expires: Time specifying when the reaper work is next scheduled.
  7560. + * @rtx_timeout.reaper: Work performing timeout checks and subsequent actions.
  7561. + * @ops: Request layer operations.
  7562. + */
  7563. +struct ssh_rtl {
  7564. + struct ssh_ptl ptl;
  7565. + unsigned long state;
  7566. +
  7567. + struct {
  7568. + spinlock_t lock;
  7569. + struct list_head head;
  7570. + } queue;
  7571. +
  7572. + struct {
  7573. + spinlock_t lock;
  7574. + struct list_head head;
  7575. + atomic_t count;
  7576. + } pending;
  7577. +
  7578. + struct {
  7579. + struct work_struct work;
  7580. + } tx;
  7581. +
  7582. + struct {
  7583. + spinlock_t lock;
  7584. + ktime_t timeout;
  7585. + ktime_t expires;
  7586. + struct delayed_work reaper;
  7587. + } rtx_timeout;
  7588. +
  7589. + struct ssh_rtl_ops ops;
  7590. +};
  7591. +
  7592. +#define rtl_dbg(r, fmt, ...) ptl_dbg(&(r)->ptl, fmt, ##__VA_ARGS__)
  7593. +#define rtl_info(p, fmt, ...) ptl_info(&(p)->ptl, fmt, ##__VA_ARGS__)
  7594. +#define rtl_warn(r, fmt, ...) ptl_warn(&(r)->ptl, fmt, ##__VA_ARGS__)
  7595. +#define rtl_err(r, fmt, ...) ptl_err(&(r)->ptl, fmt, ##__VA_ARGS__)
  7596. +#define rtl_dbg_cond(r, fmt, ...) __ssam_prcond(rtl_dbg, r, fmt, ##__VA_ARGS__)
  7597. +
  7598. +#define to_ssh_rtl(ptr, member) \
  7599. + container_of(ptr, struct ssh_rtl, member)
  7600. +
  7601. +/**
  7602. + * ssh_rtl_get_device() - Get device associated with request transport layer.
  7603. + * @rtl: The request transport layer.
  7604. + *
  7605. + * Return: Returns the device on which the given request transport layer
  7606. + * builds upon.
  7607. + */
  7608. +static inline struct device *ssh_rtl_get_device(struct ssh_rtl *rtl)
  7609. +{
  7610. + return ssh_ptl_get_device(&rtl->ptl);
  7611. +}
  7612. +
  7613. +/**
  7614. + * ssh_request_rtl() - Get request transport layer associated with request.
  7615. + * @rqst: The request to get the request transport layer reference for.
  7616. + *
  7617. + * Return: Returns the &struct ssh_rtl associated with the given SSH request.
  7618. + */
  7619. +static inline struct ssh_rtl *ssh_request_rtl(struct ssh_request *rqst)
  7620. +{
  7621. + struct ssh_ptl *ptl;
  7622. +
  7623. + ptl = READ_ONCE(rqst->packet.ptl);
  7624. + return likely(ptl) ? to_ssh_rtl(ptl, ptl) : NULL;
  7625. +}
  7626. +
  7627. +int ssh_rtl_submit(struct ssh_rtl *rtl, struct ssh_request *rqst);
  7628. +bool ssh_rtl_cancel(struct ssh_request *rqst, bool pending);
  7629. +
  7630. +int ssh_rtl_init(struct ssh_rtl *rtl, struct serdev_device *serdev,
  7631. + const struct ssh_rtl_ops *ops);
  7632. +
  7633. +int ssh_rtl_start(struct ssh_rtl *rtl);
  7634. +int ssh_rtl_flush(struct ssh_rtl *rtl, unsigned long timeout);
  7635. +void ssh_rtl_shutdown(struct ssh_rtl *rtl);
  7636. +void ssh_rtl_destroy(struct ssh_rtl *rtl);
  7637. +
  7638. +int ssh_request_init(struct ssh_request *rqst, enum ssam_request_flags flags,
  7639. + const struct ssh_request_ops *ops);
  7640. +
  7641. +#endif /* _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H */
  7642. diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h
  7643. new file mode 100644
  7644. index 000000000000..f4b1ba887384
  7645. --- /dev/null
  7646. +++ b/include/linux/surface_aggregator/controller.h
  7647. @@ -0,0 +1,824 @@
  7648. +/* SPDX-License-Identifier: GPL-2.0+ */
  7649. +/*
  7650. + * Surface System Aggregator Module (SSAM) controller interface.
  7651. + *
  7652. + * Main communication interface for the SSAM EC. Provides a controller
  7653. + * managing access and communication to and from the SSAM EC, as well as main
  7654. + * communication structures and definitions.
  7655. + *
  7656. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  7657. + */
  7658. +
  7659. +#ifndef _LINUX_SURFACE_AGGREGATOR_CONTROLLER_H
  7660. +#define _LINUX_SURFACE_AGGREGATOR_CONTROLLER_H
  7661. +
  7662. +#include <linux/completion.h>
  7663. +#include <linux/device.h>
  7664. +#include <linux/types.h>
  7665. +
  7666. +#include <linux/surface_aggregator/serial_hub.h>
  7667. +
  7668. +
  7669. +/* -- Main data types and definitions --------------------------------------- */
  7670. +
  7671. +/**
  7672. + * enum ssam_event_flags - Flags for enabling/disabling SAM events
  7673. + * @SSAM_EVENT_SEQUENCED: The event will be sent via a sequenced data frame.
  7674. + */
  7675. +enum ssam_event_flags {
  7676. + SSAM_EVENT_SEQUENCED = BIT(0),
  7677. +};
  7678. +
  7679. +/**
  7680. + * struct ssam_event - SAM event sent from the EC to the host.
  7681. + * @target_category: Target category of the event source. See &enum ssam_ssh_tc.
  7682. + * @target_id: Target ID of the event source.
  7683. + * @command_id: Command ID of the event.
  7684. + * @instance_id: Instance ID of the event source.
  7685. + * @length: Length of the event payload in bytes.
  7686. + * @data: Event payload data.
  7687. + */
  7688. +struct ssam_event {
  7689. + u8 target_category;
  7690. + u8 target_id;
  7691. + u8 command_id;
  7692. + u8 instance_id;
  7693. + u16 length;
  7694. + u8 data[];
  7695. +};
  7696. +
  7697. +/**
  7698. + * enum ssam_request_flags - Flags for SAM requests.
  7699. + *
  7700. + * @SSAM_REQUEST_HAS_RESPONSE:
  7701. + * Specifies that the request expects a response. If not set, the request
  7702. + * will be directly completed after its underlying packet has been
  7703. + * transmitted. If set, the request transport system waits for a response
  7704. + * of the request.
  7705. + *
  7706. + * @SSAM_REQUEST_UNSEQUENCED:
  7707. + * Specifies that the request should be transmitted via an unsequenced
  7708. + * packet. If set, the request must not have a response, meaning that this
  7709. + * flag and the %SSAM_REQUEST_HAS_RESPONSE flag are mutually exclusive.
  7710. + */
  7711. +enum ssam_request_flags {
  7712. + SSAM_REQUEST_HAS_RESPONSE = BIT(0),
  7713. + SSAM_REQUEST_UNSEQUENCED = BIT(1),
  7714. +};
  7715. +
  7716. +/**
  7717. + * struct ssam_request - SAM request description.
  7718. + * @target_category: Category of the request's target. See &enum ssam_ssh_tc.
  7719. + * @target_id: ID of the request's target.
  7720. + * @command_id: Command ID of the request.
  7721. + * @instance_id: Instance ID of the request's target.
  7722. + * @flags: Flags for the request. See &enum ssam_request_flags.
  7723. + * @length: Length of the request payload in bytes.
  7724. + * @payload: Request payload data.
  7725. + *
  7726. + * This struct fully describes a SAM request with payload. It is intended to
  7727. + * help set up the actual transport struct, e.g. &struct ssam_request_sync,
  7728. + * and specifically its raw message data via ssam_request_write_data().
  7729. + */
  7730. +struct ssam_request {
  7731. + u8 target_category;
  7732. + u8 target_id;
  7733. + u8 command_id;
  7734. + u8 instance_id;
  7735. + u16 flags;
  7736. + u16 length;
  7737. + const u8 *payload;
  7738. +};
  7739. +
  7740. +/**
  7741. + * struct ssam_response - Response buffer for SAM request.
  7742. + * @capacity: Capacity of the buffer, in bytes.
  7743. + * @length: Length of the actual data stored in the memory pointed to by
  7744. + * @pointer, in bytes. Set by the transport system.
  7745. + * @pointer: Pointer to the buffer's memory, storing the response payload data.
  7746. + */
  7747. +struct ssam_response {
  7748. + size_t capacity;
  7749. + size_t length;
  7750. + u8 *pointer;
  7751. +};
  7752. +
  7753. +struct ssam_controller;
  7754. +
  7755. +struct ssam_controller *ssam_get_controller(void);
  7756. +struct ssam_controller *ssam_client_bind(struct device *client);
  7757. +int ssam_client_link(struct ssam_controller *ctrl, struct device *client);
  7758. +
  7759. +struct device *ssam_controller_device(struct ssam_controller *c);
  7760. +
  7761. +struct ssam_controller *ssam_controller_get(struct ssam_controller *c);
  7762. +void ssam_controller_put(struct ssam_controller *c);
  7763. +
  7764. +void ssam_controller_statelock(struct ssam_controller *c);
  7765. +void ssam_controller_stateunlock(struct ssam_controller *c);
  7766. +
  7767. +ssize_t ssam_request_write_data(struct ssam_span *buf,
  7768. + struct ssam_controller *ctrl,
  7769. + const struct ssam_request *spec);
  7770. +
  7771. +
  7772. +/* -- Synchronous request interface. ---------------------------------------- */
  7773. +
  7774. +/**
  7775. + * struct ssam_request_sync - Synchronous SAM request struct.
  7776. + * @base: Underlying SSH request.
  7777. + * @comp: Completion used to signal full completion of the request. After the
  7778. + * request has been submitted, this struct may only be modified or
  7779. + * deallocated after the completion has been signaled.
  7780. + * request has been submitted,
  7781. + * @resp: Buffer to store the response.
  7782. + * @status: Status of the request, set after the base request has been
  7783. + * completed or has failed.
  7784. + */
  7785. +struct ssam_request_sync {
  7786. + struct ssh_request base;
  7787. + struct completion comp;
  7788. + struct ssam_response *resp;
  7789. + int status;
  7790. +};
  7791. +
  7792. +int ssam_request_sync_alloc(size_t payload_len, gfp_t flags,
  7793. + struct ssam_request_sync **rqst,
  7794. + struct ssam_span *buffer);
  7795. +
  7796. +void ssam_request_sync_free(struct ssam_request_sync *rqst);
  7797. +
  7798. +int ssam_request_sync_init(struct ssam_request_sync *rqst,
  7799. + enum ssam_request_flags flags);
  7800. +
  7801. +/**
  7802. + * ssam_request_sync_set_data - Set message data of a synchronous request.
  7803. + * @rqst: The request.
  7804. + * @ptr: Pointer to the request message data.
  7805. + * @len: Length of the request message data.
  7806. + *
  7807. + * Set the request message data of a synchronous request. The provided buffer
  7808. + * needs to live until the request has been completed.
  7809. + */
  7810. +static inline void ssam_request_sync_set_data(struct ssam_request_sync *rqst,
  7811. + u8 *ptr, size_t len)
  7812. +{
  7813. + ssh_request_set_data(&rqst->base, ptr, len);
  7814. +}
  7815. +
  7816. +/**
  7817. + * ssam_request_sync_set_resp - Set response buffer of a synchronous request.
  7818. + * @rqst: The request.
  7819. + * @resp: The response buffer.
  7820. + *
  7821. + * Sets the response buffer of a synchronous request. This buffer will store
  7822. + * the response of the request after it has been completed. May be %NULL if no
  7823. + * response is expected.
  7824. + */
  7825. +static inline void ssam_request_sync_set_resp(struct ssam_request_sync *rqst,
  7826. + struct ssam_response *resp)
  7827. +{
  7828. + rqst->resp = resp;
  7829. +}
  7830. +
  7831. +int ssam_request_sync_submit(struct ssam_controller *ctrl,
  7832. + struct ssam_request_sync *rqst);
  7833. +
  7834. +/**
  7835. + * ssam_request_sync_wait - Wait for completion of a synchronous request.
  7836. + * @rqst: The request to wait for.
  7837. + *
  7838. + * Wait for completion and release of a synchronous request. After this
  7839. + * function terminates, the request is guaranteed to have left the transport
  7840. + * system. After successful submission of a request, this function must be
  7841. + * called before accessing the response of the request, freeing the request,
  7842. + * or freeing any of the buffers associated with the request.
  7843. + *
  7844. + * This function must not be called if the request has not been submitted yet
  7845. + * and may lead to a deadlock/infinite wait if a subsequent request submission
  7846. + * fails in that case, due to the completion never triggering.
  7847. + *
  7848. + * Return: Returns the status of the given request, which is set on completion
  7849. + * of the packet. This value is zero on success and negative on failure.
  7850. + */
  7851. +static inline int ssam_request_sync_wait(struct ssam_request_sync *rqst)
  7852. +{
  7853. + wait_for_completion(&rqst->comp);
  7854. + return rqst->status;
  7855. +}
  7856. +
  7857. +int ssam_request_sync(struct ssam_controller *ctrl,
  7858. + const struct ssam_request *spec,
  7859. + struct ssam_response *rsp);
  7860. +
  7861. +int ssam_request_sync_with_buffer(struct ssam_controller *ctrl,
  7862. + const struct ssam_request *spec,
  7863. + struct ssam_response *rsp,
  7864. + struct ssam_span *buf);
  7865. +
  7866. +/**
  7867. + * ssam_request_sync_onstack - Execute a synchronous request on the stack.
  7868. + * @ctrl: The controller via which the request is submitted.
  7869. + * @rqst: The request specification.
  7870. + * @rsp: The response buffer.
  7871. + * @payload_len: The (maximum) request payload length.
  7872. + *
  7873. + * Allocates a synchronous request with specified payload length on the stack,
  7874. + * fully initializes it via the provided request specification, submits it,
  7875. + * and finally waits for its completion before returning its status. This
  7876. + * helper macro essentially allocates the request message buffer on the stack
  7877. + * and then calls ssam_request_sync_with_buffer().
  7878. + *
  7879. + * Note: The @payload_len parameter specifies the maximum payload length, used
  7880. + * for buffer allocation. The actual payload length may be smaller.
  7881. + *
  7882. + * Return: Returns the status of the request or any failure during setup, i.e.
  7883. + * zero on success and a negative value on failure.
  7884. + */
  7885. +#define ssam_request_sync_onstack(ctrl, rqst, rsp, payload_len) \
  7886. + ({ \
  7887. + u8 __data[SSH_COMMAND_MESSAGE_LENGTH(payload_len)]; \
  7888. + struct ssam_span __buf = { &__data[0], ARRAY_SIZE(__data) }; \
  7889. + \
  7890. + ssam_request_sync_with_buffer(ctrl, rqst, rsp, &__buf); \
  7891. + })
  7892. +
  7893. +/**
  7894. + * __ssam_retry - Retry request in case of I/O errors or timeouts.
  7895. + * @request: The request function to execute. Must return an integer.
  7896. + * @n: Number of tries.
  7897. + * @args: Arguments for the request function.
  7898. + *
  7899. + * Executes the given request function, i.e. calls @request. In case the
  7900. + * request returns %-EREMOTEIO (indicates I/O error) or %-ETIMEDOUT (request
  7901. + * or underlying packet timed out), @request will be re-executed again, up to
  7902. + * @n times in total.
  7903. + *
  7904. + * Return: Returns the return value of the last execution of @request.
  7905. + */
  7906. +#define __ssam_retry(request, n, args...) \
  7907. + ({ \
  7908. + int __i, __s = 0; \
  7909. + \
  7910. + for (__i = (n); __i > 0; __i--) { \
  7911. + __s = request(args); \
  7912. + if (__s != -ETIMEDOUT && __s != -EREMOTEIO) \
  7913. + break; \
  7914. + } \
  7915. + __s; \
  7916. + })
  7917. +
  7918. +/**
  7919. + * ssam_retry - Retry request in case of I/O errors or timeouts up to three
  7920. + * times in total.
  7921. + * @request: The request function to execute. Must return an integer.
  7922. + * @args: Arguments for the request function.
  7923. + *
  7924. + * Executes the given request function, i.e. calls @request. In case the
  7925. + * request returns %-EREMOTEIO (indicates I/O error) or -%ETIMEDOUT (request
  7926. + * or underlying packet timed out), @request will be re-executed again, up to
  7927. + * three times in total.
  7928. + *
  7929. + * See __ssam_retry() for a more generic macro for this purpose.
  7930. + *
  7931. + * Return: Returns the return value of the last execution of @request.
  7932. + */
  7933. +#define ssam_retry(request, args...) \
  7934. + __ssam_retry(request, 3, args)
  7935. +
  7936. +/**
  7937. + * struct ssam_request_spec - Blue-print specification of SAM request.
  7938. + * @target_category: Category of the request's target. See &enum ssam_ssh_tc.
  7939. + * @target_id: ID of the request's target.
  7940. + * @command_id: Command ID of the request.
  7941. + * @instance_id: Instance ID of the request's target.
  7942. + * @flags: Flags for the request. See &enum ssam_request_flags.
  7943. + *
  7944. + * Blue-print specification for a SAM request. This struct describes the
  7945. + * unique static parameters of a request (i.e. type) without specifying any of
  7946. + * its instance-specific data (e.g. payload). It is intended to be used as base
  7947. + * for defining simple request functions via the
  7948. + * ``SSAM_DEFINE_SYNC_REQUEST_x()`` family of macros.
  7949. + */
  7950. +struct ssam_request_spec {
  7951. + u8 target_category;
  7952. + u8 target_id;
  7953. + u8 command_id;
  7954. + u8 instance_id;
  7955. + u8 flags;
  7956. +};
  7957. +
  7958. +/**
  7959. + * struct ssam_request_spec_md - Blue-print specification for multi-device SAM
  7960. + * request.
  7961. + * @target_category: Category of the request's target. See &enum ssam_ssh_tc.
  7962. + * @command_id: Command ID of the request.
  7963. + * @flags: Flags for the request. See &enum ssam_request_flags.
  7964. + *
  7965. + * Blue-print specification for a multi-device SAM request, i.e. a request
  7966. + * that is applicable to multiple device instances, described by their
  7967. + * individual target and instance IDs. This struct describes the unique static
  7968. + * parameters of a request (i.e. type) without specifying any of its
  7969. + * instance-specific data (e.g. payload) and without specifying any of its
  7970. + * device specific IDs (i.e. target and instance ID). It is intended to be
  7971. + * used as base for defining simple multi-device request functions via the
  7972. + * ``SSAM_DEFINE_SYNC_REQUEST_MD_x()`` and ``SSAM_DEFINE_SYNC_REQUEST_CL_x()``
  7973. + * families of macros.
  7974. + */
  7975. +struct ssam_request_spec_md {
  7976. + u8 target_category;
  7977. + u8 command_id;
  7978. + u8 flags;
  7979. +};
  7980. +
  7981. +/**
  7982. + * SSAM_DEFINE_SYNC_REQUEST_N() - Define synchronous SAM request function
  7983. + * with neither argument nor return value.
  7984. + * @name: Name of the generated function.
  7985. + * @spec: Specification (&struct ssam_request_spec) defining the request.
  7986. + *
  7987. + * Defines a function executing the synchronous SAM request specified by
  7988. + * @spec, with the request having neither argument nor return value. The
  7989. + * generated function takes care of setting up the request struct and buffer
  7990. + * allocation, as well as execution of the request itself, returning once the
  7991. + * request has been fully completed. The required transport buffer will be
  7992. + * allocated on the stack.
  7993. + *
  7994. + * The generated function is defined as ``int name(struct ssam_controller
  7995. + * *ctrl)``, returning the status of the request, which is zero on success and
  7996. + * negative on failure. The ``ctrl`` parameter is the controller via which the
  7997. + * request is being sent.
  7998. + *
  7999. + * Refer to ssam_request_sync_onstack() for more details on the behavior of
  8000. + * the generated function.
  8001. + */
  8002. +#define SSAM_DEFINE_SYNC_REQUEST_N(name, spec...) \
  8003. + int name(struct ssam_controller *ctrl) \
  8004. + { \
  8005. + struct ssam_request_spec s = (struct ssam_request_spec)spec; \
  8006. + struct ssam_request rqst; \
  8007. + \
  8008. + rqst.target_category = s.target_category; \
  8009. + rqst.target_id = s.target_id; \
  8010. + rqst.command_id = s.command_id; \
  8011. + rqst.instance_id = s.instance_id; \
  8012. + rqst.flags = s.flags; \
  8013. + rqst.length = 0; \
  8014. + rqst.payload = NULL; \
  8015. + \
  8016. + return ssam_request_sync_onstack(ctrl, &rqst, NULL, 0); \
  8017. + }
  8018. +
  8019. +/**
  8020. + * SSAM_DEFINE_SYNC_REQUEST_W() - Define synchronous SAM request function with
  8021. + * argument.
  8022. + * @name: Name of the generated function.
  8023. + * @atype: Type of the request's argument.
  8024. + * @spec: Specification (&struct ssam_request_spec) defining the request.
  8025. + *
  8026. + * Defines a function executing the synchronous SAM request specified by
  8027. + * @spec, with the request taking an argument of type @atype and having no
  8028. + * return value. The generated function takes care of setting up the request
  8029. + * struct, buffer allocation, as well as execution of the request itself,
  8030. + * returning once the request has been fully completed. The required transport
  8031. + * buffer will be allocated on the stack.
  8032. + *
  8033. + * The generated function is defined as ``int name(struct ssam_controller
  8034. + * *ctrl, const atype *arg)``, returning the status of the request, which is
  8035. + * zero on success and negative on failure. The ``ctrl`` parameter is the
  8036. + * controller via which the request is sent. The request argument is specified
  8037. + * via the ``arg`` pointer.
  8038. + *
  8039. + * Refer to ssam_request_sync_onstack() for more details on the behavior of
  8040. + * the generated function.
  8041. + */
  8042. +#define SSAM_DEFINE_SYNC_REQUEST_W(name, atype, spec...) \
  8043. + int name(struct ssam_controller *ctrl, const atype *arg) \
  8044. + { \
  8045. + struct ssam_request_spec s = (struct ssam_request_spec)spec; \
  8046. + struct ssam_request rqst; \
  8047. + \
  8048. + rqst.target_category = s.target_category; \
  8049. + rqst.target_id = s.target_id; \
  8050. + rqst.command_id = s.command_id; \
  8051. + rqst.instance_id = s.instance_id; \
  8052. + rqst.flags = s.flags; \
  8053. + rqst.length = sizeof(atype); \
  8054. + rqst.payload = (u8 *)arg; \
  8055. + \
  8056. + return ssam_request_sync_onstack(ctrl, &rqst, NULL, \
  8057. + sizeof(atype)); \
  8058. + }
  8059. +
  8060. +/**
  8061. + * SSAM_DEFINE_SYNC_REQUEST_R() - Define synchronous SAM request function with
  8062. + * return value.
  8063. + * @name: Name of the generated function.
  8064. + * @rtype: Type of the request's return value.
  8065. + * @spec: Specification (&struct ssam_request_spec) defining the request.
  8066. + *
  8067. + * Defines a function executing the synchronous SAM request specified by
  8068. + * @spec, with the request taking no argument but having a return value of
  8069. + * type @rtype. The generated function takes care of setting up the request
  8070. + * and response structs, buffer allocation, as well as execution of the
  8071. + * request itself, returning once the request has been fully completed. The
  8072. + * required transport buffer will be allocated on the stack.
  8073. + *
  8074. + * The generated function is defined as ``int name(struct ssam_controller
  8075. + * *ctrl, rtype *ret)``, returning the status of the request, which is zero on
  8076. + * success and negative on failure. The ``ctrl`` parameter is the controller
  8077. + * via which the request is sent. The request's return value is written to the
  8078. + * memory pointed to by the ``ret`` parameter.
  8079. + *
  8080. + * Refer to ssam_request_sync_onstack() for more details on the behavior of
  8081. + * the generated function.
  8082. + */
  8083. +#define SSAM_DEFINE_SYNC_REQUEST_R(name, rtype, spec...) \
  8084. + int name(struct ssam_controller *ctrl, rtype *ret) \
  8085. + { \
  8086. + struct ssam_request_spec s = (struct ssam_request_spec)spec; \
  8087. + struct ssam_request rqst; \
  8088. + struct ssam_response rsp; \
  8089. + int status; \
  8090. + \
  8091. + rqst.target_category = s.target_category; \
  8092. + rqst.target_id = s.target_id; \
  8093. + rqst.command_id = s.command_id; \
  8094. + rqst.instance_id = s.instance_id; \
  8095. + rqst.flags = s.flags | SSAM_REQUEST_HAS_RESPONSE; \
  8096. + rqst.length = 0; \
  8097. + rqst.payload = NULL; \
  8098. + \
  8099. + rsp.capacity = sizeof(rtype); \
  8100. + rsp.length = 0; \
  8101. + rsp.pointer = (u8 *)ret; \
  8102. + \
  8103. + status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, 0); \
  8104. + if (status) \
  8105. + return status; \
  8106. + \
  8107. + if (rsp.length != sizeof(rtype)) { \
  8108. + struct device *dev = ssam_controller_device(ctrl); \
  8109. + dev_err(dev, \
  8110. + "rqst: invalid response length, expected %zu, got %zu (tc: %#04x, cid: %#04x)", \
  8111. + sizeof(rtype), rsp.length, rqst.target_category,\
  8112. + rqst.command_id); \
  8113. + return -EIO; \
  8114. + } \
  8115. + \
  8116. + return 0; \
  8117. + }
  8118. +
  8119. +/**
  8120. + * SSAM_DEFINE_SYNC_REQUEST_MD_N() - Define synchronous multi-device SAM
  8121. + * request function with neither argument nor return value.
  8122. + * @name: Name of the generated function.
  8123. + * @spec: Specification (&struct ssam_request_spec_md) defining the request.
  8124. + *
  8125. + * Defines a function executing the synchronous SAM request specified by
  8126. + * @spec, with the request having neither argument nor return value. Device
  8127. + * specifying parameters are not hard-coded, but instead must be provided to
  8128. + * the function. The generated function takes care of setting up the request
  8129. + * struct, buffer allocation, as well as execution of the request itself,
  8130. + * returning once the request has been fully completed. The required transport
  8131. + * buffer will be allocated on the stack.
  8132. + *
  8133. + * The generated function is defined as ``int name(struct ssam_controller
  8134. + * *ctrl, u8 tid, u8 iid)``, returning the status of the request, which is
  8135. + * zero on success and negative on failure. The ``ctrl`` parameter is the
  8136. + * controller via which the request is sent, ``tid`` the target ID for the
  8137. + * request, and ``iid`` the instance ID.
  8138. + *
  8139. + * Refer to ssam_request_sync_onstack() for more details on the behavior of
  8140. + * the generated function.
  8141. + */
  8142. +#define SSAM_DEFINE_SYNC_REQUEST_MD_N(name, spec...) \
  8143. + int name(struct ssam_controller *ctrl, u8 tid, u8 iid) \
  8144. + { \
  8145. + struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \
  8146. + struct ssam_request rqst; \
  8147. + \
  8148. + rqst.target_category = s.target_category; \
  8149. + rqst.target_id = tid; \
  8150. + rqst.command_id = s.command_id; \
  8151. + rqst.instance_id = iid; \
  8152. + rqst.flags = s.flags; \
  8153. + rqst.length = 0; \
  8154. + rqst.payload = NULL; \
  8155. + \
  8156. + return ssam_request_sync_onstack(ctrl, &rqst, NULL, 0); \
  8157. + }
  8158. +
  8159. +/**
  8160. + * SSAM_DEFINE_SYNC_REQUEST_MD_W() - Define synchronous multi-device SAM
  8161. + * request function with argument.
  8162. + * @name: Name of the generated function.
  8163. + * @atype: Type of the request's argument.
  8164. + * @spec: Specification (&struct ssam_request_spec_md) defining the request.
  8165. + *
  8166. + * Defines a function executing the synchronous SAM request specified by
  8167. + * @spec, with the request taking an argument of type @atype and having no
  8168. + * return value. Device specifying parameters are not hard-coded, but instead
  8169. + * must be provided to the function. The generated function takes care of
  8170. + * setting up the request struct, buffer allocation, as well as execution of
  8171. + * the request itself, returning once the request has been fully completed.
  8172. + * The required transport buffer will be allocated on the stack.
  8173. + *
  8174. + * The generated function is defined as ``int name(struct ssam_controller
  8175. + * *ctrl, u8 tid, u8 iid, const atype *arg)``, returning the status of the
  8176. + * request, which is zero on success and negative on failure. The ``ctrl``
  8177. + * parameter is the controller via which the request is sent, ``tid`` the
  8178. + * target ID for the request, and ``iid`` the instance ID. The request argument
  8179. + * is specified via the ``arg`` pointer.
  8180. + *
  8181. + * Refer to ssam_request_sync_onstack() for more details on the behavior of
  8182. + * the generated function.
  8183. + */
  8184. +#define SSAM_DEFINE_SYNC_REQUEST_MD_W(name, atype, spec...) \
  8185. + int name(struct ssam_controller *ctrl, u8 tid, u8 iid, const atype *arg)\
  8186. + { \
  8187. + struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \
  8188. + struct ssam_request rqst; \
  8189. + \
  8190. + rqst.target_category = s.target_category; \
  8191. + rqst.target_id = tid; \
  8192. + rqst.command_id = s.command_id; \
  8193. + rqst.instance_id = iid; \
  8194. + rqst.flags = s.flags; \
  8195. + rqst.length = sizeof(atype); \
  8196. + rqst.payload = (u8 *)arg; \
  8197. + \
  8198. + return ssam_request_sync_onstack(ctrl, &rqst, NULL, \
  8199. + sizeof(atype)); \
  8200. + }
  8201. +
  8202. +/**
  8203. + * SSAM_DEFINE_SYNC_REQUEST_MD_R() - Define synchronous multi-device SAM
  8204. + * request function with return value.
  8205. + * @name: Name of the generated function.
  8206. + * @rtype: Type of the request's return value.
  8207. + * @spec: Specification (&struct ssam_request_spec_md) defining the request.
  8208. + *
  8209. + * Defines a function executing the synchronous SAM request specified by
  8210. + * @spec, with the request taking no argument but having a return value of
  8211. + * type @rtype. Device specifying parameters are not hard-coded, but instead
  8212. + * must be provided to the function. The generated function takes care of
  8213. + * setting up the request and response structs, buffer allocation, as well as
  8214. + * execution of the request itself, returning once the request has been fully
  8215. + * completed. The required transport buffer will be allocated on the stack.
  8216. + *
  8217. + * The generated function is defined as ``int name(struct ssam_controller
  8218. + * *ctrl, u8 tid, u8 iid, rtype *ret)``, returning the status of the request,
  8219. + * which is zero on success and negative on failure. The ``ctrl`` parameter is
  8220. + * the controller via which the request is sent, ``tid`` the target ID for the
  8221. + * request, and ``iid`` the instance ID. The request's return value is written
  8222. + * to the memory pointed to by the ``ret`` parameter.
  8223. + *
  8224. + * Refer to ssam_request_sync_onstack() for more details on the behavior of
  8225. + * the generated function.
  8226. + */
  8227. +#define SSAM_DEFINE_SYNC_REQUEST_MD_R(name, rtype, spec...) \
  8228. + int name(struct ssam_controller *ctrl, u8 tid, u8 iid, rtype *ret) \
  8229. + { \
  8230. + struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \
  8231. + struct ssam_request rqst; \
  8232. + struct ssam_response rsp; \
  8233. + int status; \
  8234. + \
  8235. + rqst.target_category = s.target_category; \
  8236. + rqst.target_id = tid; \
  8237. + rqst.command_id = s.command_id; \
  8238. + rqst.instance_id = iid; \
  8239. + rqst.flags = s.flags | SSAM_REQUEST_HAS_RESPONSE; \
  8240. + rqst.length = 0; \
  8241. + rqst.payload = NULL; \
  8242. + \
  8243. + rsp.capacity = sizeof(rtype); \
  8244. + rsp.length = 0; \
  8245. + rsp.pointer = (u8 *)ret; \
  8246. + \
  8247. + status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, 0); \
  8248. + if (status) \
  8249. + return status; \
  8250. + \
  8251. + if (rsp.length != sizeof(rtype)) { \
  8252. + struct device *dev = ssam_controller_device(ctrl); \
  8253. + dev_err(dev, \
  8254. + "rqst: invalid response length, expected %zu, got %zu (tc: %#04x, cid: %#04x)", \
  8255. + sizeof(rtype), rsp.length, rqst.target_category,\
  8256. + rqst.command_id); \
  8257. + return -EIO; \
  8258. + } \
  8259. + \
  8260. + return 0; \
  8261. + }
  8262. +
  8263. +
  8264. +/* -- Event notifier/callbacks. --------------------------------------------- */
  8265. +
  8266. +#define SSAM_NOTIF_STATE_SHIFT 2
  8267. +#define SSAM_NOTIF_STATE_MASK ((1 << SSAM_NOTIF_STATE_SHIFT) - 1)
  8268. +
  8269. +/**
  8270. + * enum ssam_notif_flags - Flags used in return values from SSAM notifier
  8271. + * callback functions.
  8272. + *
  8273. + * @SSAM_NOTIF_HANDLED:
  8274. + * Indicates that the notification has been handled. This flag should be
  8275. + * set by the handler if the handler can act/has acted upon the event
  8276. + * provided to it. This flag should not be set if the handler is not a
  8277. + * primary handler intended for the provided event.
  8278. + *
  8279. + * If this flag has not been set by any handler after the notifier chain
  8280. + * has been traversed, a warning will be emitted, stating that the event
  8281. + * has not been handled.
  8282. + *
  8283. + * @SSAM_NOTIF_STOP:
  8284. + * Indicates that the notifier traversal should stop. If this flag is
  8285. + * returned from a notifier callback, notifier chain traversal will
  8286. + * immediately stop and any remaining notifiers will not be called. This
  8287. + * flag is automatically set when ssam_notifier_from_errno() is called
  8288. + * with a negative error value.
  8289. + */
  8290. +enum ssam_notif_flags {
  8291. + SSAM_NOTIF_HANDLED = BIT(0),
  8292. + SSAM_NOTIF_STOP = BIT(1),
  8293. +};
  8294. +
  8295. +struct ssam_event_notifier;
  8296. +
  8297. +typedef u32 (*ssam_notifier_fn_t)(struct ssam_event_notifier *nf,
  8298. + const struct ssam_event *event);
  8299. +
  8300. +/**
  8301. + * struct ssam_notifier_block - Base notifier block for SSAM event
  8302. + * notifications.
  8303. + * @node: The node for the list of notifiers.
  8304. + * @fn: The callback function of this notifier. This function takes the
  8305. + * respective notifier block and event as input and should return
  8306. + * a notifier value, which can either be obtained from the flags
  8307. + * provided in &enum ssam_notif_flags, converted from a standard
  8308. + * error value via ssam_notifier_from_errno(), or a combination of
  8309. + * both (e.g. ``ssam_notifier_from_errno(e) | SSAM_NOTIF_HANDLED``).
  8310. + * @priority: Priority value determining the order in which notifier callbacks
  8311. + * will be called. A higher value means higher priority, i.e. the
  8312. + * associated callback will be executed earlier than other (lower
  8313. + * priority) callbacks.
  8314. + */
  8315. +struct ssam_notifier_block {
  8316. + struct list_head node;
  8317. + ssam_notifier_fn_t fn;
  8318. + int priority;
  8319. +};
  8320. +
  8321. +/**
  8322. + * ssam_notifier_from_errno() - Convert standard error value to notifier
  8323. + * return code.
  8324. + * @err: The error code to convert, must be negative (in case of failure) or
  8325. + * zero (in case of success).
  8326. + *
  8327. + * Return: Returns the notifier return value obtained by converting the
  8328. + * specified @err value. In case @err is negative, the %SSAM_NOTIF_STOP flag
  8329. + * will be set, causing notifier call chain traversal to abort.
  8330. + */
  8331. +static inline u32 ssam_notifier_from_errno(int err)
  8332. +{
  8333. + if (WARN_ON(err > 0) || err == 0)
  8334. + return 0;
  8335. + else
  8336. + return ((-err) << SSAM_NOTIF_STATE_SHIFT) | SSAM_NOTIF_STOP;
  8337. +}
  8338. +
  8339. +/**
  8340. + * ssam_notifier_to_errno() - Convert notifier return code to standard error
  8341. + * value.
  8342. + * @ret: The notifier return value to convert.
  8343. + *
  8344. + * Return: Returns the negative error value encoded in @ret or zero if @ret
  8345. + * indicates success.
  8346. + */
  8347. +static inline int ssam_notifier_to_errno(u32 ret)
  8348. +{
  8349. + return -(ret >> SSAM_NOTIF_STATE_SHIFT);
  8350. +}
  8351. +
  8352. +
  8353. +/* -- Event/notification registry. ------------------------------------------ */
  8354. +
  8355. +/**
  8356. + * struct ssam_event_registry - Registry specification used for enabling events.
  8357. + * @target_category: Target category for the event registry requests.
  8358. + * @target_id: Target ID for the event registry requests.
  8359. + * @cid_enable: Command ID for the event-enable request.
  8360. + * @cid_disable: Command ID for the event-disable request.
  8361. + *
  8362. + * This struct describes a SAM event registry via the minimal collection of
  8363. + * SAM IDs specifying the requests to use for enabling and disabling an event.
  8364. + * The individual event to be enabled/disabled itself is specified via &struct
  8365. + * ssam_event_id.
  8366. + */
  8367. +struct ssam_event_registry {
  8368. + u8 target_category;
  8369. + u8 target_id;
  8370. + u8 cid_enable;
  8371. + u8 cid_disable;
  8372. +};
  8373. +
  8374. +/**
  8375. + * struct ssam_event_id - Unique event ID used for enabling events.
  8376. + * @target_category: Target category of the event source.
  8377. + * @instance: Instance ID of the event source.
  8378. + *
  8379. + * This struct specifies the event to be enabled/disabled via an externally
  8380. + * provided registry. It does not specify the registry to be used itself, this
  8381. + * is done via &struct ssam_event_registry.
  8382. + */
  8383. +struct ssam_event_id {
  8384. + u8 target_category;
  8385. + u8 instance;
  8386. +};
  8387. +
  8388. +/**
  8389. + * enum ssam_event_mask - Flags specifying how events are matched to notifiers.
  8390. + *
  8391. + * @SSAM_EVENT_MASK_NONE:
  8392. + * Run the callback for any event with matching target category. Do not
  8393. + * do any additional filtering.
  8394. + *
  8395. + * @SSAM_EVENT_MASK_TARGET:
  8396. + * In addition to filtering by target category, only execute the notifier
  8397. + * callback for events with a target ID matching to the one of the
  8398. + * registry used for enabling/disabling the event.
  8399. + *
  8400. + * @SSAM_EVENT_MASK_INSTANCE:
  8401. + * In addition to filtering by target category, only execute the notifier
  8402. + * callback for events with an instance ID matching to the instance ID
  8403. + * used when enabling the event.
  8404. + *
  8405. + * @SSAM_EVENT_MASK_STRICT:
  8406. + * Do all the filtering above.
  8407. + */
  8408. +enum ssam_event_mask {
  8409. + SSAM_EVENT_MASK_TARGET = BIT(0),
  8410. + SSAM_EVENT_MASK_INSTANCE = BIT(1),
  8411. +
  8412. + SSAM_EVENT_MASK_NONE = 0,
  8413. + SSAM_EVENT_MASK_STRICT =
  8414. + SSAM_EVENT_MASK_TARGET
  8415. + | SSAM_EVENT_MASK_INSTANCE,
  8416. +};
  8417. +
  8418. +/**
  8419. + * SSAM_EVENT_REGISTRY() - Define a new event registry.
  8420. + * @tc: Target category for the event registry requests.
  8421. + * @tid: Target ID for the event registry requests.
  8422. + * @cid_en: Command ID for the event-enable request.
  8423. + * @cid_dis: Command ID for the event-disable request.
  8424. + *
  8425. + * Return: Returns the &struct ssam_event_registry specified by the given
  8426. + * parameters.
  8427. + */
  8428. +#define SSAM_EVENT_REGISTRY(tc, tid, cid_en, cid_dis) \
  8429. + ((struct ssam_event_registry) { \
  8430. + .target_category = (tc), \
  8431. + .target_id = (tid), \
  8432. + .cid_enable = (cid_en), \
  8433. + .cid_disable = (cid_dis), \
  8434. + })
  8435. +
  8436. +#define SSAM_EVENT_REGISTRY_SAM \
  8437. + SSAM_EVENT_REGISTRY(SSAM_SSH_TC_SAM, 0x01, 0x0b, 0x0c)
  8438. +
  8439. +#define SSAM_EVENT_REGISTRY_KIP \
  8440. + SSAM_EVENT_REGISTRY(SSAM_SSH_TC_KIP, 0x02, 0x27, 0x28)
  8441. +
  8442. +#define SSAM_EVENT_REGISTRY_REG \
  8443. + SSAM_EVENT_REGISTRY(SSAM_SSH_TC_REG, 0x02, 0x01, 0x02)
  8444. +
  8445. +/**
  8446. + * struct ssam_event_notifier - Notifier block for SSAM events.
  8447. + * @base: The base notifier block with callback function and priority.
  8448. + * @event: The event for which this block will receive notifications.
  8449. + * @event.reg: Registry via which the event will be enabled/disabled.
  8450. + * @event.id: ID specifying the event.
  8451. + * @event.mask: Flags determining how events are matched to the notifier.
  8452. + * @event.flags: Flags used for enabling the event.
  8453. + */
  8454. +struct ssam_event_notifier {
  8455. + struct ssam_notifier_block base;
  8456. +
  8457. + struct {
  8458. + struct ssam_event_registry reg;
  8459. + struct ssam_event_id id;
  8460. + enum ssam_event_mask mask;
  8461. + u8 flags;
  8462. + } event;
  8463. +};
  8464. +
  8465. +int ssam_notifier_register(struct ssam_controller *ctrl,
  8466. + struct ssam_event_notifier *n);
  8467. +
  8468. +int ssam_notifier_unregister(struct ssam_controller *ctrl,
  8469. + struct ssam_event_notifier *n);
  8470. +
  8471. +#endif /* _LINUX_SURFACE_AGGREGATOR_CONTROLLER_H */
  8472. diff --git a/include/linux/surface_aggregator/serial_hub.h b/include/linux/surface_aggregator/serial_hub.h
  8473. new file mode 100644
  8474. index 000000000000..64276fbfa1d5
  8475. --- /dev/null
  8476. +++ b/include/linux/surface_aggregator/serial_hub.h
  8477. @@ -0,0 +1,672 @@
  8478. +/* SPDX-License-Identifier: GPL-2.0+ */
  8479. +/*
  8480. + * Surface Serial Hub (SSH) protocol and communication interface.
  8481. + *
  8482. + * Lower-level communication layers and SSH protocol definitions for the
  8483. + * Surface System Aggregator Module (SSAM). Provides the interface for basic
  8484. + * packet- and request-based communication with the SSAM EC via SSH.
  8485. + *
  8486. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  8487. + */
  8488. +
  8489. +#ifndef _LINUX_SURFACE_AGGREGATOR_SERIAL_HUB_H
  8490. +#define _LINUX_SURFACE_AGGREGATOR_SERIAL_HUB_H
  8491. +
  8492. +#include <linux/crc-ccitt.h>
  8493. +#include <linux/kref.h>
  8494. +#include <linux/ktime.h>
  8495. +#include <linux/list.h>
  8496. +#include <linux/types.h>
  8497. +
  8498. +
  8499. +/* -- Data structures for SAM-over-SSH communication. ----------------------- */
  8500. +
  8501. +/**
  8502. + * enum ssh_frame_type - Frame types for SSH frames.
  8503. + *
  8504. + * @SSH_FRAME_TYPE_DATA_SEQ:
  8505. + * Indicates a data frame, followed by a payload with the length specified
  8506. + * in the ``struct ssh_frame.len`` field. This frame is sequenced, meaning
  8507. + * that an ACK is required.
  8508. + *
  8509. + * @SSH_FRAME_TYPE_DATA_NSQ:
  8510. + * Same as %SSH_FRAME_TYPE_DATA_SEQ, but unsequenced, meaning that the
  8511. + * message does not have to be ACKed.
  8512. + *
  8513. + * @SSH_FRAME_TYPE_ACK:
  8514. + * Indicates an ACK message.
  8515. + *
  8516. + * @SSH_FRAME_TYPE_NAK:
  8517. + * Indicates an error response for previously sent frame. In general, this
  8518. + * means that the frame and/or payload is malformed, e.g. a CRC is wrong.
  8519. + * For command-type payloads, this can also mean that the command is
  8520. + * invalid.
  8521. + */
  8522. +enum ssh_frame_type {
  8523. + SSH_FRAME_TYPE_DATA_SEQ = 0x80,
  8524. + SSH_FRAME_TYPE_DATA_NSQ = 0x00,
  8525. + SSH_FRAME_TYPE_ACK = 0x40,
  8526. + SSH_FRAME_TYPE_NAK = 0x04,
  8527. +};
  8528. +
  8529. +/**
  8530. + * struct ssh_frame - SSH communication frame.
  8531. + * @type: The type of the frame. See &enum ssh_frame_type.
  8532. + * @len: The length of the frame payload directly following the CRC for this
  8533. + * frame. Does not include the final CRC for that payload.
  8534. + * @seq: The sequence number for this message/exchange.
  8535. + */
  8536. +struct ssh_frame {
  8537. + u8 type;
  8538. + __le16 len;
  8539. + u8 seq;
  8540. +} __packed;
  8541. +
  8542. +static_assert(sizeof(struct ssh_frame) == 4);
  8543. +
  8544. +/*
  8545. + * SSH_FRAME_MAX_PAYLOAD_SIZE - Maximum SSH frame payload length in bytes.
  8546. + *
  8547. + * This is the physical maximum length of the protocol. Implementations may
  8548. + * set a more constrained limit.
  8549. + */
  8550. +#define SSH_FRAME_MAX_PAYLOAD_SIZE U16_MAX
  8551. +
  8552. +/**
  8553. + * enum ssh_payload_type - Type indicator for the SSH payload.
  8554. + * @SSH_PLD_TYPE_CMD: The payload is a command structure with optional command
  8555. + * payload.
  8556. + */
  8557. +enum ssh_payload_type {
  8558. + SSH_PLD_TYPE_CMD = 0x80,
  8559. +};
  8560. +
  8561. +/**
  8562. + * struct ssh_command - Payload of a command-type frame.
  8563. + * @type: The type of the payload. See &enum ssh_payload_type. Should be
  8564. + * SSH_PLD_TYPE_CMD for this struct.
  8565. + * @tc: Command target category.
  8566. + * @tid_out: Output target ID. Should be zero if this an incoming (EC to host)
  8567. + * message.
  8568. + * @tid_in: Input target ID. Should be zero if this is an outgoing (host to
  8569. + * EC) message.
  8570. + * @iid: Instance ID.
  8571. + * @rqid: Request ID. Used to match requests with responses and differentiate
  8572. + * between responses and events.
  8573. + * @cid: Command ID.
  8574. + */
  8575. +struct ssh_command {
  8576. + u8 type;
  8577. + u8 tc;
  8578. + u8 tid_out;
  8579. + u8 tid_in;
  8580. + u8 iid;
  8581. + __le16 rqid;
  8582. + u8 cid;
  8583. +} __packed;
  8584. +
  8585. +static_assert(sizeof(struct ssh_command) == 8);
  8586. +
  8587. +/*
  8588. + * SSH_COMMAND_MAX_PAYLOAD_SIZE - Maximum SSH command payload length in bytes.
  8589. + *
  8590. + * This is the physical maximum length of the protocol. Implementations may
  8591. + * set a more constrained limit.
  8592. + */
  8593. +#define SSH_COMMAND_MAX_PAYLOAD_SIZE \
  8594. + (SSH_FRAME_MAX_PAYLOAD_SIZE - sizeof(struct ssh_command))
  8595. +
  8596. +/*
  8597. + * SSH_MSG_LEN_BASE - Base-length of a SSH message.
  8598. + *
  8599. + * This is the minimum number of bytes required to form a message. The actual
  8600. + * message length is SSH_MSG_LEN_BASE plus the length of the frame payload.
  8601. + */
  8602. +#define SSH_MSG_LEN_BASE (sizeof(struct ssh_frame) + 3ull * sizeof(u16))
  8603. +
  8604. +/*
  8605. + * SSH_MSG_LEN_CTRL - Length of a SSH control message.
  8606. + *
  8607. + * This is the length of a SSH control message, which is equal to a SSH
  8608. + * message without any payload.
  8609. + */
  8610. +#define SSH_MSG_LEN_CTRL SSH_MSG_LEN_BASE
  8611. +
  8612. +/**
  8613. + * SSH_MESSAGE_LENGTH() - Compute length of SSH message.
  8614. + * @payload_size: Length of the payload inside the SSH frame.
  8615. + *
  8616. + * Return: Returns the length of a SSH message with payload of specified size.
  8617. + */
  8618. +#define SSH_MESSAGE_LENGTH(payload_size) (SSH_MSG_LEN_BASE + (payload_size))
  8619. +
  8620. +/**
  8621. + * SSH_COMMAND_MESSAGE_LENGTH() - Compute length of SSH command message.
  8622. + * @payload_size: Length of the command payload.
  8623. + *
  8624. + * Return: Returns the length of a SSH command message with command payload of
  8625. + * specified size.
  8626. + */
  8627. +#define SSH_COMMAND_MESSAGE_LENGTH(payload_size) \
  8628. + SSH_MESSAGE_LENGTH(sizeof(struct ssh_command) + (payload_size))
  8629. +
  8630. +/**
  8631. + * SSH_MSGOFFSET_FRAME() - Compute offset in SSH message to specified field in
  8632. + * frame.
  8633. + * @field: The field for which the offset should be computed.
  8634. + *
  8635. + * Return: Returns the offset of the specified &struct ssh_frame field in the
  8636. + * raw SSH message data as. Takes SYN bytes (u16) preceding the frame into
  8637. + * account.
  8638. + */
  8639. +#define SSH_MSGOFFSET_FRAME(field) \
  8640. + (sizeof(u16) + offsetof(struct ssh_frame, field))
  8641. +
  8642. +/**
  8643. + * SSH_MSGOFFSET_COMMAND() - Compute offset in SSH message to specified field
  8644. + * in command.
  8645. + * @field: The field for which the offset should be computed.
  8646. + *
  8647. + * Return: Returns the offset of the specified &struct ssh_command field in
  8648. + * the raw SSH message data. Takes SYN bytes (u16) preceding the frame and the
  8649. + * frame CRC (u16) between frame and command into account.
  8650. + */
  8651. +#define SSH_MSGOFFSET_COMMAND(field) \
  8652. + (2ull * sizeof(u16) + sizeof(struct ssh_frame) \
  8653. + + offsetof(struct ssh_command, field))
  8654. +
  8655. +/*
  8656. + * SSH_MSG_SYN - SSH message synchronization (SYN) bytes as u16.
  8657. + */
  8658. +#define SSH_MSG_SYN ((u16)0x55aa)
  8659. +
  8660. +/**
  8661. + * ssh_crc() - Compute CRC for SSH messages.
  8662. + * @buf: The pointer pointing to the data for which the CRC should be computed.
  8663. + * @len: The length of the data for which the CRC should be computed.
  8664. + *
  8665. + * Return: Returns the CRC computed on the provided data, as used for SSH
  8666. + * messages.
  8667. + */
  8668. +static inline u16 ssh_crc(const u8 *buf, size_t len)
  8669. +{
  8670. + return crc_ccitt_false(0xffff, buf, len);
  8671. +}
  8672. +
  8673. +/*
  8674. + * SSH_NUM_EVENTS - The number of reserved event IDs.
  8675. + *
  8676. + * The number of reserved event IDs, used for registering an SSH event
  8677. + * handler. Valid event IDs are numbers below or equal to this value, with
  8678. + * exception of zero, which is not an event ID. Thus, this is also the
  8679. + * absolute maximum number of event handlers that can be registered.
  8680. + */
  8681. +#define SSH_NUM_EVENTS 34
  8682. +
  8683. +/*
  8684. + * SSH_NUM_TARGETS - The number of communication targets used in the protocol.
  8685. + */
  8686. +#define SSH_NUM_TARGETS 2
  8687. +
  8688. +/**
  8689. + * ssh_rqid_next_valid() - Return the next valid request ID.
  8690. + * @rqid: The current request ID.
  8691. + *
  8692. + * Return: Returns the next valid request ID, following the current request ID
  8693. + * provided to this function. This function skips any request IDs reserved for
  8694. + * events.
  8695. + */
  8696. +static inline u16 ssh_rqid_next_valid(u16 rqid)
  8697. +{
  8698. + return rqid > 0 ? rqid + 1u : rqid + SSH_NUM_EVENTS + 1u;
  8699. +}
  8700. +
  8701. +/**
  8702. + * ssh_rqid_to_event() - Convert request ID to its corresponding event ID.
  8703. + * @rqid: The request ID to convert.
  8704. + */
  8705. +static inline u16 ssh_rqid_to_event(u16 rqid)
  8706. +{
  8707. + return rqid - 1u;
  8708. +}
  8709. +
  8710. +/**
  8711. + * ssh_rqid_is_event() - Check if given request ID is a valid event ID.
  8712. + * @rqid: The request ID to check.
  8713. + */
  8714. +static inline bool ssh_rqid_is_event(u16 rqid)
  8715. +{
  8716. + return ssh_rqid_to_event(rqid) < SSH_NUM_EVENTS;
  8717. +}
  8718. +
  8719. +/**
  8720. + * ssh_tc_to_rqid() - Convert target category to its corresponding request ID.
  8721. + * @tc: The target category to convert.
  8722. + */
  8723. +static inline u16 ssh_tc_to_rqid(u8 tc)
  8724. +{
  8725. + return tc;
  8726. +}
  8727. +
  8728. +/**
  8729. + * ssh_tid_to_index() - Convert target ID to its corresponding target index.
  8730. + * @tid: The target ID to convert.
  8731. + */
  8732. +static inline u8 ssh_tid_to_index(u8 tid)
  8733. +{
  8734. + return tid - 1u;
  8735. +}
  8736. +
  8737. +/**
  8738. + * ssh_tid_is_valid() - Check if target ID is valid/supported.
  8739. + * @tid: The target ID to check.
  8740. + */
  8741. +static inline bool ssh_tid_is_valid(u8 tid)
  8742. +{
  8743. + return ssh_tid_to_index(tid) < SSH_NUM_TARGETS;
  8744. +}
  8745. +
  8746. +/**
  8747. + * struct ssam_span - Reference to a buffer region.
  8748. + * @ptr: Pointer to the buffer region.
  8749. + * @len: Length of the buffer region.
  8750. + *
  8751. + * A reference to a (non-owned) buffer segment, consisting of pointer and
  8752. + * length. Use of this struct indicates non-owned data, i.e. data of which the
  8753. + * life-time is managed (i.e. it is allocated/freed) via another pointer.
  8754. + */
  8755. +struct ssam_span {
  8756. + u8 *ptr;
  8757. + size_t len;
  8758. +};
  8759. +
  8760. +/*
  8761. + * Known SSH/EC target categories.
  8762. + *
  8763. + * List of currently known target category values; "Known" as in we know they
  8764. + * exist and are valid on at least some device/model. Detailed functionality
  8765. + * or the full category name is only known for some of these categories and
  8766. + * is detailed in the respective comment below.
  8767. + *
  8768. + * These values and abbreviations have been extracted from strings inside the
  8769. + * Windows driver.
  8770. + */
  8771. +enum ssam_ssh_tc {
  8772. + /* Category 0x00 is invalid for EC use. */
  8773. + SSAM_SSH_TC_SAM = 0x01, /* Generic system functionality, real-time clock. */
  8774. + SSAM_SSH_TC_BAT = 0x02, /* Battery/power subsystem. */
  8775. + SSAM_SSH_TC_TMP = 0x03, /* Thermal subsystem. */
  8776. + SSAM_SSH_TC_PMC = 0x04,
  8777. + SSAM_SSH_TC_FAN = 0x05,
  8778. + SSAM_SSH_TC_PoM = 0x06,
  8779. + SSAM_SSH_TC_DBG = 0x07,
  8780. + SSAM_SSH_TC_KBD = 0x08, /* Legacy keyboard (Laptop 1/2). */
  8781. + SSAM_SSH_TC_FWU = 0x09,
  8782. + SSAM_SSH_TC_UNI = 0x0a,
  8783. + SSAM_SSH_TC_LPC = 0x0b,
  8784. + SSAM_SSH_TC_TCL = 0x0c,
  8785. + SSAM_SSH_TC_SFL = 0x0d,
  8786. + SSAM_SSH_TC_KIP = 0x0e,
  8787. + SSAM_SSH_TC_EXT = 0x0f,
  8788. + SSAM_SSH_TC_BLD = 0x10,
  8789. + SSAM_SSH_TC_BAS = 0x11, /* Detachment system (Surface Book 2/3). */
  8790. + SSAM_SSH_TC_SEN = 0x12,
  8791. + SSAM_SSH_TC_SRQ = 0x13,
  8792. + SSAM_SSH_TC_MCU = 0x14,
  8793. + SSAM_SSH_TC_HID = 0x15, /* Generic HID input subsystem. */
  8794. + SSAM_SSH_TC_TCH = 0x16,
  8795. + SSAM_SSH_TC_BKL = 0x17,
  8796. + SSAM_SSH_TC_TAM = 0x18,
  8797. + SSAM_SSH_TC_ACC = 0x19,
  8798. + SSAM_SSH_TC_UFI = 0x1a,
  8799. + SSAM_SSH_TC_USC = 0x1b,
  8800. + SSAM_SSH_TC_PEN = 0x1c,
  8801. + SSAM_SSH_TC_VID = 0x1d,
  8802. + SSAM_SSH_TC_AUD = 0x1e,
  8803. + SSAM_SSH_TC_SMC = 0x1f,
  8804. + SSAM_SSH_TC_KPD = 0x20,
  8805. + SSAM_SSH_TC_REG = 0x21, /* Extended event registry. */
  8806. +};
  8807. +
  8808. +
  8809. +/* -- Packet transport layer (ptl). ----------------------------------------- */
  8810. +
  8811. +/**
  8812. + * enum ssh_packet_base_priority - Base priorities for &struct ssh_packet.
  8813. + * @SSH_PACKET_PRIORITY_FLUSH: Base priority for flush packets.
  8814. + * @SSH_PACKET_PRIORITY_DATA: Base priority for normal data packets.
  8815. + * @SSH_PACKET_PRIORITY_NAK: Base priority for NAK packets.
  8816. + * @SSH_PACKET_PRIORITY_ACK: Base priority for ACK packets.
  8817. + */
  8818. +enum ssh_packet_base_priority {
  8819. + SSH_PACKET_PRIORITY_FLUSH = 0, /* same as DATA to sequence flush */
  8820. + SSH_PACKET_PRIORITY_DATA = 0,
  8821. + SSH_PACKET_PRIORITY_NAK = 1,
  8822. + SSH_PACKET_PRIORITY_ACK = 2,
  8823. +};
  8824. +
  8825. +/*
  8826. + * Same as SSH_PACKET_PRIORITY() below, only with actual values.
  8827. + */
  8828. +#define __SSH_PACKET_PRIORITY(base, try) \
  8829. + (((base) << 4) | ((try) & 0x0f))
  8830. +
  8831. +/**
  8832. + * SSH_PACKET_PRIORITY() - Compute packet priority from base priority and
  8833. + * number of tries.
  8834. + * @base: The base priority as suffix of &enum ssh_packet_base_priority, e.g.
  8835. + * ``FLUSH``, ``DATA``, ``ACK``, or ``NAK``.
  8836. + * @try: The number of tries (must be less than 16).
  8837. + *
  8838. + * Compute the combined packet priority. The combined priority is dominated by
  8839. + * the base priority, whereas the number of (re-)tries decides the precedence
  8840. + * of packets with the same base priority, giving higher priority to packets
  8841. + * that already have more tries.
  8842. + *
  8843. + * Return: Returns the computed priority as value fitting inside a &u8. A
  8844. + * higher number means a higher priority.
  8845. + */
  8846. +#define SSH_PACKET_PRIORITY(base, try) \
  8847. + __SSH_PACKET_PRIORITY(SSH_PACKET_PRIORITY_##base, (try))
  8848. +
  8849. +/**
  8850. + * ssh_packet_priority_get_try() - Get number of tries from packet priority.
  8851. + * @priority: The packet priority.
  8852. + *
  8853. + * Return: Returns the number of tries encoded in the specified packet
  8854. + * priority.
  8855. + */
  8856. +static inline u8 ssh_packet_priority_get_try(u8 priority)
  8857. +{
  8858. + return priority & 0x0f;
  8859. +}
  8860. +
  8861. +/**
  8862. + * ssh_packet_priority_get_base - Get base priority from packet priority.
  8863. + * @priority: The packet priority.
  8864. + *
  8865. + * Return: Returns the base priority encoded in the given packet priority.
  8866. + */
  8867. +static inline u8 ssh_packet_priority_get_base(u8 priority)
  8868. +{
  8869. + return (priority & 0xf0) >> 4;
  8870. +}
  8871. +
  8872. +enum ssh_packet_flags {
  8873. + /* state flags */
  8874. + SSH_PACKET_SF_LOCKED_BIT,
  8875. + SSH_PACKET_SF_QUEUED_BIT,
  8876. + SSH_PACKET_SF_PENDING_BIT,
  8877. + SSH_PACKET_SF_TRANSMITTING_BIT,
  8878. + SSH_PACKET_SF_TRANSMITTED_BIT,
  8879. + SSH_PACKET_SF_ACKED_BIT,
  8880. + SSH_PACKET_SF_CANCELED_BIT,
  8881. + SSH_PACKET_SF_COMPLETED_BIT,
  8882. +
  8883. + /* type flags */
  8884. + SSH_PACKET_TY_FLUSH_BIT,
  8885. + SSH_PACKET_TY_SEQUENCED_BIT,
  8886. + SSH_PACKET_TY_BLOCKING_BIT,
  8887. +
  8888. + /* mask for state flags */
  8889. + SSH_PACKET_FLAGS_SF_MASK =
  8890. + BIT(SSH_PACKET_SF_LOCKED_BIT)
  8891. + | BIT(SSH_PACKET_SF_QUEUED_BIT)
  8892. + | BIT(SSH_PACKET_SF_PENDING_BIT)
  8893. + | BIT(SSH_PACKET_SF_TRANSMITTING_BIT)
  8894. + | BIT(SSH_PACKET_SF_TRANSMITTED_BIT)
  8895. + | BIT(SSH_PACKET_SF_ACKED_BIT)
  8896. + | BIT(SSH_PACKET_SF_CANCELED_BIT)
  8897. + | BIT(SSH_PACKET_SF_COMPLETED_BIT),
  8898. +
  8899. + /* mask for type flags */
  8900. + SSH_PACKET_FLAGS_TY_MASK =
  8901. + BIT(SSH_PACKET_TY_FLUSH_BIT)
  8902. + | BIT(SSH_PACKET_TY_SEQUENCED_BIT)
  8903. + | BIT(SSH_PACKET_TY_BLOCKING_BIT),
  8904. +};
  8905. +
  8906. +struct ssh_ptl;
  8907. +struct ssh_packet;
  8908. +
  8909. +/**
  8910. + * struct ssh_packet_ops - Callback operations for a SSH packet.
  8911. + * @release: Function called when the packet reference count reaches zero.
  8912. + * This callback must be relied upon to ensure that the packet has
  8913. + * left the transport system(s).
  8914. + * @complete: Function called when the packet is completed, either with
  8915. + * success or failure. In case of failure, the reason for the
  8916. + * failure is indicated by the value of the provided status code
  8917. + * argument. This value will be zero in case of success. Note that
  8918. + * a call to this callback does not guarantee that the packet is
  8919. + * not in use by the transport system any more.
  8920. + */
  8921. +struct ssh_packet_ops {
  8922. + void (*release)(struct ssh_packet *p);
  8923. + void (*complete)(struct ssh_packet *p, int status);
  8924. +};
  8925. +
  8926. +/**
  8927. + * struct ssh_packet - SSH transport packet.
  8928. + * @ptl: Pointer to the packet transport layer. May be %NULL if the packet
  8929. + * (or enclosing request) has not been submitted yet.
  8930. + * @refcnt: Reference count of the packet.
  8931. + * @priority: Priority of the packet. Must be computed via
  8932. + * SSH_PACKET_PRIORITY(). Must only be accessed while holding the
  8933. + * queue lock after first submission.
  8934. + * @data: Raw message data.
  8935. + * @data.len: Length of the raw message data.
  8936. + * @data.ptr: Pointer to the raw message data buffer.
  8937. + * @state: State and type flags describing current packet state (dynamic)
  8938. + * and type (static). See &enum ssh_packet_flags for possible
  8939. + * options.
  8940. + * @timestamp: Timestamp specifying when the latest transmission of a
  8941. + * currently pending packet has been started. May be %KTIME_MAX
  8942. + * before or in-between transmission attempts. Used for the packet
  8943. + * timeout implementation. Must only be accessed while holding the
  8944. + * pending lock after first submission.
  8945. + * @queue_node: The list node for the packet queue.
  8946. + * @pending_node: The list node for the set of pending packets.
  8947. + * @ops: Packet operations.
  8948. + */
  8949. +struct ssh_packet {
  8950. + struct ssh_ptl *ptl;
  8951. + struct kref refcnt;
  8952. +
  8953. + u8 priority;
  8954. +
  8955. + struct {
  8956. + size_t len;
  8957. + u8 *ptr;
  8958. + } data;
  8959. +
  8960. + unsigned long state;
  8961. + ktime_t timestamp;
  8962. +
  8963. + struct list_head queue_node;
  8964. + struct list_head pending_node;
  8965. +
  8966. + const struct ssh_packet_ops *ops;
  8967. +};
  8968. +
  8969. +struct ssh_packet *ssh_packet_get(struct ssh_packet *p);
  8970. +void ssh_packet_put(struct ssh_packet *p);
  8971. +
  8972. +/**
  8973. + * ssh_packet_set_data() - Set raw message data of packet.
  8974. + * @p: The packet for which the message data should be set.
  8975. + * @ptr: Pointer to the memory holding the message data.
  8976. + * @len: Length of the message data.
  8977. + *
  8978. + * Sets the raw message data buffer of the packet to the provided memory. The
  8979. + * memory is not copied. Instead, the caller is responsible for management
  8980. + * (i.e. allocation and deallocation) of the memory. The caller must ensure
  8981. + * that the provided memory is valid and contains a valid SSH message,
  8982. + * starting from the time of submission of the packet until the ``release``
  8983. + * callback has been called. During this time, the memory may not be altered
  8984. + * in any way.
  8985. + */
  8986. +static inline void ssh_packet_set_data(struct ssh_packet *p, u8 *ptr, size_t len)
  8987. +{
  8988. + p->data.ptr = ptr;
  8989. + p->data.len = len;
  8990. +}
  8991. +
  8992. +
  8993. +/* -- Request transport layer (rtl). ---------------------------------------- */
  8994. +
  8995. +enum ssh_request_flags {
  8996. + /* state flags */
  8997. + SSH_REQUEST_SF_LOCKED_BIT,
  8998. + SSH_REQUEST_SF_QUEUED_BIT,
  8999. + SSH_REQUEST_SF_PENDING_BIT,
  9000. + SSH_REQUEST_SF_TRANSMITTING_BIT,
  9001. + SSH_REQUEST_SF_TRANSMITTED_BIT,
  9002. + SSH_REQUEST_SF_RSPRCVD_BIT,
  9003. + SSH_REQUEST_SF_CANCELED_BIT,
  9004. + SSH_REQUEST_SF_COMPLETED_BIT,
  9005. +
  9006. + /* type flags */
  9007. + SSH_REQUEST_TY_FLUSH_BIT,
  9008. + SSH_REQUEST_TY_HAS_RESPONSE_BIT,
  9009. +
  9010. + /* mask for state flags */
  9011. + SSH_REQUEST_FLAGS_SF_MASK =
  9012. + BIT(SSH_REQUEST_SF_LOCKED_BIT)
  9013. + | BIT(SSH_REQUEST_SF_QUEUED_BIT)
  9014. + | BIT(SSH_REQUEST_SF_PENDING_BIT)
  9015. + | BIT(SSH_REQUEST_SF_TRANSMITTING_BIT)
  9016. + | BIT(SSH_REQUEST_SF_TRANSMITTED_BIT)
  9017. + | BIT(SSH_REQUEST_SF_RSPRCVD_BIT)
  9018. + | BIT(SSH_REQUEST_SF_CANCELED_BIT)
  9019. + | BIT(SSH_REQUEST_SF_COMPLETED_BIT),
  9020. +
  9021. + /* mask for type flags */
  9022. + SSH_REQUEST_FLAGS_TY_MASK =
  9023. + BIT(SSH_REQUEST_TY_FLUSH_BIT)
  9024. + | BIT(SSH_REQUEST_TY_HAS_RESPONSE_BIT),
  9025. +};
  9026. +
  9027. +struct ssh_rtl;
  9028. +struct ssh_request;
  9029. +
  9030. +/**
  9031. + * struct ssh_request_ops - Callback operations for a SSH request.
  9032. + * @release: Function called when the request's reference count reaches zero.
  9033. + * This callback must be relied upon to ensure that the request has
  9034. + * left the transport systems (both, packet an request systems).
  9035. + * @complete: Function called when the request is completed, either with
  9036. + * success or failure. The command data for the request response
  9037. + * is provided via the &struct ssh_command parameter (``cmd``),
  9038. + * the command payload of the request response via the &struct
  9039. + * ssh_span parameter (``data``).
  9040. + *
  9041. + * If the request does not have any response or has not been
  9042. + * completed with success, both ``cmd`` and ``data`` parameters will
  9043. + * be NULL. If the request response does not have any command
  9044. + * payload, the ``data`` span will be an empty (zero-length) span.
  9045. + *
  9046. + * In case of failure, the reason for the failure is indicated by
  9047. + * the value of the provided status code argument (``status``). This
  9048. + * value will be zero in case of success and a regular errno
  9049. + * otherwise.
  9050. + *
  9051. + * Note that a call to this callback does not guarantee that the
  9052. + * request is not in use by the transport systems any more.
  9053. + */
  9054. +struct ssh_request_ops {
  9055. + void (*release)(struct ssh_request *rqst);
  9056. + void (*complete)(struct ssh_request *rqst,
  9057. + const struct ssh_command *cmd,
  9058. + const struct ssam_span *data, int status);
  9059. +};
  9060. +
  9061. +/**
  9062. + * struct ssh_request - SSH transport request.
  9063. + * @packet: The underlying SSH transport packet.
  9064. + * @node: List node for the request queue and pending set.
  9065. + * @state: State and type flags describing current request state (dynamic)
  9066. + * and type (static). See &enum ssh_request_flags for possible
  9067. + * options.
  9068. + * @timestamp: Timestamp specifying when we start waiting on the response of
  9069. + * the request. This is set once the underlying packet has been
  9070. + * completed and may be %KTIME_MAX before that, or when the request
  9071. + * does not expect a response. Used for the request timeout
  9072. + * implementation.
  9073. + * @ops: Request Operations.
  9074. + */
  9075. +struct ssh_request {
  9076. + struct ssh_packet packet;
  9077. + struct list_head node;
  9078. +
  9079. + unsigned long state;
  9080. + ktime_t timestamp;
  9081. +
  9082. + const struct ssh_request_ops *ops;
  9083. +};
  9084. +
  9085. +/**
  9086. + * to_ssh_request() - Cast a SSH packet to its enclosing SSH request.
  9087. + * @p: The packet to cast.
  9088. + *
  9089. + * Casts the given &struct ssh_packet to its enclosing &struct ssh_request.
  9090. + * The caller is responsible for making sure that the packet is actually
  9091. + * wrapped in a &struct ssh_request.
  9092. + *
  9093. + * Return: Returns the &struct ssh_request wrapping the provided packet.
  9094. + */
  9095. +static inline struct ssh_request *to_ssh_request(struct ssh_packet *p)
  9096. +{
  9097. + return container_of(p, struct ssh_request, packet);
  9098. +}
  9099. +
  9100. +/**
  9101. + * ssh_request_get() - Increment reference count of request.
  9102. + * @r: The request to increment the reference count of.
  9103. + *
  9104. + * Increments the reference count of the given request by incrementing the
  9105. + * reference count of the underlying &struct ssh_packet, enclosed in it.
  9106. + *
  9107. + * See also ssh_request_put(), ssh_packet_get().
  9108. + *
  9109. + * Return: Returns the request provided as input.
  9110. + */
  9111. +static inline struct ssh_request *ssh_request_get(struct ssh_request *r)
  9112. +{
  9113. + return r ? to_ssh_request(ssh_packet_get(&r->packet)) : NULL;
  9114. +}
  9115. +
  9116. +/**
  9117. + * ssh_request_put() - Decrement reference count of request.
  9118. + * @r: The request to decrement the reference count of.
  9119. + *
  9120. + * Decrements the reference count of the given request by decrementing the
  9121. + * reference count of the underlying &struct ssh_packet, enclosed in it. If
  9122. + * the reference count reaches zero, the ``release`` callback specified in the
  9123. + * request's &struct ssh_request_ops, i.e. ``r->ops->release``, will be
  9124. + * called.
  9125. + *
  9126. + * See also ssh_request_get(), ssh_packet_put().
  9127. + */
  9128. +static inline void ssh_request_put(struct ssh_request *r)
  9129. +{
  9130. + if (r)
  9131. + ssh_packet_put(&r->packet);
  9132. +}
  9133. +
  9134. +/**
  9135. + * ssh_request_set_data() - Set raw message data of request.
  9136. + * @r: The request for which the message data should be set.
  9137. + * @ptr: Pointer to the memory holding the message data.
  9138. + * @len: Length of the message data.
  9139. + *
  9140. + * Sets the raw message data buffer of the underlying packet to the specified
  9141. + * buffer. Does not copy the actual message data, just sets the buffer pointer
  9142. + * and length. Refer to ssh_packet_set_data() for more details.
  9143. + */
  9144. +static inline void ssh_request_set_data(struct ssh_request *r, u8 *ptr, size_t len)
  9145. +{
  9146. + ssh_packet_set_data(&r->packet, ptr, len);
  9147. +}
  9148. +
  9149. +#endif /* _LINUX_SURFACE_AGGREGATOR_SERIAL_HUB_H */
  9150. --
  9151. 2.31.0
  9152. From 8371b5f32f7ec7a9fedb20d1a7c8e18429e13633 Mon Sep 17 00:00:00 2001
  9153. From: Maximilian Luz <luzmaximilian@gmail.com>
  9154. Date: Mon, 21 Dec 2020 19:39:52 +0100
  9155. Subject: [PATCH] platform/surface: aggregator: Add control packet allocation
  9156. caching
  9157. Surface Serial Hub communication is, in its core, packet based. Each
  9158. sequenced packet requires to be acknowledged, via an ACK-type control
  9159. packet. In case invalid data has been received by the driver, a NAK-type
  9160. (not-acknowledge/negative acknowledge) control packet is sent,
  9161. triggering retransmission.
  9162. Control packets are therefore a core communication primitive and used
  9163. frequently enough (with every sequenced packet transmission sent by the
  9164. embedded controller, including events and request responses) that it may
  9165. warrant caching their allocations to reduce possible memory
  9166. fragmentation.
  9167. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  9168. Reviewed-by: Hans de Goede <hdegoede@redhat.com>
  9169. Link: https://lore.kernel.org/r/20201221183959.1186143-3-luzmaximilian@gmail.com
  9170. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  9171. Patchset: surface-sam
  9172. ---
  9173. drivers/platform/surface/aggregator/core.c | 27 ++++++++++-
  9174. .../surface/aggregator/ssh_packet_layer.c | 47 +++++++++++++++----
  9175. .../surface/aggregator/ssh_packet_layer.h | 3 ++
  9176. 3 files changed, 67 insertions(+), 10 deletions(-)
  9177. diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
  9178. index 18e0e9e34e7b..60d312f71436 100644
  9179. --- a/drivers/platform/surface/aggregator/core.c
  9180. +++ b/drivers/platform/surface/aggregator/core.c
  9181. @@ -780,7 +780,32 @@ static struct serdev_device_driver ssam_serial_hub = {
  9182. .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  9183. },
  9184. };
  9185. -module_serdev_device_driver(ssam_serial_hub);
  9186. +
  9187. +
  9188. +/* -- Module setup. --------------------------------------------------------- */
  9189. +
  9190. +static int __init ssam_core_init(void)
  9191. +{
  9192. + int status;
  9193. +
  9194. + status = ssh_ctrl_packet_cache_init();
  9195. + if (status)
  9196. + return status;
  9197. +
  9198. + status = serdev_device_driver_register(&ssam_serial_hub);
  9199. + if (status)
  9200. + ssh_ctrl_packet_cache_destroy();
  9201. +
  9202. + return status;
  9203. +}
  9204. +module_init(ssam_core_init);
  9205. +
  9206. +static void __exit ssam_core_exit(void)
  9207. +{
  9208. + serdev_device_driver_unregister(&ssam_serial_hub);
  9209. + ssh_ctrl_packet_cache_destroy();
  9210. +}
  9211. +module_exit(ssam_core_exit);
  9212. MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  9213. MODULE_DESCRIPTION("Subsystem and Surface Serial Hub driver for Surface System Aggregator Module");
  9214. diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c
  9215. index 66e38fdc7963..23c2e31e7d0e 100644
  9216. --- a/drivers/platform/surface/aggregator/ssh_packet_layer.c
  9217. +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c
  9218. @@ -303,24 +303,53 @@ void ssh_packet_init(struct ssh_packet *packet, unsigned long type,
  9219. packet->ops = ops;
  9220. }
  9221. +static struct kmem_cache *ssh_ctrl_packet_cache;
  9222. +
  9223. +/**
  9224. + * ssh_ctrl_packet_cache_init() - Initialize the control packet cache.
  9225. + */
  9226. +int ssh_ctrl_packet_cache_init(void)
  9227. +{
  9228. + const unsigned int size = sizeof(struct ssh_packet) + SSH_MSG_LEN_CTRL;
  9229. + const unsigned int align = __alignof__(struct ssh_packet);
  9230. + struct kmem_cache *cache;
  9231. +
  9232. + cache = kmem_cache_create("ssam_ctrl_packet", size, align, 0, NULL);
  9233. + if (!cache)
  9234. + return -ENOMEM;
  9235. +
  9236. + ssh_ctrl_packet_cache = cache;
  9237. + return 0;
  9238. +}
  9239. +
  9240. +/**
  9241. + * ssh_ctrl_packet_cache_destroy() - Deinitialize the control packet cache.
  9242. + */
  9243. +void ssh_ctrl_packet_cache_destroy(void)
  9244. +{
  9245. + kmem_cache_destroy(ssh_ctrl_packet_cache);
  9246. + ssh_ctrl_packet_cache = NULL;
  9247. +}
  9248. +
  9249. /**
  9250. - * ssh_ctrl_packet_alloc() - Allocate control packet.
  9251. + * ssh_ctrl_packet_alloc() - Allocate packet from control packet cache.
  9252. * @packet: Where the pointer to the newly allocated packet should be stored.
  9253. * @buffer: The buffer corresponding to this packet.
  9254. * @flags: Flags used for allocation.
  9255. *
  9256. - * Allocates a packet and corresponding transport buffer. Sets the packet's
  9257. - * buffer reference to the allocated buffer. The packet must be freed via
  9258. - * ssh_ctrl_packet_free(), which will also free the corresponding buffer. The
  9259. - * corresponding buffer must not be freed separately. Intended to be used with
  9260. - * %ssh_ptl_ctrl_packet_ops as packet operations.
  9261. + * Allocates a packet and corresponding transport buffer from the control
  9262. + * packet cache. Sets the packet's buffer reference to the allocated buffer.
  9263. + * The packet must be freed via ssh_ctrl_packet_free(), which will also free
  9264. + * the corresponding buffer. The corresponding buffer must not be freed
  9265. + * separately. Intended to be used with %ssh_ptl_ctrl_packet_ops as packet
  9266. + * operations.
  9267. *
  9268. * Return: Returns zero on success, %-ENOMEM if the allocation failed.
  9269. */
  9270. static int ssh_ctrl_packet_alloc(struct ssh_packet **packet,
  9271. struct ssam_span *buffer, gfp_t flags)
  9272. {
  9273. - *packet = kzalloc(sizeof(**packet) + SSH_MSG_LEN_CTRL, flags);
  9274. + *packet = kmem_cache_alloc(ssh_ctrl_packet_cache, flags);
  9275. if (!*packet)
  9276. return -ENOMEM;
  9277. @@ -331,12 +360,12 @@ static int ssh_ctrl_packet_alloc(struct ssh_packet **packet,
  9278. }
  9279. /**
  9280. - * ssh_ctrl_packet_free() - Free control packet.
  9281. + * ssh_ctrl_packet_free() - Free packet allocated from control packet cache.
  9282. * @p: The packet to free.
  9283. */
  9284. static void ssh_ctrl_packet_free(struct ssh_packet *p)
  9285. {
  9286. - kfree(p);
  9287. + kmem_cache_free(ssh_ctrl_packet_cache, p);
  9288. }
  9289. static const struct ssh_packet_ops ssh_ptl_ctrl_packet_ops = {
  9290. diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.h b/drivers/platform/surface/aggregator/ssh_packet_layer.h
  9291. index 058f111292ca..e8757d03f279 100644
  9292. --- a/drivers/platform/surface/aggregator/ssh_packet_layer.h
  9293. +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.h
  9294. @@ -184,4 +184,7 @@ static inline void ssh_ptl_tx_wakeup_transfer(struct ssh_ptl *ptl)
  9295. void ssh_packet_init(struct ssh_packet *packet, unsigned long type,
  9296. u8 priority, const struct ssh_packet_ops *ops);
  9297. +int ssh_ctrl_packet_cache_init(void);
  9298. +void ssh_ctrl_packet_cache_destroy(void);
  9299. +
  9300. #endif /* _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H */
  9301. --
  9302. 2.31.0
  9303. From dda656831cf11f505423f8edd5dd527f0606377c Mon Sep 17 00:00:00 2001
  9304. From: Maximilian Luz <luzmaximilian@gmail.com>
  9305. Date: Mon, 21 Dec 2020 19:39:53 +0100
  9306. Subject: [PATCH] platform/surface: aggregator: Add event item allocation
  9307. caching
  9308. Event items are used for completing Surface Aggregator EC events, i.e.
  9309. placing event command data and payload on a workqueue for later
  9310. processing to avoid doing said processing directly on the receiver
  9311. thread. This means that event items are allocated for each incoming
  9312. event, regardless of that event being transmitted via sequenced or
  9313. unsequenced packets.
  9314. On the Surface Book 3 and Surface Laptop 3, touchpad HID input events
  9315. (unsequenced), can constitute a larger amount of traffic, and therefore
  9316. allocation of event items. This warrants caching event items to reduce
  9317. memory fragmentation. The size of the cached objects is specifically
  9318. tuned to accommodate keyboard and touchpad input events and their
  9319. payloads on those devices. As a result, this effectively also covers
  9320. most other event types. In case of a larger event payload, event item
  9321. allocation will fall back to kzalloc().
  9322. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  9323. Reviewed-by: Hans de Goede <hdegoede@redhat.com>
  9324. Link: https://lore.kernel.org/r/20201221183959.1186143-4-luzmaximilian@gmail.com
  9325. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  9326. Patchset: surface-sam
  9327. ---
  9328. .../platform/surface/aggregator/controller.c | 86 +++++++++++++++++--
  9329. .../platform/surface/aggregator/controller.h | 9 ++
  9330. drivers/platform/surface/aggregator/core.c | 16 +++-
  9331. 3 files changed, 101 insertions(+), 10 deletions(-)
  9332. diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
  9333. index 488318cf2098..775a4509bece 100644
  9334. --- a/drivers/platform/surface/aggregator/controller.c
  9335. +++ b/drivers/platform/surface/aggregator/controller.c
  9336. @@ -513,14 +513,74 @@ static void ssam_nf_destroy(struct ssam_nf *nf)
  9337. */
  9338. #define SSAM_CPLT_WQ_BATCH 10
  9339. +/*
  9340. + * SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN - Maximum payload length for a cached
  9341. + * &struct ssam_event_item.
  9342. + *
  9343. + * This length has been chosen to be accommodate standard touchpad and
  9344. + * keyboard input events. Events with larger payloads will be allocated
  9345. + * separately.
  9346. + */
  9347. +#define SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN 32
  9348. +
  9349. +static struct kmem_cache *ssam_event_item_cache;
  9350. +
  9351. +/**
  9352. + * ssam_event_item_cache_init() - Initialize the event item cache.
  9353. + */
  9354. +int ssam_event_item_cache_init(void)
  9355. +{
  9356. + const unsigned int size = sizeof(struct ssam_event_item)
  9357. + + SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN;
  9358. + const unsigned int align = __alignof__(struct ssam_event_item);
  9359. + struct kmem_cache *cache;
  9360. +
  9361. + cache = kmem_cache_create("ssam_event_item", size, align, 0, NULL);
  9362. + if (!cache)
  9363. + return -ENOMEM;
  9364. +
  9365. + ssam_event_item_cache = cache;
  9366. + return 0;
  9367. +}
  9368. +
  9369. +/**
  9370. + * ssam_event_item_cache_destroy() - Deinitialize the event item cache.
  9371. + */
  9372. +void ssam_event_item_cache_destroy(void)
  9373. +{
  9374. + kmem_cache_destroy(ssam_event_item_cache);
  9375. + ssam_event_item_cache = NULL;
  9376. +}
  9377. +
  9378. +static void __ssam_event_item_free_cached(struct ssam_event_item *item)
  9379. +{
  9380. + kmem_cache_free(ssam_event_item_cache, item);
  9381. +}
  9382. +
  9383. +static void __ssam_event_item_free_generic(struct ssam_event_item *item)
  9384. +{
  9385. + kfree(item);
  9386. +}
  9387. +
  9388. +/**
  9389. + * ssam_event_item_free() - Free the provided event item.
  9390. + * @item: The event item to free.
  9391. + */
  9392. +static void ssam_event_item_free(struct ssam_event_item *item)
  9393. +{
  9394. + item->ops.free(item);
  9395. +}
  9396. +
  9397. /**
  9398. * ssam_event_item_alloc() - Allocate an event item with the given payload size.
  9399. * @len: The event payload length.
  9400. * @flags: The flags used for allocation.
  9401. *
  9402. - * Allocate an event item with the given payload size. Sets the item
  9403. - * operations and payload length values. The item free callback (``ops.free``)
  9404. - * should not be overwritten after this call.
  9405. + * Allocate an event item with the given payload size, preferring allocation
  9406. + * from the event item cache if the payload is small enough (i.e. smaller than
  9407. + * %SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN). Sets the item operations and payload
  9408. + * length values. The item free callback (``ops.free``) should not be
  9409. + * overwritten after this call.
  9410. *
  9411. * Return: Returns the newly allocated event item.
  9412. */
  9413. @@ -528,9 +588,19 @@ static struct ssam_event_item *ssam_event_item_alloc(size_t len, gfp_t flags)
  9414. {
  9415. struct ssam_event_item *item;
  9416. - item = kzalloc(struct_size(item, event.data, len), flags);
  9417. - if (!item)
  9418. - return NULL;
  9419. + if (len <= SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN) {
  9420. + item = kmem_cache_alloc(ssam_event_item_cache, flags);
  9421. + if (!item)
  9422. + return NULL;
  9423. +
  9424. + item->ops.free = __ssam_event_item_free_cached;
  9425. + } else {
  9426. + item = kzalloc(struct_size(item, event.data, len), flags);
  9427. + if (!item)
  9428. + return NULL;
  9429. +
  9430. + item->ops.free = __ssam_event_item_free_generic;
  9431. + }
  9432. item->event.length = len;
  9433. return item;
  9434. @@ -692,7 +762,7 @@ static void ssam_event_queue_work_fn(struct work_struct *work)
  9435. return;
  9436. ssam_nf_call(nf, dev, item->rqid, &item->event);
  9437. - kfree(item);
  9438. + ssam_event_item_free(item);
  9439. } while (--iterations);
  9440. if (!ssam_event_queue_is_empty(queue))
  9441. @@ -900,7 +970,7 @@ static void ssam_handle_event(struct ssh_rtl *rtl,
  9442. memcpy(&item->event.data[0], data->ptr, data->len);
  9443. if (WARN_ON(ssam_cplt_submit_event(&ctrl->cplt, item)))
  9444. - kfree(item);
  9445. + ssam_event_item_free(item);
  9446. }
  9447. static const struct ssh_rtl_ops ssam_rtl_ops = {
  9448. diff --git a/drivers/platform/surface/aggregator/controller.h b/drivers/platform/surface/aggregator/controller.h
  9449. index 5ee9e966f1d7..8297d34e7489 100644
  9450. --- a/drivers/platform/surface/aggregator/controller.h
  9451. +++ b/drivers/platform/surface/aggregator/controller.h
  9452. @@ -80,12 +80,18 @@ struct ssam_cplt;
  9453. * struct ssam_event_item - Struct for event queuing and completion.
  9454. * @node: The node in the queue.
  9455. * @rqid: The request ID of the event.
  9456. + * @ops: Instance specific functions.
  9457. + * @ops.free: Callback for freeing this event item.
  9458. * @event: Actual event data.
  9459. */
  9460. struct ssam_event_item {
  9461. struct list_head node;
  9462. u16 rqid;
  9463. + struct {
  9464. + void (*free)(struct ssam_event_item *event);
  9465. + } ops;
  9466. +
  9467. struct ssam_event event; /* must be last */
  9468. };
  9469. @@ -273,4 +279,7 @@ int ssam_ctrl_notif_d0_entry(struct ssam_controller *ctrl);
  9470. int ssam_controller_suspend(struct ssam_controller *ctrl);
  9471. int ssam_controller_resume(struct ssam_controller *ctrl);
  9472. +int ssam_event_item_cache_init(void);
  9473. +void ssam_event_item_cache_destroy(void);
  9474. +
  9475. #endif /* _SURFACE_AGGREGATOR_CONTROLLER_H */
  9476. diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
  9477. index 60d312f71436..37593234fb31 100644
  9478. --- a/drivers/platform/surface/aggregator/core.c
  9479. +++ b/drivers/platform/surface/aggregator/core.c
  9480. @@ -790,12 +790,23 @@ static int __init ssam_core_init(void)
  9481. status = ssh_ctrl_packet_cache_init();
  9482. if (status)
  9483. - return status;
  9484. + goto err_cpkg;
  9485. +
  9486. + status = ssam_event_item_cache_init();
  9487. + if (status)
  9488. + goto err_evitem;
  9489. status = serdev_device_driver_register(&ssam_serial_hub);
  9490. if (status)
  9491. - ssh_ctrl_packet_cache_destroy();
  9492. + goto err_register;
  9493. + return 0;
  9494. +
  9495. +err_register:
  9496. + ssam_event_item_cache_destroy();
  9497. +err_evitem:
  9498. + ssh_ctrl_packet_cache_destroy();
  9499. +err_cpkg:
  9500. return status;
  9501. }
  9502. module_init(ssam_core_init);
  9503. @@ -803,6 +814,7 @@ module_init(ssam_core_init);
  9504. static void __exit ssam_core_exit(void)
  9505. {
  9506. serdev_device_driver_unregister(&ssam_serial_hub);
  9507. + ssam_event_item_cache_destroy();
  9508. ssh_ctrl_packet_cache_destroy();
  9509. }
  9510. module_exit(ssam_core_exit);
  9511. --
  9512. 2.31.0
  9513. From 7375917efd1285a1f7345d3a1e61374890f139a4 Mon Sep 17 00:00:00 2001
  9514. From: Maximilian Luz <luzmaximilian@gmail.com>
  9515. Date: Mon, 21 Dec 2020 19:39:54 +0100
  9516. Subject: [PATCH] platform/surface: aggregator: Add trace points
  9517. Add trace points to the Surface Aggregator subsystem core. These trace
  9518. points can be used to track packets, requests, and allocations. They are
  9519. further intended for debugging and testing/validation, specifically in
  9520. combination with the error injection capabilities introduced in the
  9521. subsequent commit.
  9522. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  9523. Reviewed-by: Hans de Goede <hdegoede@redhat.com>
  9524. Acked-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
  9525. Link: https://lore.kernel.org/r/20201221183959.1186143-5-luzmaximilian@gmail.com
  9526. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  9527. Patchset: surface-sam
  9528. ---
  9529. drivers/platform/surface/aggregator/Makefile | 3 +
  9530. .../platform/surface/aggregator/controller.c | 5 +
  9531. drivers/platform/surface/aggregator/core.c | 3 +
  9532. .../surface/aggregator/ssh_packet_layer.c | 26 +-
  9533. .../surface/aggregator/ssh_request_layer.c | 18 +
  9534. drivers/platform/surface/aggregator/trace.h | 601 ++++++++++++++++++
  9535. 6 files changed, 655 insertions(+), 1 deletion(-)
  9536. create mode 100644 drivers/platform/surface/aggregator/trace.h
  9537. diff --git a/drivers/platform/surface/aggregator/Makefile b/drivers/platform/surface/aggregator/Makefile
  9538. index faad18d4a7f2..b8b24c8ec310 100644
  9539. --- a/drivers/platform/surface/aggregator/Makefile
  9540. +++ b/drivers/platform/surface/aggregator/Makefile
  9541. @@ -1,6 +1,9 @@
  9542. # SPDX-License-Identifier: GPL-2.0+
  9543. # Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  9544. +# For include/trace/define_trace.h to include trace.h
  9545. +CFLAGS_core.o = -I$(src)
  9546. +
  9547. obj-$(CONFIG_SURFACE_AGGREGATOR) += surface_aggregator.o
  9548. surface_aggregator-objs := core.o
  9549. diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
  9550. index 775a4509bece..5bcb59ed579d 100644
  9551. --- a/drivers/platform/surface/aggregator/controller.c
  9552. +++ b/drivers/platform/surface/aggregator/controller.c
  9553. @@ -32,6 +32,8 @@
  9554. #include "ssh_msgb.h"
  9555. #include "ssh_request_layer.h"
  9556. +#include "trace.h"
  9557. +
  9558. /* -- Safe counters. -------------------------------------------------------- */
  9559. @@ -568,6 +570,7 @@ static void __ssam_event_item_free_generic(struct ssam_event_item *item)
  9560. */
  9561. static void ssam_event_item_free(struct ssam_event_item *item)
  9562. {
  9563. + trace_ssam_event_item_free(item);
  9564. item->ops.free(item);
  9565. }
  9566. @@ -603,6 +606,8 @@ static struct ssam_event_item *ssam_event_item_alloc(size_t len, gfp_t flags)
  9567. }
  9568. item->event.length = len;
  9569. +
  9570. + trace_ssam_event_item_alloc(item, len);
  9571. return item;
  9572. }
  9573. diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
  9574. index 37593234fb31..b6a9dea53592 100644
  9575. --- a/drivers/platform/surface/aggregator/core.c
  9576. +++ b/drivers/platform/surface/aggregator/core.c
  9577. @@ -24,6 +24,9 @@
  9578. #include <linux/surface_aggregator/controller.h>
  9579. #include "controller.h"
  9580. +#define CREATE_TRACE_POINTS
  9581. +#include "trace.h"
  9582. +
  9583. /* -- Static controller reference. ------------------------------------------ */
  9584. diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c
  9585. index 23c2e31e7d0e..c4f082e57372 100644
  9586. --- a/drivers/platform/surface/aggregator/ssh_packet_layer.c
  9587. +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c
  9588. @@ -26,6 +26,8 @@
  9589. #include "ssh_packet_layer.h"
  9590. #include "ssh_parser.h"
  9591. +#include "trace.h"
  9592. +
  9593. /*
  9594. * To simplify reasoning about the code below, we define a few concepts. The
  9595. * system below is similar to a state-machine for packets, however, there are
  9596. @@ -228,6 +230,8 @@ static void __ssh_ptl_packet_release(struct kref *kref)
  9597. {
  9598. struct ssh_packet *p = container_of(kref, struct ssh_packet, refcnt);
  9599. + trace_ssam_packet_release(p);
  9600. +
  9601. ptl_dbg_cond(p->ptl, "ptl: releasing packet %p\n", p);
  9602. p->ops->release(p);
  9603. }
  9604. @@ -356,6 +360,7 @@ static int ssh_ctrl_packet_alloc(struct ssh_packet **packet,
  9605. buffer->ptr = (u8 *)(*packet + 1);
  9606. buffer->len = SSH_MSG_LEN_CTRL;
  9607. + trace_ssam_ctrl_packet_alloc(*packet, buffer->len);
  9608. return 0;
  9609. }
  9610. @@ -365,6 +370,7 @@ static int ssh_ctrl_packet_alloc(struct ssh_packet **packet,
  9611. */
  9612. static void ssh_ctrl_packet_free(struct ssh_packet *p)
  9613. {
  9614. + trace_ssam_ctrl_packet_free(p);
  9615. kmem_cache_free(ssh_ctrl_packet_cache, p);
  9616. }
  9617. @@ -398,7 +404,12 @@ static void ssh_packet_next_try(struct ssh_packet *p)
  9618. lockdep_assert_held(&p->ptl->queue.lock);
  9619. - p->priority = __SSH_PACKET_PRIORITY(base, try + 1);
  9620. + /*
  9621. + * Ensure that we write the priority in one go via WRITE_ONCE() so we
  9622. + * can access it via READ_ONCE() for tracing. Note that other access
  9623. + * is guarded by the queue lock, so no need to use READ_ONCE() there.
  9624. + */
  9625. + WRITE_ONCE(p->priority, __SSH_PACKET_PRIORITY(base, try + 1));
  9626. }
  9627. /* Must be called with queue lock held. */
  9628. @@ -560,6 +571,7 @@ static void __ssh_ptl_complete(struct ssh_packet *p, int status)
  9629. {
  9630. struct ssh_ptl *ptl = READ_ONCE(p->ptl);
  9631. + trace_ssam_packet_complete(p, status);
  9632. ptl_dbg_cond(ptl, "ptl: completing packet %p (status: %d)\n", p, status);
  9633. if (p->ops->complete)
  9634. @@ -1014,6 +1026,8 @@ int ssh_ptl_submit(struct ssh_ptl *ptl, struct ssh_packet *p)
  9635. struct ssh_ptl *ptl_old;
  9636. int status;
  9637. + trace_ssam_packet_submit(p);
  9638. +
  9639. /* Validate packet fields. */
  9640. if (test_bit(SSH_PACKET_TY_FLUSH_BIT, &p->state)) {
  9641. if (p->data.ptr || test_bit(SSH_PACKET_TY_SEQUENCED_BIT, &p->state))
  9642. @@ -1065,6 +1079,8 @@ static int __ssh_ptl_resubmit(struct ssh_packet *packet)
  9643. lockdep_assert_held(&packet->ptl->pending.lock);
  9644. + trace_ssam_packet_resubmit(packet);
  9645. +
  9646. spin_lock(&packet->ptl->queue.lock);
  9647. /* Check if the packet is out of tries. */
  9648. @@ -1148,6 +1164,8 @@ void ssh_ptl_cancel(struct ssh_packet *p)
  9649. if (test_and_set_bit(SSH_PACKET_SF_CANCELED_BIT, &p->state))
  9650. return;
  9651. + trace_ssam_packet_cancel(p);
  9652. +
  9653. /*
  9654. * Lock packet and commit with memory barrier. If this packet has
  9655. * already been locked, it's going to be removed and completed by
  9656. @@ -1202,6 +1220,8 @@ static void ssh_ptl_timeout_reap(struct work_struct *work)
  9657. bool resub = false;
  9658. int status;
  9659. + trace_ssam_ptl_timeout_reap(atomic_read(&ptl->pending.count));
  9660. +
  9661. /*
  9662. * Mark reaper as "not pending". This is done before checking any
  9663. * packets to avoid lost-update type problems.
  9664. @@ -1224,6 +1244,8 @@ static void ssh_ptl_timeout_reap(struct work_struct *work)
  9665. continue;
  9666. }
  9667. + trace_ssam_packet_timeout(p);
  9668. +
  9669. status = __ssh_ptl_resubmit(p);
  9670. /*
  9671. @@ -1416,6 +1438,8 @@ static size_t ssh_ptl_rx_eval(struct ssh_ptl *ptl, struct ssam_span *source)
  9672. if (!frame) /* Not enough data. */
  9673. return aligned.ptr - source->ptr;
  9674. + trace_ssam_rx_frame_received(frame);
  9675. +
  9676. switch (frame->type) {
  9677. case SSH_FRAME_TYPE_ACK:
  9678. ssh_ptl_acknowledge(ptl, frame->seq);
  9679. diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c
  9680. index 66c839a995f3..b649d71840fd 100644
  9681. --- a/drivers/platform/surface/aggregator/ssh_request_layer.c
  9682. +++ b/drivers/platform/surface/aggregator/ssh_request_layer.c
  9683. @@ -22,6 +22,8 @@
  9684. #include "ssh_packet_layer.h"
  9685. #include "ssh_request_layer.h"
  9686. +#include "trace.h"
  9687. +
  9688. /*
  9689. * SSH_RTL_REQUEST_TIMEOUT - Request timeout.
  9690. *
  9691. @@ -144,6 +146,8 @@ static void ssh_rtl_complete_with_status(struct ssh_request *rqst, int status)
  9692. {
  9693. struct ssh_rtl *rtl = ssh_request_rtl(rqst);
  9694. + trace_ssam_request_complete(rqst, status);
  9695. +
  9696. /* rtl/ptl may not be set if we're canceling before submitting. */
  9697. rtl_dbg_cond(rtl, "rtl: completing request (rqid: %#06x, status: %d)\n",
  9698. ssh_request_get_rqid_safe(rqst), status);
  9699. @@ -157,6 +161,8 @@ static void ssh_rtl_complete_with_rsp(struct ssh_request *rqst,
  9700. {
  9701. struct ssh_rtl *rtl = ssh_request_rtl(rqst);
  9702. + trace_ssam_request_complete(rqst, 0);
  9703. +
  9704. rtl_dbg(rtl, "rtl: completing request with response (rqid: %#06x)\n",
  9705. ssh_request_get_rqid(rqst));
  9706. @@ -329,6 +335,8 @@ static void ssh_rtl_tx_work_fn(struct work_struct *work)
  9707. */
  9708. int ssh_rtl_submit(struct ssh_rtl *rtl, struct ssh_request *rqst)
  9709. {
  9710. + trace_ssam_request_submit(rqst);
  9711. +
  9712. /*
  9713. * Ensure that requests expecting a response are sequenced. If this
  9714. * invariant ever changes, see the comment in ssh_rtl_complete() on what
  9715. @@ -439,6 +447,8 @@ static void ssh_rtl_complete(struct ssh_rtl *rtl,
  9716. struct ssh_request *p, *n;
  9717. u16 rqid = get_unaligned_le16(&command->rqid);
  9718. + trace_ssam_rx_response_received(command, command_data->len);
  9719. +
  9720. /*
  9721. * Get request from pending based on request ID and mark it as response
  9722. * received and locked.
  9723. @@ -688,6 +698,8 @@ bool ssh_rtl_cancel(struct ssh_request *rqst, bool pending)
  9724. if (test_and_set_bit(SSH_REQUEST_SF_CANCELED_BIT, &rqst->state))
  9725. return true;
  9726. + trace_ssam_request_cancel(rqst);
  9727. +
  9728. if (pending)
  9729. canceled = ssh_rtl_cancel_pending(rqst);
  9730. else
  9731. @@ -779,6 +791,8 @@ static void ssh_rtl_timeout_reap(struct work_struct *work)
  9732. ktime_t timeout = rtl->rtx_timeout.timeout;
  9733. ktime_t next = KTIME_MAX;
  9734. + trace_ssam_rtl_timeout_reap(atomic_read(&rtl->pending.count));
  9735. +
  9736. /*
  9737. * Mark reaper as "not pending". This is done before checking any
  9738. * requests to avoid lost-update type problems.
  9739. @@ -822,6 +836,8 @@ static void ssh_rtl_timeout_reap(struct work_struct *work)
  9740. /* Cancel and complete the request. */
  9741. list_for_each_entry_safe(r, n, &claimed, node) {
  9742. + trace_ssam_request_timeout(r);
  9743. +
  9744. /*
  9745. * At this point we've removed the packet from pending. This
  9746. * means that we've obtained the last (only) reference of the
  9747. @@ -849,6 +865,8 @@ static void ssh_rtl_timeout_reap(struct work_struct *work)
  9748. static void ssh_rtl_rx_event(struct ssh_rtl *rtl, const struct ssh_command *cmd,
  9749. const struct ssam_span *data)
  9750. {
  9751. + trace_ssam_rx_event_received(cmd, data->len);
  9752. +
  9753. rtl_dbg(rtl, "rtl: handling event (rqid: %#06x)\n",
  9754. get_unaligned_le16(&cmd->rqid));
  9755. diff --git a/drivers/platform/surface/aggregator/trace.h b/drivers/platform/surface/aggregator/trace.h
  9756. new file mode 100644
  9757. index 000000000000..dcca8007d876
  9758. --- /dev/null
  9759. +++ b/drivers/platform/surface/aggregator/trace.h
  9760. @@ -0,0 +1,601 @@
  9761. +/* SPDX-License-Identifier: GPL-2.0+ */
  9762. +/*
  9763. + * Trace points for SSAM/SSH.
  9764. + *
  9765. + * Copyright (C) 2020 Maximilian Luz <luzmaximilian@gmail.com>
  9766. + */
  9767. +
  9768. +#undef TRACE_SYSTEM
  9769. +#define TRACE_SYSTEM surface_aggregator
  9770. +
  9771. +#if !defined(_SURFACE_AGGREGATOR_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
  9772. +#define _SURFACE_AGGREGATOR_TRACE_H
  9773. +
  9774. +#include <linux/surface_aggregator/serial_hub.h>
  9775. +
  9776. +#include <asm/unaligned.h>
  9777. +#include <linux/tracepoint.h>
  9778. +
  9779. +TRACE_DEFINE_ENUM(SSH_FRAME_TYPE_DATA_SEQ);
  9780. +TRACE_DEFINE_ENUM(SSH_FRAME_TYPE_DATA_NSQ);
  9781. +TRACE_DEFINE_ENUM(SSH_FRAME_TYPE_ACK);
  9782. +TRACE_DEFINE_ENUM(SSH_FRAME_TYPE_NAK);
  9783. +
  9784. +TRACE_DEFINE_ENUM(SSH_PACKET_SF_LOCKED_BIT);
  9785. +TRACE_DEFINE_ENUM(SSH_PACKET_SF_QUEUED_BIT);
  9786. +TRACE_DEFINE_ENUM(SSH_PACKET_SF_PENDING_BIT);
  9787. +TRACE_DEFINE_ENUM(SSH_PACKET_SF_TRANSMITTING_BIT);
  9788. +TRACE_DEFINE_ENUM(SSH_PACKET_SF_TRANSMITTED_BIT);
  9789. +TRACE_DEFINE_ENUM(SSH_PACKET_SF_ACKED_BIT);
  9790. +TRACE_DEFINE_ENUM(SSH_PACKET_SF_CANCELED_BIT);
  9791. +TRACE_DEFINE_ENUM(SSH_PACKET_SF_COMPLETED_BIT);
  9792. +
  9793. +TRACE_DEFINE_ENUM(SSH_PACKET_TY_FLUSH_BIT);
  9794. +TRACE_DEFINE_ENUM(SSH_PACKET_TY_SEQUENCED_BIT);
  9795. +TRACE_DEFINE_ENUM(SSH_PACKET_TY_BLOCKING_BIT);
  9796. +
  9797. +TRACE_DEFINE_ENUM(SSH_PACKET_FLAGS_SF_MASK);
  9798. +TRACE_DEFINE_ENUM(SSH_PACKET_FLAGS_TY_MASK);
  9799. +
  9800. +TRACE_DEFINE_ENUM(SSH_REQUEST_SF_LOCKED_BIT);
  9801. +TRACE_DEFINE_ENUM(SSH_REQUEST_SF_QUEUED_BIT);
  9802. +TRACE_DEFINE_ENUM(SSH_REQUEST_SF_PENDING_BIT);
  9803. +TRACE_DEFINE_ENUM(SSH_REQUEST_SF_TRANSMITTING_BIT);
  9804. +TRACE_DEFINE_ENUM(SSH_REQUEST_SF_TRANSMITTED_BIT);
  9805. +TRACE_DEFINE_ENUM(SSH_REQUEST_SF_RSPRCVD_BIT);
  9806. +TRACE_DEFINE_ENUM(SSH_REQUEST_SF_CANCELED_BIT);
  9807. +TRACE_DEFINE_ENUM(SSH_REQUEST_SF_COMPLETED_BIT);
  9808. +
  9809. +TRACE_DEFINE_ENUM(SSH_REQUEST_TY_FLUSH_BIT);
  9810. +TRACE_DEFINE_ENUM(SSH_REQUEST_TY_HAS_RESPONSE_BIT);
  9811. +
  9812. +TRACE_DEFINE_ENUM(SSH_REQUEST_FLAGS_SF_MASK);
  9813. +TRACE_DEFINE_ENUM(SSH_REQUEST_FLAGS_TY_MASK);
  9814. +
  9815. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_SAM);
  9816. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_BAT);
  9817. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_TMP);
  9818. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_PMC);
  9819. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_FAN);
  9820. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_PoM);
  9821. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_DBG);
  9822. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_KBD);
  9823. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_FWU);
  9824. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_UNI);
  9825. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_LPC);
  9826. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_TCL);
  9827. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_SFL);
  9828. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_KIP);
  9829. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_EXT);
  9830. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_BLD);
  9831. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_BAS);
  9832. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_SEN);
  9833. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_SRQ);
  9834. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_MCU);
  9835. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_HID);
  9836. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_TCH);
  9837. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_BKL);
  9838. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_TAM);
  9839. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_ACC);
  9840. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_UFI);
  9841. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_USC);
  9842. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_PEN);
  9843. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_VID);
  9844. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_AUD);
  9845. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_SMC);
  9846. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_KPD);
  9847. +TRACE_DEFINE_ENUM(SSAM_SSH_TC_REG);
  9848. +
  9849. +#define SSAM_PTR_UID_LEN 9
  9850. +#define SSAM_U8_FIELD_NOT_APPLICABLE ((u16)-1)
  9851. +#define SSAM_SEQ_NOT_APPLICABLE ((u16)-1)
  9852. +#define SSAM_RQID_NOT_APPLICABLE ((u32)-1)
  9853. +#define SSAM_SSH_TC_NOT_APPLICABLE 0
  9854. +
  9855. +#ifndef _SURFACE_AGGREGATOR_TRACE_HELPERS
  9856. +#define _SURFACE_AGGREGATOR_TRACE_HELPERS
  9857. +
  9858. +/**
  9859. + * ssam_trace_ptr_uid() - Convert the pointer to a non-pointer UID string.
  9860. + * @ptr: The pointer to convert.
  9861. + * @uid_str: A buffer of length SSAM_PTR_UID_LEN where the UID will be stored.
  9862. + *
  9863. + * Converts the given pointer into a UID string that is safe to be shared
  9864. + * with userspace and logs, i.e. doesn't give away the real memory location.
  9865. + */
  9866. +static inline void ssam_trace_ptr_uid(const void *ptr, char *uid_str)
  9867. +{
  9868. + char buf[2 * sizeof(void *) + 1];
  9869. +
  9870. + BUILD_BUG_ON(ARRAY_SIZE(buf) < SSAM_PTR_UID_LEN);
  9871. +
  9872. + snprintf(buf, ARRAY_SIZE(buf), "%p", ptr);
  9873. + memcpy(uid_str, &buf[ARRAY_SIZE(buf) - SSAM_PTR_UID_LEN],
  9874. + SSAM_PTR_UID_LEN);
  9875. +}
  9876. +
  9877. +/**
  9878. + * ssam_trace_get_packet_seq() - Read the packet's sequence ID.
  9879. + * @p: The packet.
  9880. + *
  9881. + * Return: Returns the packet's sequence ID (SEQ) field if present, or
  9882. + * %SSAM_SEQ_NOT_APPLICABLE if not (e.g. flush packet).
  9883. + */
  9884. +static inline u16 ssam_trace_get_packet_seq(const struct ssh_packet *p)
  9885. +{
  9886. + if (!p->data.ptr || p->data.len < SSH_MESSAGE_LENGTH(0))
  9887. + return SSAM_SEQ_NOT_APPLICABLE;
  9888. +
  9889. + return p->data.ptr[SSH_MSGOFFSET_FRAME(seq)];
  9890. +}
  9891. +
  9892. +/**
  9893. + * ssam_trace_get_request_id() - Read the packet's request ID.
  9894. + * @p: The packet.
  9895. + *
  9896. + * Return: Returns the packet's request ID (RQID) field if the packet
  9897. + * represents a request with command data, or %SSAM_RQID_NOT_APPLICABLE if not
  9898. + * (e.g. flush request, control packet).
  9899. + */
  9900. +static inline u32 ssam_trace_get_request_id(const struct ssh_packet *p)
  9901. +{
  9902. + if (!p->data.ptr || p->data.len < SSH_COMMAND_MESSAGE_LENGTH(0))
  9903. + return SSAM_RQID_NOT_APPLICABLE;
  9904. +
  9905. + return get_unaligned_le16(&p->data.ptr[SSH_MSGOFFSET_COMMAND(rqid)]);
  9906. +}
  9907. +
  9908. +/**
  9909. + * ssam_trace_get_request_tc() - Read the packet's request target category.
  9910. + * @p: The packet.
  9911. + *
  9912. + * Return: Returns the packet's request target category (TC) field if the
  9913. + * packet represents a request with command data, or %SSAM_TC_NOT_APPLICABLE
  9914. + * if not (e.g. flush request, control packet).
  9915. + */
  9916. +static inline u32 ssam_trace_get_request_tc(const struct ssh_packet *p)
  9917. +{
  9918. + if (!p->data.ptr || p->data.len < SSH_COMMAND_MESSAGE_LENGTH(0))
  9919. + return SSAM_SSH_TC_NOT_APPLICABLE;
  9920. +
  9921. + return get_unaligned_le16(&p->data.ptr[SSH_MSGOFFSET_COMMAND(tc)]);
  9922. +}
  9923. +
  9924. +#endif /* _SURFACE_AGGREGATOR_TRACE_HELPERS */
  9925. +
  9926. +#define ssam_trace_get_command_field_u8(packet, field) \
  9927. + ((!(packet) || (packet)->data.len < SSH_COMMAND_MESSAGE_LENGTH(0)) \
  9928. + ? 0 : (packet)->data.ptr[SSH_MSGOFFSET_COMMAND(field)])
  9929. +
  9930. +#define ssam_show_generic_u8_field(value) \
  9931. + __print_symbolic(value, \
  9932. + { SSAM_U8_FIELD_NOT_APPLICABLE, "N/A" } \
  9933. + )
  9934. +
  9935. +#define ssam_show_frame_type(ty) \
  9936. + __print_symbolic(ty, \
  9937. + { SSH_FRAME_TYPE_DATA_SEQ, "DSEQ" }, \
  9938. + { SSH_FRAME_TYPE_DATA_NSQ, "DNSQ" }, \
  9939. + { SSH_FRAME_TYPE_ACK, "ACK" }, \
  9940. + { SSH_FRAME_TYPE_NAK, "NAK" } \
  9941. + )
  9942. +
  9943. +#define ssam_show_packet_type(type) \
  9944. + __print_flags(flags & SSH_PACKET_FLAGS_TY_MASK, "", \
  9945. + { BIT(SSH_PACKET_TY_FLUSH_BIT), "F" }, \
  9946. + { BIT(SSH_PACKET_TY_SEQUENCED_BIT), "S" }, \
  9947. + { BIT(SSH_PACKET_TY_BLOCKING_BIT), "B" } \
  9948. + )
  9949. +
  9950. +#define ssam_show_packet_state(state) \
  9951. + __print_flags(flags & SSH_PACKET_FLAGS_SF_MASK, "", \
  9952. + { BIT(SSH_PACKET_SF_LOCKED_BIT), "L" }, \
  9953. + { BIT(SSH_PACKET_SF_QUEUED_BIT), "Q" }, \
  9954. + { BIT(SSH_PACKET_SF_PENDING_BIT), "P" }, \
  9955. + { BIT(SSH_PACKET_SF_TRANSMITTING_BIT), "S" }, \
  9956. + { BIT(SSH_PACKET_SF_TRANSMITTED_BIT), "T" }, \
  9957. + { BIT(SSH_PACKET_SF_ACKED_BIT), "A" }, \
  9958. + { BIT(SSH_PACKET_SF_CANCELED_BIT), "C" }, \
  9959. + { BIT(SSH_PACKET_SF_COMPLETED_BIT), "F" } \
  9960. + )
  9961. +
  9962. +#define ssam_show_packet_seq(seq) \
  9963. + __print_symbolic(seq, \
  9964. + { SSAM_SEQ_NOT_APPLICABLE, "N/A" } \
  9965. + )
  9966. +
  9967. +#define ssam_show_request_type(flags) \
  9968. + __print_flags((flags) & SSH_REQUEST_FLAGS_TY_MASK, "", \
  9969. + { BIT(SSH_REQUEST_TY_FLUSH_BIT), "F" }, \
  9970. + { BIT(SSH_REQUEST_TY_HAS_RESPONSE_BIT), "R" } \
  9971. + )
  9972. +
  9973. +#define ssam_show_request_state(flags) \
  9974. + __print_flags((flags) & SSH_REQUEST_FLAGS_SF_MASK, "", \
  9975. + { BIT(SSH_REQUEST_SF_LOCKED_BIT), "L" }, \
  9976. + { BIT(SSH_REQUEST_SF_QUEUED_BIT), "Q" }, \
  9977. + { BIT(SSH_REQUEST_SF_PENDING_BIT), "P" }, \
  9978. + { BIT(SSH_REQUEST_SF_TRANSMITTING_BIT), "S" }, \
  9979. + { BIT(SSH_REQUEST_SF_TRANSMITTED_BIT), "T" }, \
  9980. + { BIT(SSH_REQUEST_SF_RSPRCVD_BIT), "A" }, \
  9981. + { BIT(SSH_REQUEST_SF_CANCELED_BIT), "C" }, \
  9982. + { BIT(SSH_REQUEST_SF_COMPLETED_BIT), "F" } \
  9983. + )
  9984. +
  9985. +#define ssam_show_request_id(rqid) \
  9986. + __print_symbolic(rqid, \
  9987. + { SSAM_RQID_NOT_APPLICABLE, "N/A" } \
  9988. + )
  9989. +
  9990. +#define ssam_show_ssh_tc(rqid) \
  9991. + __print_symbolic(rqid, \
  9992. + { SSAM_SSH_TC_NOT_APPLICABLE, "N/A" }, \
  9993. + { SSAM_SSH_TC_SAM, "SAM" }, \
  9994. + { SSAM_SSH_TC_BAT, "BAT" }, \
  9995. + { SSAM_SSH_TC_TMP, "TMP" }, \
  9996. + { SSAM_SSH_TC_PMC, "PMC" }, \
  9997. + { SSAM_SSH_TC_FAN, "FAN" }, \
  9998. + { SSAM_SSH_TC_PoM, "PoM" }, \
  9999. + { SSAM_SSH_TC_DBG, "DBG" }, \
  10000. + { SSAM_SSH_TC_KBD, "KBD" }, \
  10001. + { SSAM_SSH_TC_FWU, "FWU" }, \
  10002. + { SSAM_SSH_TC_UNI, "UNI" }, \
  10003. + { SSAM_SSH_TC_LPC, "LPC" }, \
  10004. + { SSAM_SSH_TC_TCL, "TCL" }, \
  10005. + { SSAM_SSH_TC_SFL, "SFL" }, \
  10006. + { SSAM_SSH_TC_KIP, "KIP" }, \
  10007. + { SSAM_SSH_TC_EXT, "EXT" }, \
  10008. + { SSAM_SSH_TC_BLD, "BLD" }, \
  10009. + { SSAM_SSH_TC_BAS, "BAS" }, \
  10010. + { SSAM_SSH_TC_SEN, "SEN" }, \
  10011. + { SSAM_SSH_TC_SRQ, "SRQ" }, \
  10012. + { SSAM_SSH_TC_MCU, "MCU" }, \
  10013. + { SSAM_SSH_TC_HID, "HID" }, \
  10014. + { SSAM_SSH_TC_TCH, "TCH" }, \
  10015. + { SSAM_SSH_TC_BKL, "BKL" }, \
  10016. + { SSAM_SSH_TC_TAM, "TAM" }, \
  10017. + { SSAM_SSH_TC_ACC, "ACC" }, \
  10018. + { SSAM_SSH_TC_UFI, "UFI" }, \
  10019. + { SSAM_SSH_TC_USC, "USC" }, \
  10020. + { SSAM_SSH_TC_PEN, "PEN" }, \
  10021. + { SSAM_SSH_TC_VID, "VID" }, \
  10022. + { SSAM_SSH_TC_AUD, "AUD" }, \
  10023. + { SSAM_SSH_TC_SMC, "SMC" }, \
  10024. + { SSAM_SSH_TC_KPD, "KPD" }, \
  10025. + { SSAM_SSH_TC_REG, "REG" } \
  10026. + )
  10027. +
  10028. +DECLARE_EVENT_CLASS(ssam_frame_class,
  10029. + TP_PROTO(const struct ssh_frame *frame),
  10030. +
  10031. + TP_ARGS(frame),
  10032. +
  10033. + TP_STRUCT__entry(
  10034. + __field(u8, type)
  10035. + __field(u8, seq)
  10036. + __field(u16, len)
  10037. + ),
  10038. +
  10039. + TP_fast_assign(
  10040. + __entry->type = frame->type;
  10041. + __entry->seq = frame->seq;
  10042. + __entry->len = get_unaligned_le16(&frame->len);
  10043. + ),
  10044. +
  10045. + TP_printk("ty=%s, seq=%#04x, len=%u",
  10046. + ssam_show_frame_type(__entry->type),
  10047. + __entry->seq,
  10048. + __entry->len
  10049. + )
  10050. +);
  10051. +
  10052. +#define DEFINE_SSAM_FRAME_EVENT(name) \
  10053. + DEFINE_EVENT(ssam_frame_class, ssam_##name, \
  10054. + TP_PROTO(const struct ssh_frame *frame), \
  10055. + TP_ARGS(frame) \
  10056. + )
  10057. +
  10058. +DECLARE_EVENT_CLASS(ssam_command_class,
  10059. + TP_PROTO(const struct ssh_command *cmd, u16 len),
  10060. +
  10061. + TP_ARGS(cmd, len),
  10062. +
  10063. + TP_STRUCT__entry(
  10064. + __field(u16, rqid)
  10065. + __field(u16, len)
  10066. + __field(u8, tc)
  10067. + __field(u8, cid)
  10068. + __field(u8, iid)
  10069. + ),
  10070. +
  10071. + TP_fast_assign(
  10072. + __entry->rqid = get_unaligned_le16(&cmd->rqid);
  10073. + __entry->tc = cmd->tc;
  10074. + __entry->cid = cmd->cid;
  10075. + __entry->iid = cmd->iid;
  10076. + __entry->len = len;
  10077. + ),
  10078. +
  10079. + TP_printk("rqid=%#06x, tc=%s, cid=%#04x, iid=%#04x, len=%u",
  10080. + __entry->rqid,
  10081. + ssam_show_ssh_tc(__entry->tc),
  10082. + __entry->cid,
  10083. + __entry->iid,
  10084. + __entry->len
  10085. + )
  10086. +);
  10087. +
  10088. +#define DEFINE_SSAM_COMMAND_EVENT(name) \
  10089. + DEFINE_EVENT(ssam_command_class, ssam_##name, \
  10090. + TP_PROTO(const struct ssh_command *cmd, u16 len), \
  10091. + TP_ARGS(cmd, len) \
  10092. + )
  10093. +
  10094. +DECLARE_EVENT_CLASS(ssam_packet_class,
  10095. + TP_PROTO(const struct ssh_packet *packet),
  10096. +
  10097. + TP_ARGS(packet),
  10098. +
  10099. + TP_STRUCT__entry(
  10100. + __field(unsigned long, state)
  10101. + __array(char, uid, SSAM_PTR_UID_LEN)
  10102. + __field(u8, priority)
  10103. + __field(u16, length)
  10104. + __field(u16, seq)
  10105. + ),
  10106. +
  10107. + TP_fast_assign(
  10108. + __entry->state = READ_ONCE(packet->state);
  10109. + ssam_trace_ptr_uid(packet, __entry->uid);
  10110. + __entry->priority = READ_ONCE(packet->priority);
  10111. + __entry->length = packet->data.len;
  10112. + __entry->seq = ssam_trace_get_packet_seq(packet);
  10113. + ),
  10114. +
  10115. + TP_printk("uid=%s, seq=%s, ty=%s, pri=%#04x, len=%u, sta=%s",
  10116. + __entry->uid,
  10117. + ssam_show_packet_seq(__entry->seq),
  10118. + ssam_show_packet_type(__entry->state),
  10119. + __entry->priority,
  10120. + __entry->length,
  10121. + ssam_show_packet_state(__entry->state)
  10122. + )
  10123. +);
  10124. +
  10125. +#define DEFINE_SSAM_PACKET_EVENT(name) \
  10126. + DEFINE_EVENT(ssam_packet_class, ssam_##name, \
  10127. + TP_PROTO(const struct ssh_packet *packet), \
  10128. + TP_ARGS(packet) \
  10129. + )
  10130. +
  10131. +DECLARE_EVENT_CLASS(ssam_packet_status_class,
  10132. + TP_PROTO(const struct ssh_packet *packet, int status),
  10133. +
  10134. + TP_ARGS(packet, status),
  10135. +
  10136. + TP_STRUCT__entry(
  10137. + __field(unsigned long, state)
  10138. + __field(int, status)
  10139. + __array(char, uid, SSAM_PTR_UID_LEN)
  10140. + __field(u8, priority)
  10141. + __field(u16, length)
  10142. + __field(u16, seq)
  10143. + ),
  10144. +
  10145. + TP_fast_assign(
  10146. + __entry->state = READ_ONCE(packet->state);
  10147. + __entry->status = status;
  10148. + ssam_trace_ptr_uid(packet, __entry->uid);
  10149. + __entry->priority = READ_ONCE(packet->priority);
  10150. + __entry->length = packet->data.len;
  10151. + __entry->seq = ssam_trace_get_packet_seq(packet);
  10152. + ),
  10153. +
  10154. + TP_printk("uid=%s, seq=%s, ty=%s, pri=%#04x, len=%u, sta=%s, status=%d",
  10155. + __entry->uid,
  10156. + ssam_show_packet_seq(__entry->seq),
  10157. + ssam_show_packet_type(__entry->state),
  10158. + __entry->priority,
  10159. + __entry->length,
  10160. + ssam_show_packet_state(__entry->state),
  10161. + __entry->status
  10162. + )
  10163. +);
  10164. +
  10165. +#define DEFINE_SSAM_PACKET_STATUS_EVENT(name) \
  10166. + DEFINE_EVENT(ssam_packet_status_class, ssam_##name, \
  10167. + TP_PROTO(const struct ssh_packet *packet, int status), \
  10168. + TP_ARGS(packet, status) \
  10169. + )
  10170. +
  10171. +DECLARE_EVENT_CLASS(ssam_request_class,
  10172. + TP_PROTO(const struct ssh_request *request),
  10173. +
  10174. + TP_ARGS(request),
  10175. +
  10176. + TP_STRUCT__entry(
  10177. + __field(unsigned long, state)
  10178. + __field(u32, rqid)
  10179. + __array(char, uid, SSAM_PTR_UID_LEN)
  10180. + __field(u8, tc)
  10181. + __field(u16, cid)
  10182. + __field(u16, iid)
  10183. + ),
  10184. +
  10185. + TP_fast_assign(
  10186. + const struct ssh_packet *p = &request->packet;
  10187. +
  10188. + /* Use packet for UID so we can match requests to packets. */
  10189. + __entry->state = READ_ONCE(request->state);
  10190. + __entry->rqid = ssam_trace_get_request_id(p);
  10191. + ssam_trace_ptr_uid(p, __entry->uid);
  10192. + __entry->tc = ssam_trace_get_request_tc(p);
  10193. + __entry->cid = ssam_trace_get_command_field_u8(p, cid);
  10194. + __entry->iid = ssam_trace_get_command_field_u8(p, iid);
  10195. + ),
  10196. +
  10197. + TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tc=%s, cid=%s, iid=%s",
  10198. + __entry->uid,
  10199. + ssam_show_request_id(__entry->rqid),
  10200. + ssam_show_request_type(__entry->state),
  10201. + ssam_show_request_state(__entry->state),
  10202. + ssam_show_ssh_tc(__entry->tc),
  10203. + ssam_show_generic_u8_field(__entry->cid),
  10204. + ssam_show_generic_u8_field(__entry->iid)
  10205. + )
  10206. +);
  10207. +
  10208. +#define DEFINE_SSAM_REQUEST_EVENT(name) \
  10209. + DEFINE_EVENT(ssam_request_class, ssam_##name, \
  10210. + TP_PROTO(const struct ssh_request *request), \
  10211. + TP_ARGS(request) \
  10212. + )
  10213. +
  10214. +DECLARE_EVENT_CLASS(ssam_request_status_class,
  10215. + TP_PROTO(const struct ssh_request *request, int status),
  10216. +
  10217. + TP_ARGS(request, status),
  10218. +
  10219. + TP_STRUCT__entry(
  10220. + __field(unsigned long, state)
  10221. + __field(u32, rqid)
  10222. + __field(int, status)
  10223. + __array(char, uid, SSAM_PTR_UID_LEN)
  10224. + __field(u8, tc)
  10225. + __field(u16, cid)
  10226. + __field(u16, iid)
  10227. + ),
  10228. +
  10229. + TP_fast_assign(
  10230. + const struct ssh_packet *p = &request->packet;
  10231. +
  10232. + /* Use packet for UID so we can match requests to packets. */
  10233. + __entry->state = READ_ONCE(request->state);
  10234. + __entry->rqid = ssam_trace_get_request_id(p);
  10235. + __entry->status = status;
  10236. + ssam_trace_ptr_uid(p, __entry->uid);
  10237. + __entry->tc = ssam_trace_get_request_tc(p);
  10238. + __entry->cid = ssam_trace_get_command_field_u8(p, cid);
  10239. + __entry->iid = ssam_trace_get_command_field_u8(p, iid);
  10240. + ),
  10241. +
  10242. + TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tc=%s, cid=%s, iid=%s, status=%d",
  10243. + __entry->uid,
  10244. + ssam_show_request_id(__entry->rqid),
  10245. + ssam_show_request_type(__entry->state),
  10246. + ssam_show_request_state(__entry->state),
  10247. + ssam_show_ssh_tc(__entry->tc),
  10248. + ssam_show_generic_u8_field(__entry->cid),
  10249. + ssam_show_generic_u8_field(__entry->iid),
  10250. + __entry->status
  10251. + )
  10252. +);
  10253. +
  10254. +#define DEFINE_SSAM_REQUEST_STATUS_EVENT(name) \
  10255. + DEFINE_EVENT(ssam_request_status_class, ssam_##name, \
  10256. + TP_PROTO(const struct ssh_request *request, int status),\
  10257. + TP_ARGS(request, status) \
  10258. + )
  10259. +
  10260. +DECLARE_EVENT_CLASS(ssam_alloc_class,
  10261. + TP_PROTO(void *ptr, size_t len),
  10262. +
  10263. + TP_ARGS(ptr, len),
  10264. +
  10265. + TP_STRUCT__entry(
  10266. + __field(size_t, len)
  10267. + __array(char, uid, SSAM_PTR_UID_LEN)
  10268. + ),
  10269. +
  10270. + TP_fast_assign(
  10271. + __entry->len = len;
  10272. + ssam_trace_ptr_uid(ptr, __entry->uid);
  10273. + ),
  10274. +
  10275. + TP_printk("uid=%s, len=%zu", __entry->uid, __entry->len)
  10276. +);
  10277. +
  10278. +#define DEFINE_SSAM_ALLOC_EVENT(name) \
  10279. + DEFINE_EVENT(ssam_alloc_class, ssam_##name, \
  10280. + TP_PROTO(void *ptr, size_t len), \
  10281. + TP_ARGS(ptr, len) \
  10282. + )
  10283. +
  10284. +DECLARE_EVENT_CLASS(ssam_free_class,
  10285. + TP_PROTO(void *ptr),
  10286. +
  10287. + TP_ARGS(ptr),
  10288. +
  10289. + TP_STRUCT__entry(
  10290. + __array(char, uid, SSAM_PTR_UID_LEN)
  10291. + ),
  10292. +
  10293. + TP_fast_assign(
  10294. + ssam_trace_ptr_uid(ptr, __entry->uid);
  10295. + ),
  10296. +
  10297. + TP_printk("uid=%s", __entry->uid)
  10298. +);
  10299. +
  10300. +#define DEFINE_SSAM_FREE_EVENT(name) \
  10301. + DEFINE_EVENT(ssam_free_class, ssam_##name, \
  10302. + TP_PROTO(void *ptr), \
  10303. + TP_ARGS(ptr) \
  10304. + )
  10305. +
  10306. +DECLARE_EVENT_CLASS(ssam_pending_class,
  10307. + TP_PROTO(unsigned int pending),
  10308. +
  10309. + TP_ARGS(pending),
  10310. +
  10311. + TP_STRUCT__entry(
  10312. + __field(unsigned int, pending)
  10313. + ),
  10314. +
  10315. + TP_fast_assign(
  10316. + __entry->pending = pending;
  10317. + ),
  10318. +
  10319. + TP_printk("pending=%u", __entry->pending)
  10320. +);
  10321. +
  10322. +#define DEFINE_SSAM_PENDING_EVENT(name) \
  10323. + DEFINE_EVENT(ssam_pending_class, ssam_##name, \
  10324. + TP_PROTO(unsigned int pending), \
  10325. + TP_ARGS(pending) \
  10326. + )
  10327. +
  10328. +DEFINE_SSAM_FRAME_EVENT(rx_frame_received);
  10329. +DEFINE_SSAM_COMMAND_EVENT(rx_response_received);
  10330. +DEFINE_SSAM_COMMAND_EVENT(rx_event_received);
  10331. +
  10332. +DEFINE_SSAM_PACKET_EVENT(packet_release);
  10333. +DEFINE_SSAM_PACKET_EVENT(packet_submit);
  10334. +DEFINE_SSAM_PACKET_EVENT(packet_resubmit);
  10335. +DEFINE_SSAM_PACKET_EVENT(packet_timeout);
  10336. +DEFINE_SSAM_PACKET_EVENT(packet_cancel);
  10337. +DEFINE_SSAM_PACKET_STATUS_EVENT(packet_complete);
  10338. +DEFINE_SSAM_PENDING_EVENT(ptl_timeout_reap);
  10339. +
  10340. +DEFINE_SSAM_REQUEST_EVENT(request_submit);
  10341. +DEFINE_SSAM_REQUEST_EVENT(request_timeout);
  10342. +DEFINE_SSAM_REQUEST_EVENT(request_cancel);
  10343. +DEFINE_SSAM_REQUEST_STATUS_EVENT(request_complete);
  10344. +DEFINE_SSAM_PENDING_EVENT(rtl_timeout_reap);
  10345. +
  10346. +DEFINE_SSAM_ALLOC_EVENT(ctrl_packet_alloc);
  10347. +DEFINE_SSAM_FREE_EVENT(ctrl_packet_free);
  10348. +
  10349. +DEFINE_SSAM_ALLOC_EVENT(event_item_alloc);
  10350. +DEFINE_SSAM_FREE_EVENT(event_item_free);
  10351. +
  10352. +#endif /* _SURFACE_AGGREGATOR_TRACE_H */
  10353. +
  10354. +/* This part must be outside protection */
  10355. +#undef TRACE_INCLUDE_PATH
  10356. +#undef TRACE_INCLUDE_FILE
  10357. +
  10358. +#define TRACE_INCLUDE_PATH .
  10359. +#define TRACE_INCLUDE_FILE trace
  10360. +
  10361. +#include <trace/define_trace.h>
  10362. --
  10363. 2.31.0
  10364. From 65bd02ca093d1733cb54549a9751638451b52384 Mon Sep 17 00:00:00 2001
  10365. From: Maximilian Luz <luzmaximilian@gmail.com>
  10366. Date: Mon, 21 Dec 2020 19:39:55 +0100
  10367. Subject: [PATCH] platform/surface: aggregator: Add error injection
  10368. capabilities
  10369. This commit adds error injection hooks to the Surface Serial Hub
  10370. communication protocol implementation, to:
  10371. - simulate simple serial transmission errors,
  10372. - drop packets, requests, and responses, simulating communication
  10373. failures and potentially trigger retransmission timeouts, as well as
  10374. - inject invalid data into submitted and received packets.
  10375. Together with the trace points introduced in the previous commit, these
  10376. facilities are intended to aid in testing, validation, and debugging of
  10377. the Surface Aggregator communication layer.
  10378. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  10379. Reviewed-by: Hans de Goede <hdegoede@redhat.com>
  10380. Acked-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
  10381. Link: https://lore.kernel.org/r/20201221183959.1186143-6-luzmaximilian@gmail.com
  10382. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  10383. Patchset: surface-sam
  10384. ---
  10385. drivers/platform/surface/aggregator/Kconfig | 14 +
  10386. .../surface/aggregator/ssh_packet_layer.c | 296 +++++++++++++++++-
  10387. .../surface/aggregator/ssh_request_layer.c | 35 +++
  10388. drivers/platform/surface/aggregator/trace.h | 31 ++
  10389. 4 files changed, 375 insertions(+), 1 deletion(-)
  10390. diff --git a/drivers/platform/surface/aggregator/Kconfig b/drivers/platform/surface/aggregator/Kconfig
  10391. index e9f4ad96e40a..e417bac67088 100644
  10392. --- a/drivers/platform/surface/aggregator/Kconfig
  10393. +++ b/drivers/platform/surface/aggregator/Kconfig
  10394. @@ -40,3 +40,17 @@ menuconfig SURFACE_AGGREGATOR
  10395. Choose m if you want to build the SAM subsystem core and SSH driver as
  10396. module, y if you want to build it into the kernel and n if you don't
  10397. want it at all.
  10398. +
  10399. +config SURFACE_AGGREGATOR_ERROR_INJECTION
  10400. + bool "Surface System Aggregator Module Error Injection Capabilities"
  10401. + depends on SURFACE_AGGREGATOR
  10402. + depends on FUNCTION_ERROR_INJECTION
  10403. + help
  10404. + Provides error-injection capabilities for the Surface System
  10405. + Aggregator Module subsystem and Surface Serial Hub driver.
  10406. +
  10407. + Specifically, exports error injection hooks to be used with the
  10408. + kernel's function error injection capabilities to simulate underlying
  10409. + transport and communication problems, such as invalid data sent to or
  10410. + received from the EC, dropped data, and communication timeouts.
  10411. + Intended for development and debugging.
  10412. diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c
  10413. index c4f082e57372..74f0faaa2b27 100644
  10414. --- a/drivers/platform/surface/aggregator/ssh_packet_layer.c
  10415. +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c
  10416. @@ -7,6 +7,7 @@
  10417. #include <asm/unaligned.h>
  10418. #include <linux/atomic.h>
  10419. +#include <linux/error-injection.h>
  10420. #include <linux/jiffies.h>
  10421. #include <linux/kfifo.h>
  10422. #include <linux/kref.h>
  10423. @@ -226,6 +227,286 @@
  10424. */
  10425. #define SSH_PTL_RX_FIFO_LEN 4096
  10426. +#ifdef CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION
  10427. +
  10428. +/**
  10429. + * ssh_ptl_should_drop_ack_packet() - Error injection hook to drop ACK packets.
  10430. + *
  10431. + * Useful to test detection and handling of automated re-transmits by the EC.
  10432. + * Specifically of packets that the EC considers not-ACKed but the driver
  10433. + * already considers ACKed (due to dropped ACK). In this case, the EC
  10434. + * re-transmits the packet-to-be-ACKed and the driver should detect it as
  10435. + * duplicate/already handled. Note that the driver should still send an ACK
  10436. + * for the re-transmitted packet.
  10437. + */
  10438. +static noinline bool ssh_ptl_should_drop_ack_packet(void)
  10439. +{
  10440. + return false;
  10441. +}
  10442. +ALLOW_ERROR_INJECTION(ssh_ptl_should_drop_ack_packet, TRUE);
  10443. +
  10444. +/**
  10445. + * ssh_ptl_should_drop_nak_packet() - Error injection hook to drop NAK packets.
  10446. + *
  10447. + * Useful to test/force automated (timeout-based) re-transmit by the EC.
  10448. + * Specifically, packets that have not reached the driver completely/with valid
  10449. + * checksums. Only useful in combination with receival of (injected) bad data.
  10450. + */
  10451. +static noinline bool ssh_ptl_should_drop_nak_packet(void)
  10452. +{
  10453. + return false;
  10454. +}
  10455. +ALLOW_ERROR_INJECTION(ssh_ptl_should_drop_nak_packet, TRUE);
  10456. +
  10457. +/**
  10458. + * ssh_ptl_should_drop_dsq_packet() - Error injection hook to drop sequenced
  10459. + * data packet.
  10460. + *
  10461. + * Useful to test re-transmit timeout of the driver. If the data packet has not
  10462. + * been ACKed after a certain time, the driver should re-transmit the packet up
  10463. + * to limited number of times defined in SSH_PTL_MAX_PACKET_TRIES.
  10464. + */
  10465. +static noinline bool ssh_ptl_should_drop_dsq_packet(void)
  10466. +{
  10467. + return false;
  10468. +}
  10469. +ALLOW_ERROR_INJECTION(ssh_ptl_should_drop_dsq_packet, TRUE);
  10470. +
  10471. +/**
  10472. + * ssh_ptl_should_fail_write() - Error injection hook to make
  10473. + * serdev_device_write() fail.
  10474. + *
  10475. + * Hook to simulate errors in serdev_device_write when transmitting packets.
  10476. + */
  10477. +static noinline int ssh_ptl_should_fail_write(void)
  10478. +{
  10479. + return 0;
  10480. +}
  10481. +ALLOW_ERROR_INJECTION(ssh_ptl_should_fail_write, ERRNO);
  10482. +
  10483. +/**
  10484. + * ssh_ptl_should_corrupt_tx_data() - Error injection hook to simulate invalid
  10485. + * data being sent to the EC.
  10486. + *
  10487. + * Hook to simulate corrupt/invalid data being sent from host (driver) to EC.
  10488. + * Causes the packet data to be actively corrupted by overwriting it with
  10489. + * pre-defined values, such that it becomes invalid, causing the EC to respond
  10490. + * with a NAK packet. Useful to test handling of NAK packets received by the
  10491. + * driver.
  10492. + */
  10493. +static noinline bool ssh_ptl_should_corrupt_tx_data(void)
  10494. +{
  10495. + return false;
  10496. +}
  10497. +ALLOW_ERROR_INJECTION(ssh_ptl_should_corrupt_tx_data, TRUE);
  10498. +
  10499. +/**
  10500. + * ssh_ptl_should_corrupt_rx_syn() - Error injection hook to simulate invalid
  10501. + * data being sent by the EC.
  10502. + *
  10503. + * Hook to simulate invalid SYN bytes, i.e. an invalid start of messages and
  10504. + * test handling thereof in the driver.
  10505. + */
  10506. +static noinline bool ssh_ptl_should_corrupt_rx_syn(void)
  10507. +{
  10508. + return false;
  10509. +}
  10510. +ALLOW_ERROR_INJECTION(ssh_ptl_should_corrupt_rx_syn, TRUE);
  10511. +
  10512. +/**
  10513. + * ssh_ptl_should_corrupt_rx_data() - Error injection hook to simulate invalid
  10514. + * data being sent by the EC.
  10515. + *
  10516. + * Hook to simulate invalid data/checksum of the message frame and test handling
  10517. + * thereof in the driver.
  10518. + */
  10519. +static noinline bool ssh_ptl_should_corrupt_rx_data(void)
  10520. +{
  10521. + return false;
  10522. +}
  10523. +ALLOW_ERROR_INJECTION(ssh_ptl_should_corrupt_rx_data, TRUE);
  10524. +
  10525. +static bool __ssh_ptl_should_drop_ack_packet(struct ssh_packet *packet)
  10526. +{
  10527. + if (likely(!ssh_ptl_should_drop_ack_packet()))
  10528. + return false;
  10529. +
  10530. + trace_ssam_ei_tx_drop_ack_packet(packet);
  10531. + ptl_info(packet->ptl, "packet error injection: dropping ACK packet %p\n",
  10532. + packet);
  10533. +
  10534. + return true;
  10535. +}
  10536. +
  10537. +static bool __ssh_ptl_should_drop_nak_packet(struct ssh_packet *packet)
  10538. +{
  10539. + if (likely(!ssh_ptl_should_drop_nak_packet()))
  10540. + return false;
  10541. +
  10542. + trace_ssam_ei_tx_drop_nak_packet(packet);
  10543. + ptl_info(packet->ptl, "packet error injection: dropping NAK packet %p\n",
  10544. + packet);
  10545. +
  10546. + return true;
  10547. +}
  10548. +
  10549. +static bool __ssh_ptl_should_drop_dsq_packet(struct ssh_packet *packet)
  10550. +{
  10551. + if (likely(!ssh_ptl_should_drop_dsq_packet()))
  10552. + return false;
  10553. +
  10554. + trace_ssam_ei_tx_drop_dsq_packet(packet);
  10555. + ptl_info(packet->ptl,
  10556. + "packet error injection: dropping sequenced data packet %p\n",
  10557. + packet);
  10558. +
  10559. + return true;
  10560. +}
  10561. +
  10562. +static bool ssh_ptl_should_drop_packet(struct ssh_packet *packet)
  10563. +{
  10564. + /* Ignore packets that don't carry any data (i.e. flush). */
  10565. + if (!packet->data.ptr || !packet->data.len)
  10566. + return false;
  10567. +
  10568. + switch (packet->data.ptr[SSH_MSGOFFSET_FRAME(type)]) {
  10569. + case SSH_FRAME_TYPE_ACK:
  10570. + return __ssh_ptl_should_drop_ack_packet(packet);
  10571. +
  10572. + case SSH_FRAME_TYPE_NAK:
  10573. + return __ssh_ptl_should_drop_nak_packet(packet);
  10574. +
  10575. + case SSH_FRAME_TYPE_DATA_SEQ:
  10576. + return __ssh_ptl_should_drop_dsq_packet(packet);
  10577. +
  10578. + default:
  10579. + return false;
  10580. + }
  10581. +}
  10582. +
  10583. +static int ssh_ptl_write_buf(struct ssh_ptl *ptl, struct ssh_packet *packet,
  10584. + const unsigned char *buf, size_t count)
  10585. +{
  10586. + int status;
  10587. +
  10588. + status = ssh_ptl_should_fail_write();
  10589. + if (unlikely(status)) {
  10590. + trace_ssam_ei_tx_fail_write(packet, status);
  10591. + ptl_info(packet->ptl,
  10592. + "packet error injection: simulating transmit error %d, packet %p\n",
  10593. + status, packet);
  10594. +
  10595. + return status;
  10596. + }
  10597. +
  10598. + return serdev_device_write_buf(ptl->serdev, buf, count);
  10599. +}
  10600. +
  10601. +static void ssh_ptl_tx_inject_invalid_data(struct ssh_packet *packet)
  10602. +{
  10603. + /* Ignore packets that don't carry any data (i.e. flush). */
  10604. + if (!packet->data.ptr || !packet->data.len)
  10605. + return;
  10606. +
  10607. + /* Only allow sequenced data packets to be modified. */
  10608. + if (packet->data.ptr[SSH_MSGOFFSET_FRAME(type)] != SSH_FRAME_TYPE_DATA_SEQ)
  10609. + return;
  10610. +
  10611. + if (likely(!ssh_ptl_should_corrupt_tx_data()))
  10612. + return;
  10613. +
  10614. + trace_ssam_ei_tx_corrupt_data(packet);
  10615. + ptl_info(packet->ptl,
  10616. + "packet error injection: simulating invalid transmit data on packet %p\n",
  10617. + packet);
  10618. +
  10619. + /*
  10620. + * NB: The value 0xb3 has been chosen more or less randomly so that it
  10621. + * doesn't have any (major) overlap with the SYN bytes (aa 55) and is
  10622. + * non-trivial (i.e. non-zero, non-0xff).
  10623. + */
  10624. + memset(packet->data.ptr, 0xb3, packet->data.len);
  10625. +}
  10626. +
  10627. +static void ssh_ptl_rx_inject_invalid_syn(struct ssh_ptl *ptl,
  10628. + struct ssam_span *data)
  10629. +{
  10630. + struct ssam_span frame;
  10631. +
  10632. + /* Check if there actually is something to corrupt. */
  10633. + if (!sshp_find_syn(data, &frame))
  10634. + return;
  10635. +
  10636. + if (likely(!ssh_ptl_should_corrupt_rx_syn()))
  10637. + return;
  10638. +
  10639. + trace_ssam_ei_rx_corrupt_syn(data->len);
  10640. +
  10641. + data->ptr[1] = 0xb3; /* Set second byte of SYN to "random" value. */
  10642. +}
  10643. +
  10644. +static void ssh_ptl_rx_inject_invalid_data(struct ssh_ptl *ptl,
  10645. + struct ssam_span *frame)
  10646. +{
  10647. + size_t payload_len, message_len;
  10648. + struct ssh_frame *sshf;
  10649. +
  10650. + /* Ignore incomplete messages, will get handled once it's complete. */
  10651. + if (frame->len < SSH_MESSAGE_LENGTH(0))
  10652. + return;
  10653. +
  10654. + /* Ignore incomplete messages, part 2. */
  10655. + payload_len = get_unaligned_le16(&frame->ptr[SSH_MSGOFFSET_FRAME(len)]);
  10656. + message_len = SSH_MESSAGE_LENGTH(payload_len);
  10657. + if (frame->len < message_len)
  10658. + return;
  10659. +
  10660. + if (likely(!ssh_ptl_should_corrupt_rx_data()))
  10661. + return;
  10662. +
  10663. + sshf = (struct ssh_frame *)&frame->ptr[SSH_MSGOFFSET_FRAME(type)];
  10664. + trace_ssam_ei_rx_corrupt_data(sshf);
  10665. +
  10666. + /*
  10667. + * Flip bits in first byte of payload checksum. This is basically
  10668. + * equivalent to a payload/frame data error without us having to worry
  10669. + * about (the, arguably pretty small, probability of) accidental
  10670. + * checksum collisions.
  10671. + */
  10672. + frame->ptr[frame->len - 2] = ~frame->ptr[frame->len - 2];
  10673. +}
  10674. +
  10675. +#else /* CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION */
  10676. +
  10677. +static inline bool ssh_ptl_should_drop_packet(struct ssh_packet *packet)
  10678. +{
  10679. + return false;
  10680. +}
  10681. +
  10682. +static inline int ssh_ptl_write_buf(struct ssh_ptl *ptl,
  10683. + struct ssh_packet *packet,
  10684. + const unsigned char *buf,
  10685. + size_t count)
  10686. +{
  10687. + return serdev_device_write_buf(ptl->serdev, buf, count);
  10688. +}
  10689. +
  10690. +static inline void ssh_ptl_tx_inject_invalid_data(struct ssh_packet *packet)
  10691. +{
  10692. +}
  10693. +
  10694. +static inline void ssh_ptl_rx_inject_invalid_syn(struct ssh_ptl *ptl,
  10695. + struct ssam_span *data)
  10696. +{
  10697. +}
  10698. +
  10699. +static inline void ssh_ptl_rx_inject_invalid_data(struct ssh_ptl *ptl,
  10700. + struct ssam_span *frame)
  10701. +{
  10702. +}
  10703. +
  10704. +#endif /* CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION */
  10705. +
  10706. static void __ssh_ptl_packet_release(struct kref *kref)
  10707. {
  10708. struct ssh_packet *p = container_of(kref, struct ssh_packet, refcnt);
  10709. @@ -776,6 +1057,13 @@ static int ssh_ptl_tx_packet(struct ssh_ptl *ptl, struct ssh_packet *packet)
  10710. if (unlikely(!packet->data.ptr))
  10711. return 0;
  10712. + /* Error injection: drop packet to simulate transmission problem. */
  10713. + if (ssh_ptl_should_drop_packet(packet))
  10714. + return 0;
  10715. +
  10716. + /* Error injection: simulate invalid packet data. */
  10717. + ssh_ptl_tx_inject_invalid_data(packet);
  10718. +
  10719. ptl_dbg(ptl, "tx: sending data (length: %zu)\n", packet->data.len);
  10720. print_hex_dump_debug("tx: ", DUMP_PREFIX_OFFSET, 16, 1,
  10721. packet->data.ptr, packet->data.len, false);
  10722. @@ -787,7 +1075,7 @@ static int ssh_ptl_tx_packet(struct ssh_ptl *ptl, struct ssh_packet *packet)
  10723. buf = packet->data.ptr + offset;
  10724. len = packet->data.len - offset;
  10725. - status = serdev_device_write_buf(ptl->serdev, buf, len);
  10726. + status = ssh_ptl_write_buf(ptl, packet, buf, len);
  10727. if (status < 0)
  10728. return status;
  10729. @@ -1400,6 +1688,9 @@ static size_t ssh_ptl_rx_eval(struct ssh_ptl *ptl, struct ssam_span *source)
  10730. bool syn_found;
  10731. int status;
  10732. + /* Error injection: Modify data to simulate corrupt SYN bytes. */
  10733. + ssh_ptl_rx_inject_invalid_syn(ptl, source);
  10734. +
  10735. /* Find SYN. */
  10736. syn_found = sshp_find_syn(source, &aligned);
  10737. @@ -1430,6 +1721,9 @@ static size_t ssh_ptl_rx_eval(struct ssh_ptl *ptl, struct ssam_span *source)
  10738. if (unlikely(!syn_found))
  10739. return aligned.ptr - source->ptr;
  10740. + /* Error injection: Modify data to simulate corruption. */
  10741. + ssh_ptl_rx_inject_invalid_data(ptl, &aligned);
  10742. +
  10743. /* Parse and validate frame. */
  10744. status = sshp_parse_frame(&ptl->serdev->dev, &aligned, &frame, &payload,
  10745. SSH_PTL_RX_BUF_LEN);
  10746. diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c
  10747. index b649d71840fd..bb1c862411a2 100644
  10748. --- a/drivers/platform/surface/aggregator/ssh_request_layer.c
  10749. +++ b/drivers/platform/surface/aggregator/ssh_request_layer.c
  10750. @@ -8,6 +8,7 @@
  10751. #include <asm/unaligned.h>
  10752. #include <linux/atomic.h>
  10753. #include <linux/completion.h>
  10754. +#include <linux/error-injection.h>
  10755. #include <linux/ktime.h>
  10756. #include <linux/limits.h>
  10757. #include <linux/list.h>
  10758. @@ -58,6 +59,30 @@
  10759. */
  10760. #define SSH_RTL_TX_BATCH 10
  10761. +#ifdef CONFIG_SURFACE_AGGREGATOR_ERROR_INJECTION
  10762. +
  10763. +/**
  10764. + * ssh_rtl_should_drop_response() - Error injection hook to drop request
  10765. + * responses.
  10766. + *
  10767. + * Useful to cause request transmission timeouts in the driver by dropping the
  10768. + * response to a request.
  10769. + */
  10770. +static noinline bool ssh_rtl_should_drop_response(void)
  10771. +{
  10772. + return false;
  10773. +}
  10774. +ALLOW_ERROR_INJECTION(ssh_rtl_should_drop_response, TRUE);
  10775. +
  10776. +#else
  10777. +
  10778. +static inline bool ssh_rtl_should_drop_response(void)
  10779. +{
  10780. + return false;
  10781. +}
  10782. +
  10783. +#endif
  10784. +
  10785. static u16 ssh_request_get_rqid(struct ssh_request *rqst)
  10786. {
  10787. return get_unaligned_le16(rqst->packet.data.ptr
  10788. @@ -459,6 +484,16 @@ static void ssh_rtl_complete(struct ssh_rtl *rtl,
  10789. if (unlikely(ssh_request_get_rqid(p) != rqid))
  10790. continue;
  10791. + /* Simulate response timeout. */
  10792. + if (ssh_rtl_should_drop_response()) {
  10793. + spin_unlock(&rtl->pending.lock);
  10794. +
  10795. + trace_ssam_ei_rx_drop_response(p);
  10796. + rtl_info(rtl, "request error injection: dropping response for request %p\n",
  10797. + &p->packet);
  10798. + return;
  10799. + }
  10800. +
  10801. /*
  10802. * Mark as "response received" and "locked" as we're going to
  10803. * complete it.
  10804. diff --git a/drivers/platform/surface/aggregator/trace.h b/drivers/platform/surface/aggregator/trace.h
  10805. index dcca8007d876..eb332bb53ae4 100644
  10806. --- a/drivers/platform/surface/aggregator/trace.h
  10807. +++ b/drivers/platform/surface/aggregator/trace.h
  10808. @@ -565,6 +565,28 @@ DECLARE_EVENT_CLASS(ssam_pending_class,
  10809. TP_ARGS(pending) \
  10810. )
  10811. +DECLARE_EVENT_CLASS(ssam_data_class,
  10812. + TP_PROTO(size_t length),
  10813. +
  10814. + TP_ARGS(length),
  10815. +
  10816. + TP_STRUCT__entry(
  10817. + __field(size_t, length)
  10818. + ),
  10819. +
  10820. + TP_fast_assign(
  10821. + __entry->length = length;
  10822. + ),
  10823. +
  10824. + TP_printk("length=%zu", __entry->length)
  10825. +);
  10826. +
  10827. +#define DEFINE_SSAM_DATA_EVENT(name) \
  10828. + DEFINE_EVENT(ssam_data_class, ssam_##name, \
  10829. + TP_PROTO(size_t length), \
  10830. + TP_ARGS(length) \
  10831. + )
  10832. +
  10833. DEFINE_SSAM_FRAME_EVENT(rx_frame_received);
  10834. DEFINE_SSAM_COMMAND_EVENT(rx_response_received);
  10835. DEFINE_SSAM_COMMAND_EVENT(rx_event_received);
  10836. @@ -583,6 +605,15 @@ DEFINE_SSAM_REQUEST_EVENT(request_cancel);
  10837. DEFINE_SSAM_REQUEST_STATUS_EVENT(request_complete);
  10838. DEFINE_SSAM_PENDING_EVENT(rtl_timeout_reap);
  10839. +DEFINE_SSAM_PACKET_EVENT(ei_tx_drop_ack_packet);
  10840. +DEFINE_SSAM_PACKET_EVENT(ei_tx_drop_nak_packet);
  10841. +DEFINE_SSAM_PACKET_EVENT(ei_tx_drop_dsq_packet);
  10842. +DEFINE_SSAM_PACKET_STATUS_EVENT(ei_tx_fail_write);
  10843. +DEFINE_SSAM_PACKET_EVENT(ei_tx_corrupt_data);
  10844. +DEFINE_SSAM_DATA_EVENT(ei_rx_corrupt_syn);
  10845. +DEFINE_SSAM_FRAME_EVENT(ei_rx_corrupt_data);
  10846. +DEFINE_SSAM_REQUEST_EVENT(ei_rx_drop_response);
  10847. +
  10848. DEFINE_SSAM_ALLOC_EVENT(ctrl_packet_alloc);
  10849. DEFINE_SSAM_FREE_EVENT(ctrl_packet_free);
  10850. --
  10851. 2.31.0
  10852. From b13806dafeff14be6cdaad9736d7c9327fe822ac Mon Sep 17 00:00:00 2001
  10853. From: Maximilian Luz <luzmaximilian@gmail.com>
  10854. Date: Mon, 21 Dec 2020 19:39:56 +0100
  10855. Subject: [PATCH] platform/surface: aggregator: Add dedicated bus and device
  10856. type
  10857. The Surface Aggregator EC provides varying functionality, depending on
  10858. the Surface device. To manage this functionality, we use dedicated
  10859. client devices for each subsystem or virtual device of the EC. While
  10860. some of these clients are described as standard devices in ACPI and the
  10861. corresponding client drivers can be implemented as platform drivers in
  10862. the kernel (making use of the controller API already present), many
  10863. devices, especially on newer Surface models, cannot be found there.
  10864. To simplify management of these devices, we introduce a new bus and
  10865. client device type for the Surface Aggregator subsystem. The new device
  10866. type takes care of managing the controller reference, essentially
  10867. guaranteeing its validity for as long as the client device exists, thus
  10868. alleviating the need to manually establish device links for that purpose
  10869. in the client driver (as has to be done with the platform devices).
  10870. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  10871. Reviewed-by: Hans de Goede <hdegoede@redhat.com>
  10872. Link: https://lore.kernel.org/r/20201221183959.1186143-7-luzmaximilian@gmail.com
  10873. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  10874. Patchset: surface-sam
  10875. ---
  10876. drivers/platform/surface/aggregator/Kconfig | 12 +
  10877. drivers/platform/surface/aggregator/Makefile | 4 +
  10878. drivers/platform/surface/aggregator/bus.c | 415 ++++++++++++++++++
  10879. drivers/platform/surface/aggregator/bus.h | 27 ++
  10880. drivers/platform/surface/aggregator/core.c | 12 +
  10881. include/linux/mod_devicetable.h | 18 +
  10882. include/linux/surface_aggregator/device.h | 423 +++++++++++++++++++
  10883. scripts/mod/devicetable-offsets.c | 8 +
  10884. scripts/mod/file2alias.c | 23 +
  10885. 9 files changed, 942 insertions(+)
  10886. create mode 100644 drivers/platform/surface/aggregator/bus.c
  10887. create mode 100644 drivers/platform/surface/aggregator/bus.h
  10888. create mode 100644 include/linux/surface_aggregator/device.h
  10889. diff --git a/drivers/platform/surface/aggregator/Kconfig b/drivers/platform/surface/aggregator/Kconfig
  10890. index e417bac67088..3aaeea9f0433 100644
  10891. --- a/drivers/platform/surface/aggregator/Kconfig
  10892. +++ b/drivers/platform/surface/aggregator/Kconfig
  10893. @@ -41,6 +41,18 @@ menuconfig SURFACE_AGGREGATOR
  10894. module, y if you want to build it into the kernel and n if you don't
  10895. want it at all.
  10896. +config SURFACE_AGGREGATOR_BUS
  10897. + bool "Surface System Aggregator Module Bus"
  10898. + depends on SURFACE_AGGREGATOR
  10899. + default y
  10900. + help
  10901. + Expands the Surface System Aggregator Module (SSAM) core driver by
  10902. + providing a dedicated bus and client-device type.
  10903. +
  10904. + This bus and device type are intended to provide and simplify support
  10905. + for non-platform and non-ACPI SSAM devices, i.e. SSAM devices that are
  10906. + not auto-detectable via the conventional means (e.g. ACPI).
  10907. +
  10908. config SURFACE_AGGREGATOR_ERROR_INJECTION
  10909. bool "Surface System Aggregator Module Error Injection Capabilities"
  10910. depends on SURFACE_AGGREGATOR
  10911. diff --git a/drivers/platform/surface/aggregator/Makefile b/drivers/platform/surface/aggregator/Makefile
  10912. index b8b24c8ec310..c112e2c7112b 100644
  10913. --- a/drivers/platform/surface/aggregator/Makefile
  10914. +++ b/drivers/platform/surface/aggregator/Makefile
  10915. @@ -11,3 +11,7 @@ surface_aggregator-objs += ssh_parser.o
  10916. surface_aggregator-objs += ssh_packet_layer.o
  10917. surface_aggregator-objs += ssh_request_layer.o
  10918. surface_aggregator-objs += controller.o
  10919. +
  10920. +ifeq ($(CONFIG_SURFACE_AGGREGATOR_BUS),y)
  10921. +surface_aggregator-objs += bus.o
  10922. +endif
  10923. diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c
  10924. new file mode 100644
  10925. index 000000000000..a9b660af0917
  10926. --- /dev/null
  10927. +++ b/drivers/platform/surface/aggregator/bus.c
  10928. @@ -0,0 +1,415 @@
  10929. +// SPDX-License-Identifier: GPL-2.0+
  10930. +/*
  10931. + * Surface System Aggregator Module bus and device integration.
  10932. + *
  10933. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  10934. + */
  10935. +
  10936. +#include <linux/device.h>
  10937. +#include <linux/slab.h>
  10938. +
  10939. +#include <linux/surface_aggregator/controller.h>
  10940. +#include <linux/surface_aggregator/device.h>
  10941. +
  10942. +#include "bus.h"
  10943. +#include "controller.h"
  10944. +
  10945. +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
  10946. + char *buf)
  10947. +{
  10948. + struct ssam_device *sdev = to_ssam_device(dev);
  10949. +
  10950. + return sysfs_emit(buf, "ssam:d%02Xc%02Xt%02Xi%02Xf%02X\n",
  10951. + sdev->uid.domain, sdev->uid.category, sdev->uid.target,
  10952. + sdev->uid.instance, sdev->uid.function);
  10953. +}
  10954. +static DEVICE_ATTR_RO(modalias);
  10955. +
  10956. +static struct attribute *ssam_device_attrs[] = {
  10957. + &dev_attr_modalias.attr,
  10958. + NULL,
  10959. +};
  10960. +ATTRIBUTE_GROUPS(ssam_device);
  10961. +
  10962. +static int ssam_device_uevent(struct device *dev, struct kobj_uevent_env *env)
  10963. +{
  10964. + struct ssam_device *sdev = to_ssam_device(dev);
  10965. +
  10966. + return add_uevent_var(env, "MODALIAS=ssam:d%02Xc%02Xt%02Xi%02Xf%02X",
  10967. + sdev->uid.domain, sdev->uid.category,
  10968. + sdev->uid.target, sdev->uid.instance,
  10969. + sdev->uid.function);
  10970. +}
  10971. +
  10972. +static void ssam_device_release(struct device *dev)
  10973. +{
  10974. + struct ssam_device *sdev = to_ssam_device(dev);
  10975. +
  10976. + ssam_controller_put(sdev->ctrl);
  10977. + kfree(sdev);
  10978. +}
  10979. +
  10980. +const struct device_type ssam_device_type = {
  10981. + .name = "surface_aggregator_device",
  10982. + .groups = ssam_device_groups,
  10983. + .uevent = ssam_device_uevent,
  10984. + .release = ssam_device_release,
  10985. +};
  10986. +EXPORT_SYMBOL_GPL(ssam_device_type);
  10987. +
  10988. +/**
  10989. + * ssam_device_alloc() - Allocate and initialize a SSAM client device.
  10990. + * @ctrl: The controller under which the device should be added.
  10991. + * @uid: The UID of the device to be added.
  10992. + *
  10993. + * Allocates and initializes a new client device. The parent of the device
  10994. + * will be set to the controller device and the name will be set based on the
  10995. + * UID. Note that the device still has to be added via ssam_device_add().
  10996. + * Refer to that function for more details.
  10997. + *
  10998. + * Return: Returns the newly allocated and initialized SSAM client device, or
  10999. + * %NULL if it could not be allocated.
  11000. + */
  11001. +struct ssam_device *ssam_device_alloc(struct ssam_controller *ctrl,
  11002. + struct ssam_device_uid uid)
  11003. +{
  11004. + struct ssam_device *sdev;
  11005. +
  11006. + sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
  11007. + if (!sdev)
  11008. + return NULL;
  11009. +
  11010. + device_initialize(&sdev->dev);
  11011. + sdev->dev.bus = &ssam_bus_type;
  11012. + sdev->dev.type = &ssam_device_type;
  11013. + sdev->dev.parent = ssam_controller_device(ctrl);
  11014. + sdev->ctrl = ssam_controller_get(ctrl);
  11015. + sdev->uid = uid;
  11016. +
  11017. + dev_set_name(&sdev->dev, "%02x:%02x:%02x:%02x:%02x",
  11018. + sdev->uid.domain, sdev->uid.category, sdev->uid.target,
  11019. + sdev->uid.instance, sdev->uid.function);
  11020. +
  11021. + return sdev;
  11022. +}
  11023. +EXPORT_SYMBOL_GPL(ssam_device_alloc);
  11024. +
  11025. +/**
  11026. + * ssam_device_add() - Add a SSAM client device.
  11027. + * @sdev: The SSAM client device to be added.
  11028. + *
  11029. + * Added client devices must be guaranteed to always have a valid and active
  11030. + * controller. Thus, this function will fail with %-ENODEV if the controller
  11031. + * of the device has not been initialized yet, has been suspended, or has been
  11032. + * shut down.
  11033. + *
  11034. + * The caller of this function should ensure that the corresponding call to
  11035. + * ssam_device_remove() is issued before the controller is shut down. If the
  11036. + * added device is a direct child of the controller device (default), it will
  11037. + * be automatically removed when the controller is shut down.
  11038. + *
  11039. + * By default, the controller device will become the parent of the newly
  11040. + * created client device. The parent may be changed before ssam_device_add is
  11041. + * called, but care must be taken that a) the correct suspend/resume ordering
  11042. + * is guaranteed and b) the client device does not outlive the controller,
  11043. + * i.e. that the device is removed before the controller is being shut down.
  11044. + * In case these guarantees have to be manually enforced, please refer to the
  11045. + * ssam_client_link() and ssam_client_bind() functions, which are intended to
  11046. + * set up device-links for this purpose.
  11047. + *
  11048. + * Return: Returns zero on success, a negative error code on failure.
  11049. + */
  11050. +int ssam_device_add(struct ssam_device *sdev)
  11051. +{
  11052. + int status;
  11053. +
  11054. + /*
  11055. + * Ensure that we can only add new devices to a controller if it has
  11056. + * been started and is not going away soon. This works in combination
  11057. + * with ssam_controller_remove_clients to ensure driver presence for the
  11058. + * controller device, i.e. it ensures that the controller (sdev->ctrl)
  11059. + * is always valid and can be used for requests as long as the client
  11060. + * device we add here is registered as child under it. This essentially
  11061. + * guarantees that the client driver can always expect the preconditions
  11062. + * for functions like ssam_request_sync (controller has to be started
  11063. + * and is not suspended) to hold and thus does not have to check for
  11064. + * them.
  11065. + *
  11066. + * Note that for this to work, the controller has to be a parent device.
  11067. + * If it is not a direct parent, care has to be taken that the device is
  11068. + * removed via ssam_device_remove(), as device_unregister does not
  11069. + * remove child devices recursively.
  11070. + */
  11071. + ssam_controller_statelock(sdev->ctrl);
  11072. +
  11073. + if (sdev->ctrl->state != SSAM_CONTROLLER_STARTED) {
  11074. + ssam_controller_stateunlock(sdev->ctrl);
  11075. + return -ENODEV;
  11076. + }
  11077. +
  11078. + status = device_add(&sdev->dev);
  11079. +
  11080. + ssam_controller_stateunlock(sdev->ctrl);
  11081. + return status;
  11082. +}
  11083. +EXPORT_SYMBOL_GPL(ssam_device_add);
  11084. +
  11085. +/**
  11086. + * ssam_device_remove() - Remove a SSAM client device.
  11087. + * @sdev: The device to remove.
  11088. + *
  11089. + * Removes and unregisters the provided SSAM client device.
  11090. + */
  11091. +void ssam_device_remove(struct ssam_device *sdev)
  11092. +{
  11093. + device_unregister(&sdev->dev);
  11094. +}
  11095. +EXPORT_SYMBOL_GPL(ssam_device_remove);
  11096. +
  11097. +/**
  11098. + * ssam_device_id_compatible() - Check if a device ID matches a UID.
  11099. + * @id: The device ID as potential match.
  11100. + * @uid: The device UID matching against.
  11101. + *
  11102. + * Check if the given ID is a match for the given UID, i.e. if a device with
  11103. + * the provided UID is compatible to the given ID following the match rules
  11104. + * described in its &ssam_device_id.match_flags member.
  11105. + *
  11106. + * Return: Returns %true if the given UID is compatible to the match rule
  11107. + * described by the given ID, %false otherwise.
  11108. + */
  11109. +static bool ssam_device_id_compatible(const struct ssam_device_id *id,
  11110. + struct ssam_device_uid uid)
  11111. +{
  11112. + if (id->domain != uid.domain || id->category != uid.category)
  11113. + return false;
  11114. +
  11115. + if ((id->match_flags & SSAM_MATCH_TARGET) && id->target != uid.target)
  11116. + return false;
  11117. +
  11118. + if ((id->match_flags & SSAM_MATCH_INSTANCE) && id->instance != uid.instance)
  11119. + return false;
  11120. +
  11121. + if ((id->match_flags & SSAM_MATCH_FUNCTION) && id->function != uid.function)
  11122. + return false;
  11123. +
  11124. + return true;
  11125. +}
  11126. +
  11127. +/**
  11128. + * ssam_device_id_is_null() - Check if a device ID is null.
  11129. + * @id: The device ID to check.
  11130. + *
  11131. + * Check if a given device ID is null, i.e. all zeros. Used to check for the
  11132. + * end of ``MODULE_DEVICE_TABLE(ssam, ...)`` or similar lists.
  11133. + *
  11134. + * Return: Returns %true if the given ID represents a null ID, %false
  11135. + * otherwise.
  11136. + */
  11137. +static bool ssam_device_id_is_null(const struct ssam_device_id *id)
  11138. +{
  11139. + return id->match_flags == 0 &&
  11140. + id->domain == 0 &&
  11141. + id->category == 0 &&
  11142. + id->target == 0 &&
  11143. + id->instance == 0 &&
  11144. + id->function == 0 &&
  11145. + id->driver_data == 0;
  11146. +}
  11147. +
  11148. +/**
  11149. + * ssam_device_id_match() - Find the matching ID table entry for the given UID.
  11150. + * @table: The table to search in.
  11151. + * @uid: The UID to matched against the individual table entries.
  11152. + *
  11153. + * Find the first match for the provided device UID in the provided ID table
  11154. + * and return it. Returns %NULL if no match could be found.
  11155. + */
  11156. +const struct ssam_device_id *ssam_device_id_match(const struct ssam_device_id *table,
  11157. + const struct ssam_device_uid uid)
  11158. +{
  11159. + const struct ssam_device_id *id;
  11160. +
  11161. + for (id = table; !ssam_device_id_is_null(id); ++id)
  11162. + if (ssam_device_id_compatible(id, uid))
  11163. + return id;
  11164. +
  11165. + return NULL;
  11166. +}
  11167. +EXPORT_SYMBOL_GPL(ssam_device_id_match);
  11168. +
  11169. +/**
  11170. + * ssam_device_get_match() - Find and return the ID matching the device in the
  11171. + * ID table of the bound driver.
  11172. + * @dev: The device for which to get the matching ID table entry.
  11173. + *
  11174. + * Find the fist match for the UID of the device in the ID table of the
  11175. + * currently bound driver and return it. Returns %NULL if the device does not
  11176. + * have a driver bound to it, the driver does not have match_table (i.e. it is
  11177. + * %NULL), or there is no match in the driver's match_table.
  11178. + *
  11179. + * This function essentially calls ssam_device_id_match() with the ID table of
  11180. + * the bound device driver and the UID of the device.
  11181. + *
  11182. + * Return: Returns the first match for the UID of the device in the device
  11183. + * driver's match table, or %NULL if no such match could be found.
  11184. + */
  11185. +const struct ssam_device_id *ssam_device_get_match(const struct ssam_device *dev)
  11186. +{
  11187. + const struct ssam_device_driver *sdrv;
  11188. +
  11189. + sdrv = to_ssam_device_driver(dev->dev.driver);
  11190. + if (!sdrv)
  11191. + return NULL;
  11192. +
  11193. + if (!sdrv->match_table)
  11194. + return NULL;
  11195. +
  11196. + return ssam_device_id_match(sdrv->match_table, dev->uid);
  11197. +}
  11198. +EXPORT_SYMBOL_GPL(ssam_device_get_match);
  11199. +
  11200. +/**
  11201. + * ssam_device_get_match_data() - Find the ID matching the device in the
  11202. + * ID table of the bound driver and return its ``driver_data`` member.
  11203. + * @dev: The device for which to get the match data.
  11204. + *
  11205. + * Find the fist match for the UID of the device in the ID table of the
  11206. + * corresponding driver and return its driver_data. Returns %NULL if the
  11207. + * device does not have a driver bound to it, the driver does not have
  11208. + * match_table (i.e. it is %NULL), there is no match in the driver's
  11209. + * match_table, or the match does not have any driver_data.
  11210. + *
  11211. + * This function essentially calls ssam_device_get_match() and, if any match
  11212. + * could be found, returns its ``struct ssam_device_id.driver_data`` member.
  11213. + *
  11214. + * Return: Returns the driver data associated with the first match for the UID
  11215. + * of the device in the device driver's match table, or %NULL if no such match
  11216. + * could be found.
  11217. + */
  11218. +const void *ssam_device_get_match_data(const struct ssam_device *dev)
  11219. +{
  11220. + const struct ssam_device_id *id;
  11221. +
  11222. + id = ssam_device_get_match(dev);
  11223. + if (!id)
  11224. + return NULL;
  11225. +
  11226. + return (const void *)id->driver_data;
  11227. +}
  11228. +EXPORT_SYMBOL_GPL(ssam_device_get_match_data);
  11229. +
  11230. +static int ssam_bus_match(struct device *dev, struct device_driver *drv)
  11231. +{
  11232. + struct ssam_device_driver *sdrv = to_ssam_device_driver(drv);
  11233. + struct ssam_device *sdev = to_ssam_device(dev);
  11234. +
  11235. + if (!is_ssam_device(dev))
  11236. + return 0;
  11237. +
  11238. + return !!ssam_device_id_match(sdrv->match_table, sdev->uid);
  11239. +}
  11240. +
  11241. +static int ssam_bus_probe(struct device *dev)
  11242. +{
  11243. + return to_ssam_device_driver(dev->driver)
  11244. + ->probe(to_ssam_device(dev));
  11245. +}
  11246. +
  11247. +static int ssam_bus_remove(struct device *dev)
  11248. +{
  11249. + struct ssam_device_driver *sdrv = to_ssam_device_driver(dev->driver);
  11250. +
  11251. + if (sdrv->remove)
  11252. + sdrv->remove(to_ssam_device(dev));
  11253. +
  11254. + return 0;
  11255. +}
  11256. +
  11257. +struct bus_type ssam_bus_type = {
  11258. + .name = "surface_aggregator",
  11259. + .match = ssam_bus_match,
  11260. + .probe = ssam_bus_probe,
  11261. + .remove = ssam_bus_remove,
  11262. +};
  11263. +EXPORT_SYMBOL_GPL(ssam_bus_type);
  11264. +
  11265. +/**
  11266. + * __ssam_device_driver_register() - Register a SSAM client device driver.
  11267. + * @sdrv: The driver to register.
  11268. + * @owner: The module owning the provided driver.
  11269. + *
  11270. + * Please refer to the ssam_device_driver_register() macro for the normal way
  11271. + * to register a driver from inside its owning module.
  11272. + */
  11273. +int __ssam_device_driver_register(struct ssam_device_driver *sdrv,
  11274. + struct module *owner)
  11275. +{
  11276. + sdrv->driver.owner = owner;
  11277. + sdrv->driver.bus = &ssam_bus_type;
  11278. +
  11279. + /* force drivers to async probe so I/O is possible in probe */
  11280. + sdrv->driver.probe_type = PROBE_PREFER_ASYNCHRONOUS;
  11281. +
  11282. + return driver_register(&sdrv->driver);
  11283. +}
  11284. +EXPORT_SYMBOL_GPL(__ssam_device_driver_register);
  11285. +
  11286. +/**
  11287. + * ssam_device_driver_unregister - Unregister a SSAM device driver.
  11288. + * @sdrv: The driver to unregister.
  11289. + */
  11290. +void ssam_device_driver_unregister(struct ssam_device_driver *sdrv)
  11291. +{
  11292. + driver_unregister(&sdrv->driver);
  11293. +}
  11294. +EXPORT_SYMBOL_GPL(ssam_device_driver_unregister);
  11295. +
  11296. +static int ssam_remove_device(struct device *dev, void *_data)
  11297. +{
  11298. + struct ssam_device *sdev = to_ssam_device(dev);
  11299. +
  11300. + if (is_ssam_device(dev))
  11301. + ssam_device_remove(sdev);
  11302. +
  11303. + return 0;
  11304. +}
  11305. +
  11306. +/**
  11307. + * ssam_controller_remove_clients() - Remove SSAM client devices registered as
  11308. + * direct children under the given controller.
  11309. + * @ctrl: The controller to remove all direct clients for.
  11310. + *
  11311. + * Remove all SSAM client devices registered as direct children under the
  11312. + * given controller. Note that this only accounts for direct children of the
  11313. + * controller device. This does not take care of any client devices where the
  11314. + * parent device has been manually set before calling ssam_device_add. Refer
  11315. + * to ssam_device_add()/ssam_device_remove() for more details on those cases.
  11316. + *
  11317. + * To avoid new devices being added in parallel to this call, the main
  11318. + * controller lock (not statelock) must be held during this (and if
  11319. + * necessary, any subsequent deinitialization) call.
  11320. + */
  11321. +void ssam_controller_remove_clients(struct ssam_controller *ctrl)
  11322. +{
  11323. + struct device *dev;
  11324. +
  11325. + dev = ssam_controller_device(ctrl);
  11326. + device_for_each_child_reverse(dev, NULL, ssam_remove_device);
  11327. +}
  11328. +
  11329. +/**
  11330. + * ssam_bus_register() - Register and set-up the SSAM client device bus.
  11331. + */
  11332. +int ssam_bus_register(void)
  11333. +{
  11334. + return bus_register(&ssam_bus_type);
  11335. +}
  11336. +
  11337. +/**
  11338. + * ssam_bus_unregister() - Unregister the SSAM client device bus.
  11339. + */
  11340. +void ssam_bus_unregister(void)
  11341. +{
  11342. + return bus_unregister(&ssam_bus_type);
  11343. +}
  11344. diff --git a/drivers/platform/surface/aggregator/bus.h b/drivers/platform/surface/aggregator/bus.h
  11345. new file mode 100644
  11346. index 000000000000..7712baaed6a5
  11347. --- /dev/null
  11348. +++ b/drivers/platform/surface/aggregator/bus.h
  11349. @@ -0,0 +1,27 @@
  11350. +/* SPDX-License-Identifier: GPL-2.0+ */
  11351. +/*
  11352. + * Surface System Aggregator Module bus and device integration.
  11353. + *
  11354. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  11355. + */
  11356. +
  11357. +#ifndef _SURFACE_AGGREGATOR_BUS_H
  11358. +#define _SURFACE_AGGREGATOR_BUS_H
  11359. +
  11360. +#include <linux/surface_aggregator/controller.h>
  11361. +
  11362. +#ifdef CONFIG_SURFACE_AGGREGATOR_BUS
  11363. +
  11364. +void ssam_controller_remove_clients(struct ssam_controller *ctrl);
  11365. +
  11366. +int ssam_bus_register(void);
  11367. +void ssam_bus_unregister(void);
  11368. +
  11369. +#else /* CONFIG_SURFACE_AGGREGATOR_BUS */
  11370. +
  11371. +static inline void ssam_controller_remove_clients(struct ssam_controller *ctrl) {}
  11372. +static inline int ssam_bus_register(void) { return 0; }
  11373. +static inline void ssam_bus_unregister(void) {}
  11374. +
  11375. +#endif /* CONFIG_SURFACE_AGGREGATOR_BUS */
  11376. +#endif /* _SURFACE_AGGREGATOR_BUS_H */
  11377. diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
  11378. index b6a9dea53592..8dc2c267bcd6 100644
  11379. --- a/drivers/platform/surface/aggregator/core.c
  11380. +++ b/drivers/platform/surface/aggregator/core.c
  11381. @@ -22,6 +22,8 @@
  11382. #include <linux/sysfs.h>
  11383. #include <linux/surface_aggregator/controller.h>
  11384. +
  11385. +#include "bus.h"
  11386. #include "controller.h"
  11387. #define CREATE_TRACE_POINTS
  11388. @@ -739,6 +741,9 @@ static void ssam_serial_hub_remove(struct serdev_device *serdev)
  11389. sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group);
  11390. ssam_controller_lock(ctrl);
  11391. + /* Remove all client devices. */
  11392. + ssam_controller_remove_clients(ctrl);
  11393. +
  11394. /* Act as if suspending to silence events. */
  11395. status = ssam_ctrl_notif_display_off(ctrl);
  11396. if (status) {
  11397. @@ -791,6 +796,10 @@ static int __init ssam_core_init(void)
  11398. {
  11399. int status;
  11400. + status = ssam_bus_register();
  11401. + if (status)
  11402. + goto err_bus;
  11403. +
  11404. status = ssh_ctrl_packet_cache_init();
  11405. if (status)
  11406. goto err_cpkg;
  11407. @@ -810,6 +819,8 @@ static int __init ssam_core_init(void)
  11408. err_evitem:
  11409. ssh_ctrl_packet_cache_destroy();
  11410. err_cpkg:
  11411. + ssam_bus_unregister();
  11412. +err_bus:
  11413. return status;
  11414. }
  11415. module_init(ssam_core_init);
  11416. @@ -819,6 +830,7 @@ static void __exit ssam_core_exit(void)
  11417. serdev_device_driver_unregister(&ssam_serial_hub);
  11418. ssam_event_item_cache_destroy();
  11419. ssh_ctrl_packet_cache_destroy();
  11420. + ssam_bus_unregister();
  11421. }
  11422. module_exit(ssam_core_exit);
  11423. diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
  11424. index c425290b21e2..935060955152 100644
  11425. --- a/include/linux/mod_devicetable.h
  11426. +++ b/include/linux/mod_devicetable.h
  11427. @@ -846,4 +846,22 @@ struct auxiliary_device_id {
  11428. kernel_ulong_t driver_data;
  11429. };
  11430. +/* Surface System Aggregator Module */
  11431. +
  11432. +#define SSAM_MATCH_TARGET 0x1
  11433. +#define SSAM_MATCH_INSTANCE 0x2
  11434. +#define SSAM_MATCH_FUNCTION 0x4
  11435. +
  11436. +struct ssam_device_id {
  11437. + __u8 match_flags;
  11438. +
  11439. + __u8 domain;
  11440. + __u8 category;
  11441. + __u8 target;
  11442. + __u8 instance;
  11443. + __u8 function;
  11444. +
  11445. + kernel_ulong_t driver_data;
  11446. +};
  11447. +
  11448. #endif /* LINUX_MOD_DEVICETABLE_H */
  11449. diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h
  11450. new file mode 100644
  11451. index 000000000000..02f3e06c0a60
  11452. --- /dev/null
  11453. +++ b/include/linux/surface_aggregator/device.h
  11454. @@ -0,0 +1,423 @@
  11455. +/* SPDX-License-Identifier: GPL-2.0+ */
  11456. +/*
  11457. + * Surface System Aggregator Module (SSAM) bus and client-device subsystem.
  11458. + *
  11459. + * Main interface for the surface-aggregator bus, surface-aggregator client
  11460. + * devices, and respective drivers building on top of the SSAM controller.
  11461. + * Provides support for non-platform/non-ACPI SSAM clients via dedicated
  11462. + * subsystem.
  11463. + *
  11464. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  11465. + */
  11466. +
  11467. +#ifndef _LINUX_SURFACE_AGGREGATOR_DEVICE_H
  11468. +#define _LINUX_SURFACE_AGGREGATOR_DEVICE_H
  11469. +
  11470. +#include <linux/device.h>
  11471. +#include <linux/mod_devicetable.h>
  11472. +#include <linux/types.h>
  11473. +
  11474. +#include <linux/surface_aggregator/controller.h>
  11475. +
  11476. +
  11477. +/* -- Surface System Aggregator Module bus. --------------------------------- */
  11478. +
  11479. +/**
  11480. + * enum ssam_device_domain - SAM device domain.
  11481. + * @SSAM_DOMAIN_VIRTUAL: Virtual device.
  11482. + * @SSAM_DOMAIN_SERIALHUB: Physical device connected via Surface Serial Hub.
  11483. + */
  11484. +enum ssam_device_domain {
  11485. + SSAM_DOMAIN_VIRTUAL = 0x00,
  11486. + SSAM_DOMAIN_SERIALHUB = 0x01,
  11487. +};
  11488. +
  11489. +/**
  11490. + * enum ssam_virtual_tc - Target categories for the virtual SAM domain.
  11491. + * @SSAM_VIRTUAL_TC_HUB: Device hub category.
  11492. + */
  11493. +enum ssam_virtual_tc {
  11494. + SSAM_VIRTUAL_TC_HUB = 0x00,
  11495. +};
  11496. +
  11497. +/**
  11498. + * struct ssam_device_uid - Unique identifier for SSAM device.
  11499. + * @domain: Domain of the device.
  11500. + * @category: Target category of the device.
  11501. + * @target: Target ID of the device.
  11502. + * @instance: Instance ID of the device.
  11503. + * @function: Sub-function of the device. This field can be used to split a
  11504. + * single SAM device into multiple virtual subdevices to separate
  11505. + * different functionality of that device and allow one driver per
  11506. + * such functionality.
  11507. + */
  11508. +struct ssam_device_uid {
  11509. + u8 domain;
  11510. + u8 category;
  11511. + u8 target;
  11512. + u8 instance;
  11513. + u8 function;
  11514. +};
  11515. +
  11516. +/*
  11517. + * Special values for device matching.
  11518. + *
  11519. + * These values are intended to be used with SSAM_DEVICE(), SSAM_VDEV(), and
  11520. + * SSAM_SDEV() exclusively. Specifically, they are used to initialize the
  11521. + * match_flags member of the device ID structure. Do not use them directly
  11522. + * with struct ssam_device_id or struct ssam_device_uid.
  11523. + */
  11524. +#define SSAM_ANY_TID 0xffff
  11525. +#define SSAM_ANY_IID 0xffff
  11526. +#define SSAM_ANY_FUN 0xffff
  11527. +
  11528. +/**
  11529. + * SSAM_DEVICE() - Initialize a &struct ssam_device_id with the given
  11530. + * parameters.
  11531. + * @d: Domain of the device.
  11532. + * @cat: Target category of the device.
  11533. + * @tid: Target ID of the device.
  11534. + * @iid: Instance ID of the device.
  11535. + * @fun: Sub-function of the device.
  11536. + *
  11537. + * Initializes a &struct ssam_device_id with the given parameters. See &struct
  11538. + * ssam_device_uid for details regarding the parameters. The special values
  11539. + * %SSAM_ANY_TID, %SSAM_ANY_IID, and %SSAM_ANY_FUN can be used to specify that
  11540. + * matching should ignore target ID, instance ID, and/or sub-function,
  11541. + * respectively. This macro initializes the ``match_flags`` field based on the
  11542. + * given parameters.
  11543. + *
  11544. + * Note: The parameters @d and @cat must be valid &u8 values, the parameters
  11545. + * @tid, @iid, and @fun must be either valid &u8 values or %SSAM_ANY_TID,
  11546. + * %SSAM_ANY_IID, or %SSAM_ANY_FUN, respectively. Other non-&u8 values are not
  11547. + * allowed.
  11548. + */
  11549. +#define SSAM_DEVICE(d, cat, tid, iid, fun) \
  11550. + .match_flags = (((tid) != SSAM_ANY_TID) ? SSAM_MATCH_TARGET : 0) \
  11551. + | (((iid) != SSAM_ANY_IID) ? SSAM_MATCH_INSTANCE : 0) \
  11552. + | (((fun) != SSAM_ANY_FUN) ? SSAM_MATCH_FUNCTION : 0), \
  11553. + .domain = d, \
  11554. + .category = cat, \
  11555. + .target = ((tid) != SSAM_ANY_TID) ? (tid) : 0, \
  11556. + .instance = ((iid) != SSAM_ANY_IID) ? (iid) : 0, \
  11557. + .function = ((fun) != SSAM_ANY_FUN) ? (fun) : 0 \
  11558. +
  11559. +/**
  11560. + * SSAM_VDEV() - Initialize a &struct ssam_device_id as virtual device with
  11561. + * the given parameters.
  11562. + * @cat: Target category of the device.
  11563. + * @tid: Target ID of the device.
  11564. + * @iid: Instance ID of the device.
  11565. + * @fun: Sub-function of the device.
  11566. + *
  11567. + * Initializes a &struct ssam_device_id with the given parameters in the
  11568. + * virtual domain. See &struct ssam_device_uid for details regarding the
  11569. + * parameters. The special values %SSAM_ANY_TID, %SSAM_ANY_IID, and
  11570. + * %SSAM_ANY_FUN can be used to specify that matching should ignore target ID,
  11571. + * instance ID, and/or sub-function, respectively. This macro initializes the
  11572. + * ``match_flags`` field based on the given parameters.
  11573. + *
  11574. + * Note: The parameter @cat must be a valid &u8 value, the parameters @tid,
  11575. + * @iid, and @fun must be either valid &u8 values or %SSAM_ANY_TID,
  11576. + * %SSAM_ANY_IID, or %SSAM_ANY_FUN, respectively. Other non-&u8 values are not
  11577. + * allowed.
  11578. + */
  11579. +#define SSAM_VDEV(cat, tid, iid, fun) \
  11580. + SSAM_DEVICE(SSAM_DOMAIN_VIRTUAL, SSAM_VIRTUAL_TC_##cat, tid, iid, fun)
  11581. +
  11582. +/**
  11583. + * SSAM_SDEV() - Initialize a &struct ssam_device_id as physical SSH device
  11584. + * with the given parameters.
  11585. + * @cat: Target category of the device.
  11586. + * @tid: Target ID of the device.
  11587. + * @iid: Instance ID of the device.
  11588. + * @fun: Sub-function of the device.
  11589. + *
  11590. + * Initializes a &struct ssam_device_id with the given parameters in the SSH
  11591. + * domain. See &struct ssam_device_uid for details regarding the parameters.
  11592. + * The special values %SSAM_ANY_TID, %SSAM_ANY_IID, and %SSAM_ANY_FUN can be
  11593. + * used to specify that matching should ignore target ID, instance ID, and/or
  11594. + * sub-function, respectively. This macro initializes the ``match_flags``
  11595. + * field based on the given parameters.
  11596. + *
  11597. + * Note: The parameter @cat must be a valid &u8 value, the parameters @tid,
  11598. + * @iid, and @fun must be either valid &u8 values or %SSAM_ANY_TID,
  11599. + * %SSAM_ANY_IID, or %SSAM_ANY_FUN, respectively. Other non-&u8 values are not
  11600. + * allowed.
  11601. + */
  11602. +#define SSAM_SDEV(cat, tid, iid, fun) \
  11603. + SSAM_DEVICE(SSAM_DOMAIN_SERIALHUB, SSAM_SSH_TC_##cat, tid, iid, fun)
  11604. +
  11605. +/**
  11606. + * struct ssam_device - SSAM client device.
  11607. + * @dev: Driver model representation of the device.
  11608. + * @ctrl: SSAM controller managing this device.
  11609. + * @uid: UID identifying the device.
  11610. + */
  11611. +struct ssam_device {
  11612. + struct device dev;
  11613. + struct ssam_controller *ctrl;
  11614. +
  11615. + struct ssam_device_uid uid;
  11616. +};
  11617. +
  11618. +/**
  11619. + * struct ssam_device_driver - SSAM client device driver.
  11620. + * @driver: Base driver model structure.
  11621. + * @match_table: Match table specifying which devices the driver should bind to.
  11622. + * @probe: Called when the driver is being bound to a device.
  11623. + * @remove: Called when the driver is being unbound from the device.
  11624. + */
  11625. +struct ssam_device_driver {
  11626. + struct device_driver driver;
  11627. +
  11628. + const struct ssam_device_id *match_table;
  11629. +
  11630. + int (*probe)(struct ssam_device *sdev);
  11631. + void (*remove)(struct ssam_device *sdev);
  11632. +};
  11633. +
  11634. +extern struct bus_type ssam_bus_type;
  11635. +extern const struct device_type ssam_device_type;
  11636. +
  11637. +/**
  11638. + * is_ssam_device() - Check if the given device is a SSAM client device.
  11639. + * @d: The device to test the type of.
  11640. + *
  11641. + * Return: Returns %true if the specified device is of type &struct
  11642. + * ssam_device, i.e. the device type points to %ssam_device_type, and %false
  11643. + * otherwise.
  11644. + */
  11645. +static inline bool is_ssam_device(struct device *d)
  11646. +{
  11647. + return d->type == &ssam_device_type;
  11648. +}
  11649. +
  11650. +/**
  11651. + * to_ssam_device() - Casts the given device to a SSAM client device.
  11652. + * @d: The device to cast.
  11653. + *
  11654. + * Casts the given &struct device to a &struct ssam_device. The caller has to
  11655. + * ensure that the given device is actually enclosed in a &struct ssam_device,
  11656. + * e.g. by calling is_ssam_device().
  11657. + *
  11658. + * Return: Returns a pointer to the &struct ssam_device wrapping the given
  11659. + * device @d.
  11660. + */
  11661. +static inline struct ssam_device *to_ssam_device(struct device *d)
  11662. +{
  11663. + return container_of(d, struct ssam_device, dev);
  11664. +}
  11665. +
  11666. +/**
  11667. + * to_ssam_device_driver() - Casts the given device driver to a SSAM client
  11668. + * device driver.
  11669. + * @d: The driver to cast.
  11670. + *
  11671. + * Casts the given &struct device_driver to a &struct ssam_device_driver. The
  11672. + * caller has to ensure that the given driver is actually enclosed in a
  11673. + * &struct ssam_device_driver.
  11674. + *
  11675. + * Return: Returns the pointer to the &struct ssam_device_driver wrapping the
  11676. + * given device driver @d.
  11677. + */
  11678. +static inline
  11679. +struct ssam_device_driver *to_ssam_device_driver(struct device_driver *d)
  11680. +{
  11681. + return container_of(d, struct ssam_device_driver, driver);
  11682. +}
  11683. +
  11684. +const struct ssam_device_id *ssam_device_id_match(const struct ssam_device_id *table,
  11685. + const struct ssam_device_uid uid);
  11686. +
  11687. +const struct ssam_device_id *ssam_device_get_match(const struct ssam_device *dev);
  11688. +
  11689. +const void *ssam_device_get_match_data(const struct ssam_device *dev);
  11690. +
  11691. +struct ssam_device *ssam_device_alloc(struct ssam_controller *ctrl,
  11692. + struct ssam_device_uid uid);
  11693. +
  11694. +int ssam_device_add(struct ssam_device *sdev);
  11695. +void ssam_device_remove(struct ssam_device *sdev);
  11696. +
  11697. +/**
  11698. + * ssam_device_get() - Increment reference count of SSAM client device.
  11699. + * @sdev: The device to increment the reference count of.
  11700. + *
  11701. + * Increments the reference count of the given SSAM client device by
  11702. + * incrementing the reference count of the enclosed &struct device via
  11703. + * get_device().
  11704. + *
  11705. + * See ssam_device_put() for the counter-part of this function.
  11706. + *
  11707. + * Return: Returns the device provided as input.
  11708. + */
  11709. +static inline struct ssam_device *ssam_device_get(struct ssam_device *sdev)
  11710. +{
  11711. + return sdev ? to_ssam_device(get_device(&sdev->dev)) : NULL;
  11712. +}
  11713. +
  11714. +/**
  11715. + * ssam_device_put() - Decrement reference count of SSAM client device.
  11716. + * @sdev: The device to decrement the reference count of.
  11717. + *
  11718. + * Decrements the reference count of the given SSAM client device by
  11719. + * decrementing the reference count of the enclosed &struct device via
  11720. + * put_device().
  11721. + *
  11722. + * See ssam_device_get() for the counter-part of this function.
  11723. + */
  11724. +static inline void ssam_device_put(struct ssam_device *sdev)
  11725. +{
  11726. + if (sdev)
  11727. + put_device(&sdev->dev);
  11728. +}
  11729. +
  11730. +/**
  11731. + * ssam_device_get_drvdata() - Get driver-data of SSAM client device.
  11732. + * @sdev: The device to get the driver-data from.
  11733. + *
  11734. + * Return: Returns the driver-data of the given device, previously set via
  11735. + * ssam_device_set_drvdata().
  11736. + */
  11737. +static inline void *ssam_device_get_drvdata(struct ssam_device *sdev)
  11738. +{
  11739. + return dev_get_drvdata(&sdev->dev);
  11740. +}
  11741. +
  11742. +/**
  11743. + * ssam_device_set_drvdata() - Set driver-data of SSAM client device.
  11744. + * @sdev: The device to set the driver-data of.
  11745. + * @data: The data to set the device's driver-data pointer to.
  11746. + */
  11747. +static inline void ssam_device_set_drvdata(struct ssam_device *sdev, void *data)
  11748. +{
  11749. + dev_set_drvdata(&sdev->dev, data);
  11750. +}
  11751. +
  11752. +int __ssam_device_driver_register(struct ssam_device_driver *d, struct module *o);
  11753. +void ssam_device_driver_unregister(struct ssam_device_driver *d);
  11754. +
  11755. +/**
  11756. + * ssam_device_driver_register() - Register a SSAM client device driver.
  11757. + * @drv: The driver to register.
  11758. + */
  11759. +#define ssam_device_driver_register(drv) \
  11760. + __ssam_device_driver_register(drv, THIS_MODULE)
  11761. +
  11762. +/**
  11763. + * module_ssam_device_driver() - Helper macro for SSAM device driver
  11764. + * registration.
  11765. + * @drv: The driver managed by this module.
  11766. + *
  11767. + * Helper macro to register a SSAM device driver via module_init() and
  11768. + * module_exit(). This macro may only be used once per module and replaces the
  11769. + * aforementioned definitions.
  11770. + */
  11771. +#define module_ssam_device_driver(drv) \
  11772. + module_driver(drv, ssam_device_driver_register, \
  11773. + ssam_device_driver_unregister)
  11774. +
  11775. +
  11776. +/* -- Helpers for client-device requests. ----------------------------------- */
  11777. +
  11778. +/**
  11779. + * SSAM_DEFINE_SYNC_REQUEST_CL_N() - Define synchronous client-device SAM
  11780. + * request function with neither argument nor return value.
  11781. + * @name: Name of the generated function.
  11782. + * @spec: Specification (&struct ssam_request_spec_md) defining the request.
  11783. + *
  11784. + * Defines a function executing the synchronous SAM request specified by
  11785. + * @spec, with the request having neither argument nor return value. Device
  11786. + * specifying parameters are not hard-coded, but instead are provided via the
  11787. + * client device, specifically its UID, supplied when calling this function.
  11788. + * The generated function takes care of setting up the request struct, buffer
  11789. + * allocation, as well as execution of the request itself, returning once the
  11790. + * request has been fully completed. The required transport buffer will be
  11791. + * allocated on the stack.
  11792. + *
  11793. + * The generated function is defined as ``int name(struct ssam_device *sdev)``,
  11794. + * returning the status of the request, which is zero on success and negative
  11795. + * on failure. The ``sdev`` parameter specifies both the target device of the
  11796. + * request and by association the controller via which the request is sent.
  11797. + *
  11798. + * Refer to ssam_request_sync_onstack() for more details on the behavior of
  11799. + * the generated function.
  11800. + */
  11801. +#define SSAM_DEFINE_SYNC_REQUEST_CL_N(name, spec...) \
  11802. + SSAM_DEFINE_SYNC_REQUEST_MD_N(__raw_##name, spec) \
  11803. + int name(struct ssam_device *sdev) \
  11804. + { \
  11805. + return __raw_##name(sdev->ctrl, sdev->uid.target, \
  11806. + sdev->uid.instance); \
  11807. + }
  11808. +
  11809. +/**
  11810. + * SSAM_DEFINE_SYNC_REQUEST_CL_W() - Define synchronous client-device SAM
  11811. + * request function with argument.
  11812. + * @name: Name of the generated function.
  11813. + * @atype: Type of the request's argument.
  11814. + * @spec: Specification (&struct ssam_request_spec_md) defining the request.
  11815. + *
  11816. + * Defines a function executing the synchronous SAM request specified by
  11817. + * @spec, with the request taking an argument of type @atype and having no
  11818. + * return value. Device specifying parameters are not hard-coded, but instead
  11819. + * are provided via the client device, specifically its UID, supplied when
  11820. + * calling this function. The generated function takes care of setting up the
  11821. + * request struct, buffer allocation, as well as execution of the request
  11822. + * itself, returning once the request has been fully completed. The required
  11823. + * transport buffer will be allocated on the stack.
  11824. + *
  11825. + * The generated function is defined as ``int name(struct ssam_device *sdev,
  11826. + * const atype *arg)``, returning the status of the request, which is zero on
  11827. + * success and negative on failure. The ``sdev`` parameter specifies both the
  11828. + * target device of the request and by association the controller via which
  11829. + * the request is sent. The request's argument is specified via the ``arg``
  11830. + * pointer.
  11831. + *
  11832. + * Refer to ssam_request_sync_onstack() for more details on the behavior of
  11833. + * the generated function.
  11834. + */
  11835. +#define SSAM_DEFINE_SYNC_REQUEST_CL_W(name, atype, spec...) \
  11836. + SSAM_DEFINE_SYNC_REQUEST_MD_W(__raw_##name, atype, spec) \
  11837. + int name(struct ssam_device *sdev, const atype *arg) \
  11838. + { \
  11839. + return __raw_##name(sdev->ctrl, sdev->uid.target, \
  11840. + sdev->uid.instance, arg); \
  11841. + }
  11842. +
  11843. +/**
  11844. + * SSAM_DEFINE_SYNC_REQUEST_CL_R() - Define synchronous client-device SAM
  11845. + * request function with return value.
  11846. + * @name: Name of the generated function.
  11847. + * @rtype: Type of the request's return value.
  11848. + * @spec: Specification (&struct ssam_request_spec_md) defining the request.
  11849. + *
  11850. + * Defines a function executing the synchronous SAM request specified by
  11851. + * @spec, with the request taking no argument but having a return value of
  11852. + * type @rtype. Device specifying parameters are not hard-coded, but instead
  11853. + * are provided via the client device, specifically its UID, supplied when
  11854. + * calling this function. The generated function takes care of setting up the
  11855. + * request struct, buffer allocation, as well as execution of the request
  11856. + * itself, returning once the request has been fully completed. The required
  11857. + * transport buffer will be allocated on the stack.
  11858. + *
  11859. + * The generated function is defined as ``int name(struct ssam_device *sdev,
  11860. + * rtype *ret)``, returning the status of the request, which is zero on
  11861. + * success and negative on failure. The ``sdev`` parameter specifies both the
  11862. + * target device of the request and by association the controller via which
  11863. + * the request is sent. The request's return value is written to the memory
  11864. + * pointed to by the ``ret`` parameter.
  11865. + *
  11866. + * Refer to ssam_request_sync_onstack() for more details on the behavior of
  11867. + * the generated function.
  11868. + */
  11869. +#define SSAM_DEFINE_SYNC_REQUEST_CL_R(name, rtype, spec...) \
  11870. + SSAM_DEFINE_SYNC_REQUEST_MD_R(__raw_##name, rtype, spec) \
  11871. + int name(struct ssam_device *sdev, rtype *ret) \
  11872. + { \
  11873. + return __raw_##name(sdev->ctrl, sdev->uid.target, \
  11874. + sdev->uid.instance, ret); \
  11875. + }
  11876. +
  11877. +#endif /* _LINUX_SURFACE_AGGREGATOR_DEVICE_H */
  11878. diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c
  11879. index e377f52dbfa3..f078eeb0a961 100644
  11880. --- a/scripts/mod/devicetable-offsets.c
  11881. +++ b/scripts/mod/devicetable-offsets.c
  11882. @@ -246,5 +246,13 @@ int main(void)
  11883. DEVID(auxiliary_device_id);
  11884. DEVID_FIELD(auxiliary_device_id, name);
  11885. + DEVID(ssam_device_id);
  11886. + DEVID_FIELD(ssam_device_id, match_flags);
  11887. + DEVID_FIELD(ssam_device_id, domain);
  11888. + DEVID_FIELD(ssam_device_id, category);
  11889. + DEVID_FIELD(ssam_device_id, target);
  11890. + DEVID_FIELD(ssam_device_id, instance);
  11891. + DEVID_FIELD(ssam_device_id, function);
  11892. +
  11893. return 0;
  11894. }
  11895. diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
  11896. index fb4827027536..d21d2871387b 100644
  11897. --- a/scripts/mod/file2alias.c
  11898. +++ b/scripts/mod/file2alias.c
  11899. @@ -1375,6 +1375,28 @@ static int do_auxiliary_entry(const char *filename, void *symval, char *alias)
  11900. return 1;
  11901. }
  11902. +/*
  11903. + * Looks like: ssam:dNcNtNiNfN
  11904. + *
  11905. + * N is exactly 2 digits, where each is an upper-case hex digit.
  11906. + */
  11907. +static int do_ssam_entry(const char *filename, void *symval, char *alias)
  11908. +{
  11909. + DEF_FIELD(symval, ssam_device_id, match_flags);
  11910. + DEF_FIELD(symval, ssam_device_id, domain);
  11911. + DEF_FIELD(symval, ssam_device_id, category);
  11912. + DEF_FIELD(symval, ssam_device_id, target);
  11913. + DEF_FIELD(symval, ssam_device_id, instance);
  11914. + DEF_FIELD(symval, ssam_device_id, function);
  11915. +
  11916. + sprintf(alias, "ssam:d%02Xc%02X", domain, category);
  11917. + ADD(alias, "t", match_flags & SSAM_MATCH_TARGET, target);
  11918. + ADD(alias, "i", match_flags & SSAM_MATCH_INSTANCE, instance);
  11919. + ADD(alias, "f", match_flags & SSAM_MATCH_FUNCTION, function);
  11920. +
  11921. + return 1;
  11922. +}
  11923. +
  11924. /* Does namelen bytes of name exactly match the symbol? */
  11925. static bool sym_is(const char *name, unsigned namelen, const char *symbol)
  11926. {
  11927. @@ -1450,6 +1472,7 @@ static const struct devtable devtable[] = {
  11928. {"wmi", SIZE_wmi_device_id, do_wmi_entry},
  11929. {"mhi", SIZE_mhi_device_id, do_mhi_entry},
  11930. {"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry},
  11931. + {"ssam", SIZE_ssam_device_id, do_ssam_entry},
  11932. };
  11933. /* Create MODULE_ALIAS() statements.
  11934. --
  11935. 2.31.0
  11936. From e17f8d603291fa603359d2ad132ea776dcfc1bfb Mon Sep 17 00:00:00 2001
  11937. From: Maximilian Luz <luzmaximilian@gmail.com>
  11938. Date: Mon, 21 Dec 2020 19:39:57 +0100
  11939. Subject: [PATCH] docs: driver-api: Add Surface Aggregator subsystem
  11940. documentation
  11941. Add documentation for the Surface Aggregator subsystem and its client
  11942. drivers, giving an overview of the subsystem, its use-cases, its
  11943. internal structure and internal API, as well as its external API for
  11944. writing client drivers.
  11945. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  11946. Reviewed-by: Hans de Goede <hdegoede@redhat.com>
  11947. Link: https://lore.kernel.org/r/20201221183959.1186143-8-luzmaximilian@gmail.com
  11948. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  11949. Patchset: surface-sam
  11950. ---
  11951. Documentation/driver-api/index.rst | 1 +
  11952. .../surface_aggregator/client-api.rst | 38 ++
  11953. .../driver-api/surface_aggregator/client.rst | 393 ++++++++++++
  11954. .../surface_aggregator/clients/index.rst | 10 +
  11955. .../driver-api/surface_aggregator/index.rst | 21 +
  11956. .../surface_aggregator/internal-api.rst | 67 ++
  11957. .../surface_aggregator/internal.rst | 577 ++++++++++++++++++
  11958. .../surface_aggregator/overview.rst | 77 +++
  11959. .../driver-api/surface_aggregator/ssh.rst | 344 +++++++++++
  11960. MAINTAINERS | 1 +
  11961. 10 files changed, 1529 insertions(+)
  11962. create mode 100644 Documentation/driver-api/surface_aggregator/client-api.rst
  11963. create mode 100644 Documentation/driver-api/surface_aggregator/client.rst
  11964. create mode 100644 Documentation/driver-api/surface_aggregator/clients/index.rst
  11965. create mode 100644 Documentation/driver-api/surface_aggregator/index.rst
  11966. create mode 100644 Documentation/driver-api/surface_aggregator/internal-api.rst
  11967. create mode 100644 Documentation/driver-api/surface_aggregator/internal.rst
  11968. create mode 100644 Documentation/driver-api/surface_aggregator/overview.rst
  11969. create mode 100644 Documentation/driver-api/surface_aggregator/ssh.rst
  11970. diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst
  11971. index 2456d0a97ed8..9d9af54d68c5 100644
  11972. --- a/Documentation/driver-api/index.rst
  11973. +++ b/Documentation/driver-api/index.rst
  11974. @@ -99,6 +99,7 @@ available subsections can be seen below.
  11975. rfkill
  11976. serial/index
  11977. sm501
  11978. + surface_aggregator/index
  11979. switchtec
  11980. sync_file
  11981. vfio-mediated-device
  11982. diff --git a/Documentation/driver-api/surface_aggregator/client-api.rst b/Documentation/driver-api/surface_aggregator/client-api.rst
  11983. new file mode 100644
  11984. index 000000000000..8e0b000d0e64
  11985. --- /dev/null
  11986. +++ b/Documentation/driver-api/surface_aggregator/client-api.rst
  11987. @@ -0,0 +1,38 @@
  11988. +.. SPDX-License-Identifier: GPL-2.0+
  11989. +
  11990. +===============================
  11991. +Client Driver API Documentation
  11992. +===============================
  11993. +
  11994. +.. contents::
  11995. + :depth: 2
  11996. +
  11997. +
  11998. +Serial Hub Communication
  11999. +========================
  12000. +
  12001. +.. kernel-doc:: include/linux/surface_aggregator/serial_hub.h
  12002. +
  12003. +.. kernel-doc:: drivers/platform/surface/aggregator/ssh_packet_layer.c
  12004. + :export:
  12005. +
  12006. +
  12007. +Controller and Core Interface
  12008. +=============================
  12009. +
  12010. +.. kernel-doc:: include/linux/surface_aggregator/controller.h
  12011. +
  12012. +.. kernel-doc:: drivers/platform/surface/aggregator/controller.c
  12013. + :export:
  12014. +
  12015. +.. kernel-doc:: drivers/platform/surface/aggregator/core.c
  12016. + :export:
  12017. +
  12018. +
  12019. +Client Bus and Client Device API
  12020. +================================
  12021. +
  12022. +.. kernel-doc:: include/linux/surface_aggregator/device.h
  12023. +
  12024. +.. kernel-doc:: drivers/platform/surface/aggregator/bus.c
  12025. + :export:
  12026. diff --git a/Documentation/driver-api/surface_aggregator/client.rst b/Documentation/driver-api/surface_aggregator/client.rst
  12027. new file mode 100644
  12028. index 000000000000..26d13085a117
  12029. --- /dev/null
  12030. +++ b/Documentation/driver-api/surface_aggregator/client.rst
  12031. @@ -0,0 +1,393 @@
  12032. +.. SPDX-License-Identifier: GPL-2.0+
  12033. +
  12034. +.. |ssam_controller| replace:: :c:type:`struct ssam_controller <ssam_controller>`
  12035. +.. |ssam_device| replace:: :c:type:`struct ssam_device <ssam_device>`
  12036. +.. |ssam_device_driver| replace:: :c:type:`struct ssam_device_driver <ssam_device_driver>`
  12037. +.. |ssam_client_bind| replace:: :c:func:`ssam_client_bind`
  12038. +.. |ssam_client_link| replace:: :c:func:`ssam_client_link`
  12039. +.. |ssam_get_controller| replace:: :c:func:`ssam_get_controller`
  12040. +.. |ssam_controller_get| replace:: :c:func:`ssam_controller_get`
  12041. +.. |ssam_controller_put| replace:: :c:func:`ssam_controller_put`
  12042. +.. |ssam_device_alloc| replace:: :c:func:`ssam_device_alloc`
  12043. +.. |ssam_device_add| replace:: :c:func:`ssam_device_add`
  12044. +.. |ssam_device_remove| replace:: :c:func:`ssam_device_remove`
  12045. +.. |ssam_device_driver_register| replace:: :c:func:`ssam_device_driver_register`
  12046. +.. |ssam_device_driver_unregister| replace:: :c:func:`ssam_device_driver_unregister`
  12047. +.. |module_ssam_device_driver| replace:: :c:func:`module_ssam_device_driver`
  12048. +.. |SSAM_DEVICE| replace:: :c:func:`SSAM_DEVICE`
  12049. +.. |ssam_notifier_register| replace:: :c:func:`ssam_notifier_register`
  12050. +.. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister`
  12051. +.. |ssam_request_sync| replace:: :c:func:`ssam_request_sync`
  12052. +.. |ssam_event_mask| replace:: :c:type:`enum ssam_event_mask <ssam_event_mask>`
  12053. +
  12054. +
  12055. +======================
  12056. +Writing Client Drivers
  12057. +======================
  12058. +
  12059. +For the API documentation, refer to:
  12060. +
  12061. +.. toctree::
  12062. + :maxdepth: 2
  12063. +
  12064. + client-api
  12065. +
  12066. +
  12067. +Overview
  12068. +========
  12069. +
  12070. +Client drivers can be set up in two main ways, depending on how the
  12071. +corresponding device is made available to the system. We specifically
  12072. +differentiate between devices that are presented to the system via one of
  12073. +the conventional ways, e.g. as platform devices via ACPI, and devices that
  12074. +are non-discoverable and instead need to be explicitly provided by some
  12075. +other mechanism, as discussed further below.
  12076. +
  12077. +
  12078. +Non-SSAM Client Drivers
  12079. +=======================
  12080. +
  12081. +All communication with the SAM EC is handled via the |ssam_controller|
  12082. +representing that EC to the kernel. Drivers targeting a non-SSAM device (and
  12083. +thus not being a |ssam_device_driver|) need to explicitly establish a
  12084. +connection/relation to that controller. This can be done via the
  12085. +|ssam_client_bind| function. Said function returns a reference to the SSAM
  12086. +controller, but, more importantly, also establishes a device link between
  12087. +client device and controller (this can also be done separate via
  12088. +|ssam_client_link|). It is important to do this, as it, first, guarantees
  12089. +that the returned controller is valid for use in the client driver for as
  12090. +long as this driver is bound to its device, i.e. that the driver gets
  12091. +unbound before the controller ever becomes invalid, and, second, as it
  12092. +ensures correct suspend/resume ordering. This setup should be done in the
  12093. +driver's probe function, and may be used to defer probing in case the SSAM
  12094. +subsystem is not ready yet, for example:
  12095. +
  12096. +.. code-block:: c
  12097. +
  12098. + static int client_driver_probe(struct platform_device *pdev)
  12099. + {
  12100. + struct ssam_controller *ctrl;
  12101. +
  12102. + ctrl = ssam_client_bind(&pdev->dev);
  12103. + if (IS_ERR(ctrl))
  12104. + return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl);
  12105. +
  12106. + // ...
  12107. +
  12108. + return 0;
  12109. + }
  12110. +
  12111. +The controller may be separately obtained via |ssam_get_controller| and its
  12112. +lifetime be guaranteed via |ssam_controller_get| and |ssam_controller_put|.
  12113. +Note that none of these functions, however, guarantee that the controller
  12114. +will not be shut down or suspended. These functions essentially only operate
  12115. +on the reference, i.e. only guarantee a bare minimum of accessibility
  12116. +without any guarantees at all on practical operability.
  12117. +
  12118. +
  12119. +Adding SSAM Devices
  12120. +===================
  12121. +
  12122. +If a device does not already exist/is not already provided via conventional
  12123. +means, it should be provided as |ssam_device| via the SSAM client device
  12124. +hub. New devices can be added to this hub by entering their UID into the
  12125. +corresponding registry. SSAM devices can also be manually allocated via
  12126. +|ssam_device_alloc|, subsequently to which they have to be added via
  12127. +|ssam_device_add| and eventually removed via |ssam_device_remove|. By
  12128. +default, the parent of the device is set to the controller device provided
  12129. +for allocation, however this may be changed before the device is added. Note
  12130. +that, when changing the parent device, care must be taken to ensure that the
  12131. +controller lifetime and suspend/resume ordering guarantees, in the default
  12132. +setup provided through the parent-child relation, are preserved. If
  12133. +necessary, by use of |ssam_client_link| as is done for non-SSAM client
  12134. +drivers and described in more detail above.
  12135. +
  12136. +A client device must always be removed by the party which added the
  12137. +respective device before the controller shuts down. Such removal can be
  12138. +guaranteed by linking the driver providing the SSAM device to the controller
  12139. +via |ssam_client_link|, causing it to unbind before the controller driver
  12140. +unbinds. Client devices registered with the controller as parent are
  12141. +automatically removed when the controller shuts down, but this should not be
  12142. +relied upon, especially as this does not extend to client devices with a
  12143. +different parent.
  12144. +
  12145. +
  12146. +SSAM Client Drivers
  12147. +===================
  12148. +
  12149. +SSAM client device drivers are, in essence, no different than other device
  12150. +driver types. They are represented via |ssam_device_driver| and bind to a
  12151. +|ssam_device| via its UID (:c:type:`struct ssam_device.uid <ssam_device>`)
  12152. +member and the match table
  12153. +(:c:type:`struct ssam_device_driver.match_table <ssam_device_driver>`),
  12154. +which should be set when declaring the driver struct instance. Refer to the
  12155. +|SSAM_DEVICE| macro documentation for more details on how to define members
  12156. +of the driver's match table.
  12157. +
  12158. +The UID for SSAM client devices consists of a ``domain``, a ``category``,
  12159. +a ``target``, an ``instance``, and a ``function``. The ``domain`` is used
  12160. +differentiate between physical SAM devices
  12161. +(:c:type:`SSAM_DOMAIN_SERIALHUB <ssam_device_domain>`), i.e. devices that can
  12162. +be accessed via the Surface Serial Hub, and virtual ones
  12163. +(:c:type:`SSAM_DOMAIN_VIRTUAL <ssam_device_domain>`), such as client-device
  12164. +hubs, that have no real representation on the SAM EC and are solely used on
  12165. +the kernel/driver-side. For physical devices, ``category`` represents the
  12166. +target category, ``target`` the target ID, and ``instance`` the instance ID
  12167. +used to access the physical SAM device. In addition, ``function`` references
  12168. +a specific device functionality, but has no meaning to the SAM EC. The
  12169. +(default) name of a client device is generated based on its UID.
  12170. +
  12171. +A driver instance can be registered via |ssam_device_driver_register| and
  12172. +unregistered via |ssam_device_driver_unregister|. For convenience, the
  12173. +|module_ssam_device_driver| macro may be used to define module init- and
  12174. +exit-functions registering the driver.
  12175. +
  12176. +The controller associated with a SSAM client device can be found in its
  12177. +:c:type:`struct ssam_device.ctrl <ssam_device>` member. This reference is
  12178. +guaranteed to be valid for at least as long as the client driver is bound,
  12179. +but should also be valid for as long as the client device exists. Note,
  12180. +however, that access outside of the bound client driver must ensure that the
  12181. +controller device is not suspended while making any requests or
  12182. +(un-)registering event notifiers (and thus should generally be avoided). This
  12183. +is guaranteed when the controller is accessed from inside the bound client
  12184. +driver.
  12185. +
  12186. +
  12187. +Making Synchronous Requests
  12188. +===========================
  12189. +
  12190. +Synchronous requests are (currently) the main form of host-initiated
  12191. +communication with the EC. There are a couple of ways to define and execute
  12192. +such requests, however, most of them boil down to something similar as shown
  12193. +in the example below. This example defines a write-read request, meaning
  12194. +that the caller provides an argument to the SAM EC and receives a response.
  12195. +The caller needs to know the (maximum) length of the response payload and
  12196. +provide a buffer for it.
  12197. +
  12198. +Care must be taken to ensure that any command payload data passed to the SAM
  12199. +EC is provided in little-endian format and, similarly, any response payload
  12200. +data received from it is converted from little-endian to host endianness.
  12201. +
  12202. +.. code-block:: c
  12203. +
  12204. + int perform_request(struct ssam_controller *ctrl, u32 arg, u32 *ret)
  12205. + {
  12206. + struct ssam_request rqst;
  12207. + struct ssam_response resp;
  12208. + int status;
  12209. +
  12210. + /* Convert request argument to little-endian. */
  12211. + __le32 arg_le = cpu_to_le32(arg);
  12212. + __le32 ret_le = cpu_to_le32(0);
  12213. +
  12214. + /*
  12215. + * Initialize request specification. Replace this with your values.
  12216. + * The rqst.payload field may be NULL if rqst.length is zero,
  12217. + * indicating that the request does not have any argument.
  12218. + *
  12219. + * Note: The request parameters used here are not valid, i.e.
  12220. + * they do not correspond to an actual SAM/EC request.
  12221. + */
  12222. + rqst.target_category = SSAM_SSH_TC_SAM;
  12223. + rqst.target_id = 0x01;
  12224. + rqst.command_id = 0x02;
  12225. + rqst.instance_id = 0x03;
  12226. + rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
  12227. + rqst.length = sizeof(arg_le);
  12228. + rqst.payload = (u8 *)&arg_le;
  12229. +
  12230. + /* Initialize request response. */
  12231. + resp.capacity = sizeof(ret_le);
  12232. + resp.length = 0;
  12233. + resp.pointer = (u8 *)&ret_le;
  12234. +
  12235. + /*
  12236. + * Perform actual request. The response pointer may be null in case
  12237. + * the request does not have any response. This must be consistent
  12238. + * with the SSAM_REQUEST_HAS_RESPONSE flag set in the specification
  12239. + * above.
  12240. + */
  12241. + status = ssam_request_sync(ctrl, &rqst, &resp);
  12242. +
  12243. + /*
  12244. + * Alternatively use
  12245. + *
  12246. + * ssam_request_sync_onstack(ctrl, &rqst, &resp, sizeof(arg_le));
  12247. + *
  12248. + * to perform the request, allocating the message buffer directly
  12249. + * on the stack as opposed to allocation via kzalloc().
  12250. + */
  12251. +
  12252. + /*
  12253. + * Convert request response back to native format. Note that in the
  12254. + * error case, this value is not touched by the SSAM core, i.e.
  12255. + * 'ret_le' will be zero as specified in its initialization.
  12256. + */
  12257. + *ret = le32_to_cpu(ret_le);
  12258. +
  12259. + return status;
  12260. + }
  12261. +
  12262. +Note that |ssam_request_sync| in its essence is a wrapper over lower-level
  12263. +request primitives, which may also be used to perform requests. Refer to its
  12264. +implementation and documentation for more details.
  12265. +
  12266. +An arguably more user-friendly way of defining such functions is by using
  12267. +one of the generator macros, for example via:
  12268. +
  12269. +.. code-block:: c
  12270. +
  12271. + SSAM_DEFINE_SYNC_REQUEST_W(__ssam_tmp_perf_mode_set, __le32, {
  12272. + .target_category = SSAM_SSH_TC_TMP,
  12273. + .target_id = 0x01,
  12274. + .command_id = 0x03,
  12275. + .instance_id = 0x00,
  12276. + });
  12277. +
  12278. +This example defines a function
  12279. +
  12280. +.. code-block:: c
  12281. +
  12282. + int __ssam_tmp_perf_mode_set(struct ssam_controller *ctrl, const __le32 *arg);
  12283. +
  12284. +executing the specified request, with the controller passed in when calling
  12285. +said function. In this example, the argument is provided via the ``arg``
  12286. +pointer. Note that the generated function allocates the message buffer on
  12287. +the stack. Thus, if the argument provided via the request is large, these
  12288. +kinds of macros should be avoided. Also note that, in contrast to the
  12289. +previous non-macro example, this function does not do any endianness
  12290. +conversion, which has to be handled by the caller. Apart from those
  12291. +differences the function generated by the macro is similar to the one
  12292. +provided in the non-macro example above.
  12293. +
  12294. +The full list of such function-generating macros is
  12295. +
  12296. +- :c:func:`SSAM_DEFINE_SYNC_REQUEST_N` for requests without return value and
  12297. + without argument.
  12298. +- :c:func:`SSAM_DEFINE_SYNC_REQUEST_R` for requests with return value but no
  12299. + argument.
  12300. +- :c:func:`SSAM_DEFINE_SYNC_REQUEST_W` for requests without return value but
  12301. + with argument.
  12302. +
  12303. +Refer to their respective documentation for more details. For each one of
  12304. +these macros, a special variant is provided, which targets request types
  12305. +applicable to multiple instances of the same device type:
  12306. +
  12307. +- :c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_N`
  12308. +- :c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_R`
  12309. +- :c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_W`
  12310. +
  12311. +The difference of those macros to the previously mentioned versions is, that
  12312. +the device target and instance IDs are not fixed for the generated function,
  12313. +but instead have to be provided by the caller of said function.
  12314. +
  12315. +Additionally, variants for direct use with client devices, i.e.
  12316. +|ssam_device|, are also provided. These can, for example, be used as
  12317. +follows:
  12318. +
  12319. +.. code-block:: c
  12320. +
  12321. + SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, {
  12322. + .target_category = SSAM_SSH_TC_BAT,
  12323. + .command_id = 0x01,
  12324. + });
  12325. +
  12326. +This invocation of the macro defines a function
  12327. +
  12328. +.. code-block:: c
  12329. +
  12330. + int ssam_bat_get_sta(struct ssam_device *sdev, __le32 *ret);
  12331. +
  12332. +executing the specified request, using the device IDs and controller given
  12333. +in the client device. The full list of such macros for client devices is:
  12334. +
  12335. +- :c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_N`
  12336. +- :c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_R`
  12337. +- :c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_W`
  12338. +
  12339. +
  12340. +Handling Events
  12341. +===============
  12342. +
  12343. +To receive events from the SAM EC, an event notifier must be registered for
  12344. +the desired event via |ssam_notifier_register|. The notifier must be
  12345. +unregistered via |ssam_notifier_unregister| once it is not required any
  12346. +more.
  12347. +
  12348. +Event notifiers are registered by providing (at minimum) a callback to call
  12349. +in case an event has been received, the registry specifying how the event
  12350. +should be enabled, an event ID specifying for which target category and,
  12351. +optionally and depending on the registry used, for which instance ID events
  12352. +should be enabled, and finally, flags describing how the EC will send these
  12353. +events. If the specific registry does not enable events by instance ID, the
  12354. +instance ID must be set to zero. Additionally, a priority for the respective
  12355. +notifier may be specified, which determines its order in relation to any
  12356. +other notifier registered for the same target category.
  12357. +
  12358. +By default, event notifiers will receive all events for the specific target
  12359. +category, regardless of the instance ID specified when registering the
  12360. +notifier. The core may be instructed to only call a notifier if the target
  12361. +ID or instance ID (or both) of the event match the ones implied by the
  12362. +notifier IDs (in case of target ID, the target ID of the registry), by
  12363. +providing an event mask (see |ssam_event_mask|).
  12364. +
  12365. +In general, the target ID of the registry is also the target ID of the
  12366. +enabled event (with the notable exception being keyboard input events on the
  12367. +Surface Laptop 1 and 2, which are enabled via a registry with target ID 1,
  12368. +but provide events with target ID 2).
  12369. +
  12370. +A full example for registering an event notifier and handling received
  12371. +events is provided below:
  12372. +
  12373. +.. code-block:: c
  12374. +
  12375. + u32 notifier_callback(struct ssam_event_notifier *nf,
  12376. + const struct ssam_event *event)
  12377. + {
  12378. + int status = ...
  12379. +
  12380. + /* Handle the event here ... */
  12381. +
  12382. + /* Convert return value and indicate that we handled the event. */
  12383. + return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED;
  12384. + }
  12385. +
  12386. + int setup_notifier(struct ssam_device *sdev,
  12387. + struct ssam_event_notifier *nf)
  12388. + {
  12389. + /* Set priority wrt. other handlers of same target category. */
  12390. + nf->base.priority = 1;
  12391. +
  12392. + /* Set event/notifier callback. */
  12393. + nf->base.fn = notifier_callback;
  12394. +
  12395. + /* Specify event registry, i.e. how events get enabled/disabled. */
  12396. + nf->event.reg = SSAM_EVENT_REGISTRY_KIP;
  12397. +
  12398. + /* Specify which event to enable/disable */
  12399. + nf->event.id.target_category = sdev->uid.category;
  12400. + nf->event.id.instance = sdev->uid.instance;
  12401. +
  12402. + /*
  12403. + * Specify for which events the notifier callback gets executed.
  12404. + * This essentially tells the core if it can skip notifiers that
  12405. + * don't have target or instance IDs matching those of the event.
  12406. + */
  12407. + nf->event.mask = SSAM_EVENT_MASK_STRICT;
  12408. +
  12409. + /* Specify event flags. */
  12410. + nf->event.flags = SSAM_EVENT_SEQUENCED;
  12411. +
  12412. + return ssam_notifier_register(sdev->ctrl, nf);
  12413. + }
  12414. +
  12415. +Multiple event notifiers can be registered for the same event. The event
  12416. +handler core takes care of enabling and disabling events when notifiers are
  12417. +registered and unregistered, by keeping track of how many notifiers for a
  12418. +specific event (combination of registry, event target category, and event
  12419. +instance ID) are currently registered. This means that a specific event will
  12420. +be enabled when the first notifier for it is being registered and disabled
  12421. +when the last notifier for it is being unregistered. Note that the event
  12422. +flags are therefore only used on the first registered notifier, however, one
  12423. +should take care that notifiers for a specific event are always registered
  12424. +with the same flag and it is considered a bug to do otherwise.
  12425. diff --git a/Documentation/driver-api/surface_aggregator/clients/index.rst b/Documentation/driver-api/surface_aggregator/clients/index.rst
  12426. new file mode 100644
  12427. index 000000000000..31e026d96102
  12428. --- /dev/null
  12429. +++ b/Documentation/driver-api/surface_aggregator/clients/index.rst
  12430. @@ -0,0 +1,10 @@
  12431. +.. SPDX-License-Identifier: GPL-2.0+
  12432. +
  12433. +===========================
  12434. +Client Driver Documentation
  12435. +===========================
  12436. +
  12437. +This is the documentation for client drivers themselves. Refer to
  12438. +:doc:`../client` for documentation on how to write client drivers.
  12439. +
  12440. +.. Place documentation for individual client drivers here.
  12441. diff --git a/Documentation/driver-api/surface_aggregator/index.rst b/Documentation/driver-api/surface_aggregator/index.rst
  12442. new file mode 100644
  12443. index 000000000000..6f3e1094904d
  12444. --- /dev/null
  12445. +++ b/Documentation/driver-api/surface_aggregator/index.rst
  12446. @@ -0,0 +1,21 @@
  12447. +.. SPDX-License-Identifier: GPL-2.0+
  12448. +
  12449. +=======================================
  12450. +Surface System Aggregator Module (SSAM)
  12451. +=======================================
  12452. +
  12453. +.. toctree::
  12454. + :maxdepth: 2
  12455. +
  12456. + overview
  12457. + client
  12458. + clients/index
  12459. + ssh
  12460. + internal
  12461. +
  12462. +.. only:: subproject and html
  12463. +
  12464. + Indices
  12465. + =======
  12466. +
  12467. + * :ref:`genindex`
  12468. diff --git a/Documentation/driver-api/surface_aggregator/internal-api.rst b/Documentation/driver-api/surface_aggregator/internal-api.rst
  12469. new file mode 100644
  12470. index 000000000000..639a67b5a392
  12471. --- /dev/null
  12472. +++ b/Documentation/driver-api/surface_aggregator/internal-api.rst
  12473. @@ -0,0 +1,67 @@
  12474. +.. SPDX-License-Identifier: GPL-2.0+
  12475. +
  12476. +==========================
  12477. +Internal API Documentation
  12478. +==========================
  12479. +
  12480. +.. contents::
  12481. + :depth: 2
  12482. +
  12483. +
  12484. +Packet Transport Layer
  12485. +======================
  12486. +
  12487. +.. kernel-doc:: drivers/platform/surface/aggregator/ssh_parser.h
  12488. + :internal:
  12489. +
  12490. +.. kernel-doc:: drivers/platform/surface/aggregator/ssh_parser.c
  12491. + :internal:
  12492. +
  12493. +.. kernel-doc:: drivers/platform/surface/aggregator/ssh_msgb.h
  12494. + :internal:
  12495. +
  12496. +.. kernel-doc:: drivers/platform/surface/aggregator/ssh_packet_layer.h
  12497. + :internal:
  12498. +
  12499. +.. kernel-doc:: drivers/platform/surface/aggregator/ssh_packet_layer.c
  12500. + :internal:
  12501. +
  12502. +
  12503. +Request Transport Layer
  12504. +=======================
  12505. +
  12506. +.. kernel-doc:: drivers/platform/surface/aggregator/ssh_request_layer.h
  12507. + :internal:
  12508. +
  12509. +.. kernel-doc:: drivers/platform/surface/aggregator/ssh_request_layer.c
  12510. + :internal:
  12511. +
  12512. +
  12513. +Controller
  12514. +==========
  12515. +
  12516. +.. kernel-doc:: drivers/platform/surface/aggregator/controller.h
  12517. + :internal:
  12518. +
  12519. +.. kernel-doc:: drivers/platform/surface/aggregator/controller.c
  12520. + :internal:
  12521. +
  12522. +
  12523. +Client Device Bus
  12524. +=================
  12525. +
  12526. +.. kernel-doc:: drivers/platform/surface/aggregator/bus.c
  12527. + :internal:
  12528. +
  12529. +
  12530. +Core
  12531. +====
  12532. +
  12533. +.. kernel-doc:: drivers/platform/surface/aggregator/core.c
  12534. + :internal:
  12535. +
  12536. +
  12537. +Trace Helpers
  12538. +=============
  12539. +
  12540. +.. kernel-doc:: drivers/platform/surface/aggregator/trace.h
  12541. diff --git a/Documentation/driver-api/surface_aggregator/internal.rst b/Documentation/driver-api/surface_aggregator/internal.rst
  12542. new file mode 100644
  12543. index 000000000000..72704734982a
  12544. --- /dev/null
  12545. +++ b/Documentation/driver-api/surface_aggregator/internal.rst
  12546. @@ -0,0 +1,577 @@
  12547. +.. SPDX-License-Identifier: GPL-2.0+
  12548. +
  12549. +.. |ssh_ptl| replace:: :c:type:`struct ssh_ptl <ssh_ptl>`
  12550. +.. |ssh_ptl_submit| replace:: :c:func:`ssh_ptl_submit`
  12551. +.. |ssh_ptl_cancel| replace:: :c:func:`ssh_ptl_cancel`
  12552. +.. |ssh_ptl_shutdown| replace:: :c:func:`ssh_ptl_shutdown`
  12553. +.. |ssh_ptl_rx_rcvbuf| replace:: :c:func:`ssh_ptl_rx_rcvbuf`
  12554. +.. |ssh_rtl| replace:: :c:type:`struct ssh_rtl <ssh_rtl>`
  12555. +.. |ssh_rtl_submit| replace:: :c:func:`ssh_rtl_submit`
  12556. +.. |ssh_rtl_cancel| replace:: :c:func:`ssh_rtl_cancel`
  12557. +.. |ssh_rtl_shutdown| replace:: :c:func:`ssh_rtl_shutdown`
  12558. +.. |ssh_packet| replace:: :c:type:`struct ssh_packet <ssh_packet>`
  12559. +.. |ssh_packet_get| replace:: :c:func:`ssh_packet_get`
  12560. +.. |ssh_packet_put| replace:: :c:func:`ssh_packet_put`
  12561. +.. |ssh_packet_ops| replace:: :c:type:`struct ssh_packet_ops <ssh_packet_ops>`
  12562. +.. |ssh_packet_base_priority| replace:: :c:type:`enum ssh_packet_base_priority <ssh_packet_base_priority>`
  12563. +.. |ssh_packet_flags| replace:: :c:type:`enum ssh_packet_flags <ssh_packet_flags>`
  12564. +.. |SSH_PACKET_PRIORITY| replace:: :c:func:`SSH_PACKET_PRIORITY`
  12565. +.. |ssh_frame| replace:: :c:type:`struct ssh_frame <ssh_frame>`
  12566. +.. |ssh_command| replace:: :c:type:`struct ssh_command <ssh_command>`
  12567. +.. |ssh_request| replace:: :c:type:`struct ssh_request <ssh_request>`
  12568. +.. |ssh_request_get| replace:: :c:func:`ssh_request_get`
  12569. +.. |ssh_request_put| replace:: :c:func:`ssh_request_put`
  12570. +.. |ssh_request_ops| replace:: :c:type:`struct ssh_request_ops <ssh_request_ops>`
  12571. +.. |ssh_request_init| replace:: :c:func:`ssh_request_init`
  12572. +.. |ssh_request_flags| replace:: :c:type:`enum ssh_request_flags <ssh_request_flags>`
  12573. +.. |ssam_controller| replace:: :c:type:`struct ssam_controller <ssam_controller>`
  12574. +.. |ssam_device| replace:: :c:type:`struct ssam_device <ssam_device>`
  12575. +.. |ssam_device_driver| replace:: :c:type:`struct ssam_device_driver <ssam_device_driver>`
  12576. +.. |ssam_client_bind| replace:: :c:func:`ssam_client_bind`
  12577. +.. |ssam_client_link| replace:: :c:func:`ssam_client_link`
  12578. +.. |ssam_request_sync| replace:: :c:type:`struct ssam_request_sync <ssam_request_sync>`
  12579. +.. |ssam_event_registry| replace:: :c:type:`struct ssam_event_registry <ssam_event_registry>`
  12580. +.. |ssam_event_id| replace:: :c:type:`struct ssam_event_id <ssam_event_id>`
  12581. +.. |ssam_nf| replace:: :c:type:`struct ssam_nf <ssam_nf>`
  12582. +.. |ssam_nf_refcount_inc| replace:: :c:func:`ssam_nf_refcount_inc`
  12583. +.. |ssam_nf_refcount_dec| replace:: :c:func:`ssam_nf_refcount_dec`
  12584. +.. |ssam_notifier_register| replace:: :c:func:`ssam_notifier_register`
  12585. +.. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister`
  12586. +.. |ssam_cplt| replace:: :c:type:`struct ssam_cplt <ssam_cplt>`
  12587. +.. |ssam_event_queue| replace:: :c:type:`struct ssam_event_queue <ssam_event_queue>`
  12588. +.. |ssam_request_sync_submit| replace:: :c:func:`ssam_request_sync_submit`
  12589. +
  12590. +=====================
  12591. +Core Driver Internals
  12592. +=====================
  12593. +
  12594. +Architectural overview of the Surface System Aggregator Module (SSAM) core
  12595. +and Surface Serial Hub (SSH) driver. For the API documentation, refer to:
  12596. +
  12597. +.. toctree::
  12598. + :maxdepth: 2
  12599. +
  12600. + internal-api
  12601. +
  12602. +
  12603. +Overview
  12604. +========
  12605. +
  12606. +The SSAM core implementation is structured in layers, somewhat following the
  12607. +SSH protocol structure:
  12608. +
  12609. +Lower-level packet transport is implemented in the *packet transport layer
  12610. +(PTL)*, directly building on top of the serial device (serdev)
  12611. +infrastructure of the kernel. As the name indicates, this layer deals with
  12612. +the packet transport logic and handles things like packet validation, packet
  12613. +acknowledgment (ACKing), packet (retransmission) timeouts, and relaying
  12614. +packet payloads to higher-level layers.
  12615. +
  12616. +Above this sits the *request transport layer (RTL)*. This layer is centered
  12617. +around command-type packet payloads, i.e. requests (sent from host to EC),
  12618. +responses of the EC to those requests, and events (sent from EC to host).
  12619. +It, specifically, distinguishes events from request responses, matches
  12620. +responses to their corresponding requests, and implements request timeouts.
  12621. +
  12622. +The *controller* layer is building on top of this and essentially decides
  12623. +how request responses and, especially, events are dealt with. It provides an
  12624. +event notifier system, handles event activation/deactivation, provides a
  12625. +workqueue for event and asynchronous request completion, and also manages
  12626. +the message counters required for building command messages (``SEQ``,
  12627. +``RQID``). This layer basically provides a fundamental interface to the SAM
  12628. +EC for use in other kernel drivers.
  12629. +
  12630. +While the controller layer already provides an interface for other kernel
  12631. +drivers, the client *bus* extends this interface to provide support for
  12632. +native SSAM devices, i.e. devices that are not defined in ACPI and not
  12633. +implemented as platform devices, via |ssam_device| and |ssam_device_driver|
  12634. +simplify management of client devices and client drivers.
  12635. +
  12636. +Refer to :doc:`client` for documentation regarding the client device/driver
  12637. +API and interface options for other kernel drivers. It is recommended to
  12638. +familiarize oneself with that chapter and the :doc:`ssh` before continuing
  12639. +with the architectural overview below.
  12640. +
  12641. +
  12642. +Packet Transport Layer
  12643. +======================
  12644. +
  12645. +The packet transport layer is represented via |ssh_ptl| and is structured
  12646. +around the following key concepts:
  12647. +
  12648. +Packets
  12649. +-------
  12650. +
  12651. +Packets are the fundamental transmission unit of the SSH protocol. They are
  12652. +managed by the packet transport layer, which is essentially the lowest layer
  12653. +of the driver and is built upon by other components of the SSAM core.
  12654. +Packets to be transmitted by the SSAM core are represented via |ssh_packet|
  12655. +(in contrast, packets received by the core do not have any specific
  12656. +structure and are managed entirely via the raw |ssh_frame|).
  12657. +
  12658. +This structure contains the required fields to manage the packet inside the
  12659. +transport layer, as well as a reference to the buffer containing the data to
  12660. +be transmitted (i.e. the message wrapped in |ssh_frame|). Most notably, it
  12661. +contains an internal reference count, which is used for managing its
  12662. +lifetime (accessible via |ssh_packet_get| and |ssh_packet_put|). When this
  12663. +counter reaches zero, the ``release()`` callback provided to the packet via
  12664. +its |ssh_packet_ops| reference is executed, which may then deallocate the
  12665. +packet or its enclosing structure (e.g. |ssh_request|).
  12666. +
  12667. +In addition to the ``release`` callback, the |ssh_packet_ops| reference also
  12668. +provides a ``complete()`` callback, which is run once the packet has been
  12669. +completed and provides the status of this completion, i.e. zero on success
  12670. +or a negative errno value in case of an error. Once the packet has been
  12671. +submitted to the packet transport layer, the ``complete()`` callback is
  12672. +always guaranteed to be executed before the ``release()`` callback, i.e. the
  12673. +packet will always be completed, either successfully, with an error, or due
  12674. +to cancellation, before it will be released.
  12675. +
  12676. +The state of a packet is managed via its ``state`` flags
  12677. +(|ssh_packet_flags|), which also contains the packet type. In particular,
  12678. +the following bits are noteworthy:
  12679. +
  12680. +* ``SSH_PACKET_SF_LOCKED_BIT``: This bit is set when completion, either
  12681. + through error or success, is imminent. It indicates that no further
  12682. + references of the packet should be taken and any existing references
  12683. + should be dropped as soon as possible. The process setting this bit is
  12684. + responsible for removing any references to this packet from the packet
  12685. + queue and pending set.
  12686. +
  12687. +* ``SSH_PACKET_SF_COMPLETED_BIT``: This bit is set by the process running the
  12688. + ``complete()`` callback and is used to ensure that this callback only runs
  12689. + once.
  12690. +
  12691. +* ``SSH_PACKET_SF_QUEUED_BIT``: This bit is set when the packet is queued on
  12692. + the packet queue and cleared when it is dequeued.
  12693. +
  12694. +* ``SSH_PACKET_SF_PENDING_BIT``: This bit is set when the packet is added to
  12695. + the pending set and cleared when it is removed from it.
  12696. +
  12697. +Packet Queue
  12698. +------------
  12699. +
  12700. +The packet queue is the first of the two fundamental collections in the
  12701. +packet transport layer. It is a priority queue, with priority of the
  12702. +respective packets based on the packet type (major) and number of tries
  12703. +(minor). See |SSH_PACKET_PRIORITY| for more details on the priority value.
  12704. +
  12705. +All packets to be transmitted by the transport layer must be submitted to
  12706. +this queue via |ssh_ptl_submit|. Note that this includes control packets
  12707. +sent by the transport layer itself. Internally, data packets can be
  12708. +re-submitted to this queue due to timeouts or NAK packets sent by the EC.
  12709. +
  12710. +Pending Set
  12711. +-----------
  12712. +
  12713. +The pending set is the second of the two fundamental collections in the
  12714. +packet transport layer. It stores references to packets that have already
  12715. +been transmitted, but wait for acknowledgment (e.g. the corresponding ACK
  12716. +packet) by the EC.
  12717. +
  12718. +Note that a packet may both be pending and queued if it has been
  12719. +re-submitted due to a packet acknowledgment timeout or NAK. On such a
  12720. +re-submission, packets are not removed from the pending set.
  12721. +
  12722. +Transmitter Thread
  12723. +------------------
  12724. +
  12725. +The transmitter thread is responsible for most of the actual work regarding
  12726. +packet transmission. In each iteration, it (waits for and) checks if the
  12727. +next packet on the queue (if any) can be transmitted and, if so, removes it
  12728. +from the queue and increments its counter for the number of transmission
  12729. +attempts, i.e. tries. If the packet is sequenced, i.e. requires an ACK by
  12730. +the EC, the packet is added to the pending set. Next, the packet's data is
  12731. +submitted to the serdev subsystem. In case of an error or timeout during
  12732. +this submission, the packet is completed by the transmitter thread with the
  12733. +status value of the callback set accordingly. In case the packet is
  12734. +unsequenced, i.e. does not require an ACK by the EC, the packet is completed
  12735. +with success on the transmitter thread.
  12736. +
  12737. +Transmission of sequenced packets is limited by the number of concurrently
  12738. +pending packets, i.e. a limit on how many packets may be waiting for an ACK
  12739. +from the EC in parallel. This limit is currently set to one (see :doc:`ssh`
  12740. +for the reasoning behind this). Control packets (i.e. ACK and NAK) can
  12741. +always be transmitted.
  12742. +
  12743. +Receiver Thread
  12744. +---------------
  12745. +
  12746. +Any data received from the EC is put into a FIFO buffer for further
  12747. +processing. This processing happens on the receiver thread. The receiver
  12748. +thread parses and validates the received message into its |ssh_frame| and
  12749. +corresponding payload. It prepares and submits the necessary ACK (and on
  12750. +validation error or invalid data NAK) packets for the received messages.
  12751. +
  12752. +This thread also handles further processing, such as matching ACK messages
  12753. +to the corresponding pending packet (via sequence ID) and completing it, as
  12754. +well as initiating re-submission of all currently pending packets on
  12755. +receival of a NAK message (re-submission in case of a NAK is similar to
  12756. +re-submission due to timeout, see below for more details on that). Note that
  12757. +the successful completion of a sequenced packet will always run on the
  12758. +receiver thread (whereas any failure-indicating completion will run on the
  12759. +process where the failure occurred).
  12760. +
  12761. +Any payload data is forwarded via a callback to the next upper layer, i.e.
  12762. +the request transport layer.
  12763. +
  12764. +Timeout Reaper
  12765. +--------------
  12766. +
  12767. +The packet acknowledgment timeout is a per-packet timeout for sequenced
  12768. +packets, started when the respective packet begins (re-)transmission (i.e.
  12769. +this timeout is armed once per transmission attempt on the transmitter
  12770. +thread). It is used to trigger re-submission or, when the number of tries
  12771. +has been exceeded, cancellation of the packet in question.
  12772. +
  12773. +This timeout is handled via a dedicated reaper task, which is essentially a
  12774. +work item (re-)scheduled to run when the next packet is set to time out. The
  12775. +work item then checks the set of pending packets for any packets that have
  12776. +exceeded the timeout and, if there are any remaining packets, re-schedules
  12777. +itself to the next appropriate point in time.
  12778. +
  12779. +If a timeout has been detected by the reaper, the packet will either be
  12780. +re-submitted if it still has some remaining tries left, or completed with
  12781. +``-ETIMEDOUT`` as status if not. Note that re-submission, in this case and
  12782. +triggered by receival of a NAK, means that the packet is added to the queue
  12783. +with a now incremented number of tries, yielding a higher priority. The
  12784. +timeout for the packet will be disabled until the next transmission attempt
  12785. +and the packet remains on the pending set.
  12786. +
  12787. +Note that due to transmission and packet acknowledgment timeouts, the packet
  12788. +transport layer is always guaranteed to make progress, if only through
  12789. +timing out packets, and will never fully block.
  12790. +
  12791. +Concurrency and Locking
  12792. +-----------------------
  12793. +
  12794. +There are two main locks in the packet transport layer: One guarding access
  12795. +to the packet queue and one guarding access to the pending set. These
  12796. +collections may only be accessed and modified under the respective lock. If
  12797. +access to both collections is needed, the pending lock must be acquired
  12798. +before the queue lock to avoid deadlocks.
  12799. +
  12800. +In addition to guarding the collections, after initial packet submission
  12801. +certain packet fields may only be accessed under one of the locks.
  12802. +Specifically, the packet priority must only be accessed while holding the
  12803. +queue lock and the packet timestamp must only be accessed while holding the
  12804. +pending lock.
  12805. +
  12806. +Other parts of the packet transport layer are guarded independently. State
  12807. +flags are managed by atomic bit operations and, if necessary, memory
  12808. +barriers. Modifications to the timeout reaper work item and expiration date
  12809. +are guarded by their own lock.
  12810. +
  12811. +The reference of the packet to the packet transport layer (``ptl``) is
  12812. +somewhat special. It is either set when the upper layer request is submitted
  12813. +or, if there is none, when the packet is first submitted. After it is set,
  12814. +it will not change its value. Functions that may run concurrently with
  12815. +submission, i.e. cancellation, can not rely on the ``ptl`` reference to be
  12816. +set. Access to it in these functions is guarded by ``READ_ONCE()``, whereas
  12817. +setting ``ptl`` is equally guarded with ``WRITE_ONCE()`` for symmetry.
  12818. +
  12819. +Some packet fields may be read outside of the respective locks guarding
  12820. +them, specifically priority and state for tracing. In those cases, proper
  12821. +access is ensured by employing ``WRITE_ONCE()`` and ``READ_ONCE()``. Such
  12822. +read-only access is only allowed when stale values are not critical.
  12823. +
  12824. +With respect to the interface for higher layers, packet submission
  12825. +(|ssh_ptl_submit|), packet cancellation (|ssh_ptl_cancel|), data receival
  12826. +(|ssh_ptl_rx_rcvbuf|), and layer shutdown (|ssh_ptl_shutdown|) may always be
  12827. +executed concurrently with respect to each other. Note that packet
  12828. +submission may not run concurrently with itself for the same packet.
  12829. +Equally, shutdown and data receival may also not run concurrently with
  12830. +themselves (but may run concurrently with each other).
  12831. +
  12832. +
  12833. +Request Transport Layer
  12834. +=======================
  12835. +
  12836. +The request transport layer is represented via |ssh_rtl| and builds on top
  12837. +of the packet transport layer. It deals with requests, i.e. SSH packets sent
  12838. +by the host containing a |ssh_command| as frame payload. This layer
  12839. +separates responses to requests from events, which are also sent by the EC
  12840. +via a |ssh_command| payload. While responses are handled in this layer,
  12841. +events are relayed to the next upper layer, i.e. the controller layer, via
  12842. +the corresponding callback. The request transport layer is structured around
  12843. +the following key concepts:
  12844. +
  12845. +Request
  12846. +-------
  12847. +
  12848. +Requests are packets with a command-type payload, sent from host to EC to
  12849. +query data from or trigger an action on it (or both simultaneously). They
  12850. +are represented by |ssh_request|, wrapping the underlying |ssh_packet|
  12851. +storing its message data (i.e. SSH frame with command payload). Note that
  12852. +all top-level representations, e.g. |ssam_request_sync| are built upon this
  12853. +struct.
  12854. +
  12855. +As |ssh_request| extends |ssh_packet|, its lifetime is also managed by the
  12856. +reference counter inside the packet struct (which can be accessed via
  12857. +|ssh_request_get| and |ssh_request_put|). Once the counter reaches zero, the
  12858. +``release()`` callback of the |ssh_request_ops| reference of the request is
  12859. +called.
  12860. +
  12861. +Requests can have an optional response that is equally sent via a SSH
  12862. +message with command-type payload (from EC to host). The party constructing
  12863. +the request must know if a response is expected and mark this in the request
  12864. +flags provided to |ssh_request_init|, so that the request transport layer
  12865. +can wait for this response.
  12866. +
  12867. +Similar to |ssh_packet|, |ssh_request| also has a ``complete()`` callback
  12868. +provided via its request ops reference and is guaranteed to be completed
  12869. +before it is released once it has been submitted to the request transport
  12870. +layer via |ssh_rtl_submit|. For a request without a response, successful
  12871. +completion will occur once the underlying packet has been successfully
  12872. +transmitted by the packet transport layer (i.e. from within the packet
  12873. +completion callback). For a request with response, successful completion
  12874. +will occur once the response has been received and matched to the request
  12875. +via its request ID (which happens on the packet layer's data-received
  12876. +callback running on the receiver thread). If the request is completed with
  12877. +an error, the status value will be set to the corresponding (negative) errno
  12878. +value.
  12879. +
  12880. +The state of a request is again managed via its ``state`` flags
  12881. +(|ssh_request_flags|), which also encode the request type. In particular,
  12882. +the following bits are noteworthy:
  12883. +
  12884. +* ``SSH_REQUEST_SF_LOCKED_BIT``: This bit is set when completion, either
  12885. + through error or success, is imminent. It indicates that no further
  12886. + references of the request should be taken and any existing references
  12887. + should be dropped as soon as possible. The process setting this bit is
  12888. + responsible for removing any references to this request from the request
  12889. + queue and pending set.
  12890. +
  12891. +* ``SSH_REQUEST_SF_COMPLETED_BIT``: This bit is set by the process running the
  12892. + ``complete()`` callback and is used to ensure that this callback only runs
  12893. + once.
  12894. +
  12895. +* ``SSH_REQUEST_SF_QUEUED_BIT``: This bit is set when the request is queued on
  12896. + the request queue and cleared when it is dequeued.
  12897. +
  12898. +* ``SSH_REQUEST_SF_PENDING_BIT``: This bit is set when the request is added to
  12899. + the pending set and cleared when it is removed from it.
  12900. +
  12901. +Request Queue
  12902. +-------------
  12903. +
  12904. +The request queue is the first of the two fundamental collections in the
  12905. +request transport layer. In contrast to the packet queue of the packet
  12906. +transport layer, it is not a priority queue and the simple first come first
  12907. +serve principle applies.
  12908. +
  12909. +All requests to be transmitted by the request transport layer must be
  12910. +submitted to this queue via |ssh_rtl_submit|. Once submitted, requests may
  12911. +not be re-submitted, and will not be re-submitted automatically on timeout.
  12912. +Instead, the request is completed with a timeout error. If desired, the
  12913. +caller can create and submit a new request for another try, but it must not
  12914. +submit the same request again.
  12915. +
  12916. +Pending Set
  12917. +-----------
  12918. +
  12919. +The pending set is the second of the two fundamental collections in the
  12920. +request transport layer. This collection stores references to all pending
  12921. +requests, i.e. requests awaiting a response from the EC (similar to what the
  12922. +pending set of the packet transport layer does for packets).
  12923. +
  12924. +Transmitter Task
  12925. +----------------
  12926. +
  12927. +The transmitter task is scheduled when a new request is available for
  12928. +transmission. It checks if the next request on the request queue can be
  12929. +transmitted and, if so, submits its underlying packet to the packet
  12930. +transport layer. This check ensures that only a limited number of
  12931. +requests can be pending, i.e. waiting for a response, at the same time. If
  12932. +the request requires a response, the request is added to the pending set
  12933. +before its packet is submitted.
  12934. +
  12935. +Packet Completion Callback
  12936. +--------------------------
  12937. +
  12938. +The packet completion callback is executed once the underlying packet of a
  12939. +request has been completed. In case of an error completion, the
  12940. +corresponding request is completed with the error value provided in this
  12941. +callback.
  12942. +
  12943. +On successful packet completion, further processing depends on the request.
  12944. +If the request expects a response, it is marked as transmitted and the
  12945. +request timeout is started. If the request does not expect a response, it is
  12946. +completed with success.
  12947. +
  12948. +Data-Received Callback
  12949. +----------------------
  12950. +
  12951. +The data received callback notifies the request transport layer of data
  12952. +being received by the underlying packet transport layer via a data-type
  12953. +frame. In general, this is expected to be a command-type payload.
  12954. +
  12955. +If the request ID of the command is one of the request IDs reserved for
  12956. +events (one to ``SSH_NUM_EVENTS``, inclusively), it is forwarded to the
  12957. +event callback registered in the request transport layer. If the request ID
  12958. +indicates a response to a request, the respective request is looked up in
  12959. +the pending set and, if found and marked as transmitted, completed with
  12960. +success.
  12961. +
  12962. +Timeout Reaper
  12963. +--------------
  12964. +
  12965. +The request-response-timeout is a per-request timeout for requests expecting
  12966. +a response. It is used to ensure that a request does not wait indefinitely
  12967. +on a response from the EC and is started after the underlying packet has
  12968. +been successfully completed.
  12969. +
  12970. +This timeout is, similar to the packet acknowledgment timeout on the packet
  12971. +transport layer, handled via a dedicated reaper task. This task is
  12972. +essentially a work-item (re-)scheduled to run when the next request is set
  12973. +to time out. The work item then scans the set of pending requests for any
  12974. +requests that have timed out and completes them with ``-ETIMEDOUT`` as
  12975. +status. Requests will not be re-submitted automatically. Instead, the issuer
  12976. +of the request must construct and submit a new request, if so desired.
  12977. +
  12978. +Note that this timeout, in combination with packet transmission and
  12979. +acknowledgment timeouts, guarantees that the request layer will always make
  12980. +progress, even if only through timing out packets, and never fully block.
  12981. +
  12982. +Concurrency and Locking
  12983. +-----------------------
  12984. +
  12985. +Similar to the packet transport layer, there are two main locks in the
  12986. +request transport layer: One guarding access to the request queue and one
  12987. +guarding access to the pending set. These collections may only be accessed
  12988. +and modified under the respective lock.
  12989. +
  12990. +Other parts of the request transport layer are guarded independently. State
  12991. +flags are (again) managed by atomic bit operations and, if necessary, memory
  12992. +barriers. Modifications to the timeout reaper work item and expiration date
  12993. +are guarded by their own lock.
  12994. +
  12995. +Some request fields may be read outside of the respective locks guarding
  12996. +them, specifically the state for tracing. In those cases, proper access is
  12997. +ensured by employing ``WRITE_ONCE()`` and ``READ_ONCE()``. Such read-only
  12998. +access is only allowed when stale values are not critical.
  12999. +
  13000. +With respect to the interface for higher layers, request submission
  13001. +(|ssh_rtl_submit|), request cancellation (|ssh_rtl_cancel|), and layer
  13002. +shutdown (|ssh_rtl_shutdown|) may always be executed concurrently with
  13003. +respect to each other. Note that request submission may not run concurrently
  13004. +with itself for the same request (and also may only be called once per
  13005. +request). Equally, shutdown may also not run concurrently with itself.
  13006. +
  13007. +
  13008. +Controller Layer
  13009. +================
  13010. +
  13011. +The controller layer extends on the request transport layer to provide an
  13012. +easy-to-use interface for client drivers. It is represented by
  13013. +|ssam_controller| and the SSH driver. While the lower level transport layers
  13014. +take care of transmitting and handling packets and requests, the controller
  13015. +layer takes on more of a management role. Specifically, it handles device
  13016. +initialization, power management, and event handling, including event
  13017. +delivery and registration via the (event) completion system (|ssam_cplt|).
  13018. +
  13019. +Event Registration
  13020. +------------------
  13021. +
  13022. +In general, an event (or rather a class of events) has to be explicitly
  13023. +requested by the host before the EC will send it (HID input events seem to
  13024. +be the exception). This is done via an event-enable request (similarly,
  13025. +events should be disabled via an event-disable request once no longer
  13026. +desired).
  13027. +
  13028. +The specific request used to enable (or disable) an event is given via an
  13029. +event registry, i.e. the governing authority of this event (so to speak),
  13030. +represented by |ssam_event_registry|. As parameters to this request, the
  13031. +target category and, depending on the event registry, instance ID of the
  13032. +event to be enabled must be provided. This (optional) instance ID must be
  13033. +zero if the registry does not use it. Together, target category and instance
  13034. +ID form the event ID, represented by |ssam_event_id|. In short, both, event
  13035. +registry and event ID, are required to uniquely identify a respective class
  13036. +of events.
  13037. +
  13038. +Note that a further *request ID* parameter must be provided for the
  13039. +enable-event request. This parameter does not influence the class of events
  13040. +being enabled, but instead is set as the request ID (RQID) on each event of
  13041. +this class sent by the EC. It is used to identify events (as a limited
  13042. +number of request IDs is reserved for use in events only, specifically one
  13043. +to ``SSH_NUM_EVENTS`` inclusively) and also map events to their specific
  13044. +class. Currently, the controller always sets this parameter to the target
  13045. +category specified in |ssam_event_id|.
  13046. +
  13047. +As multiple client drivers may rely on the same (or overlapping) classes of
  13048. +events and enable/disable calls are strictly binary (i.e. on/off), the
  13049. +controller has to manage access to these events. It does so via reference
  13050. +counting, storing the counter inside an RB-tree based mapping with event
  13051. +registry and ID as key (there is no known list of valid event registry and
  13052. +event ID combinations). See |ssam_nf|, |ssam_nf_refcount_inc|, and
  13053. +|ssam_nf_refcount_dec| for details.
  13054. +
  13055. +This management is done together with notifier registration (described in
  13056. +the next section) via the top-level |ssam_notifier_register| and
  13057. +|ssam_notifier_unregister| functions.
  13058. +
  13059. +Event Delivery
  13060. +--------------
  13061. +
  13062. +To receive events, a client driver has to register an event notifier via
  13063. +|ssam_notifier_register|. This increments the reference counter for that
  13064. +specific class of events (as detailed in the previous section), enables the
  13065. +class on the EC (if it has not been enabled already), and installs the
  13066. +provided notifier callback.
  13067. +
  13068. +Notifier callbacks are stored in lists, with one (RCU) list per target
  13069. +category (provided via the event ID; NB: there is a fixed known number of
  13070. +target categories). There is no known association from the combination of
  13071. +event registry and event ID to the command data (target ID, target category,
  13072. +command ID, and instance ID) that can be provided by an event class, apart
  13073. +from target category and instance ID given via the event ID.
  13074. +
  13075. +Note that due to the way notifiers are (or rather have to be) stored, client
  13076. +drivers may receive events that they have not requested and need to account
  13077. +for them. Specifically, they will, by default, receive all events from the
  13078. +same target category. To simplify dealing with this, filtering of events by
  13079. +target ID (provided via the event registry) and instance ID (provided via
  13080. +the event ID) can be requested when registering a notifier. This filtering
  13081. +is applied when iterating over the notifiers at the time they are executed.
  13082. +
  13083. +All notifier callbacks are executed on a dedicated workqueue, the so-called
  13084. +completion workqueue. After an event has been received via the callback
  13085. +installed in the request layer (running on the receiver thread of the packet
  13086. +transport layer), it will be put on its respective event queue
  13087. +(|ssam_event_queue|). From this event queue the completion work item of that
  13088. +queue (running on the completion workqueue) will pick up the event and
  13089. +execute the notifier callback. This is done to avoid blocking on the
  13090. +receiver thread.
  13091. +
  13092. +There is one event queue per combination of target ID and target category.
  13093. +This is done to ensure that notifier callbacks are executed in sequence for
  13094. +events of the same target ID and target category. Callbacks can be executed
  13095. +in parallel for events with a different combination of target ID and target
  13096. +category.
  13097. +
  13098. +Concurrency and Locking
  13099. +-----------------------
  13100. +
  13101. +Most of the concurrency related safety guarantees of the controller are
  13102. +provided by the lower-level request transport layer. In addition to this,
  13103. +event (un-)registration is guarded by its own lock.
  13104. +
  13105. +Access to the controller state is guarded by the state lock. This lock is a
  13106. +read/write semaphore. The reader part can be used to ensure that the state
  13107. +does not change while functions depending on the state to stay the same
  13108. +(e.g. |ssam_notifier_register|, |ssam_notifier_unregister|,
  13109. +|ssam_request_sync_submit|, and derivatives) are executed and this guarantee
  13110. +is not already provided otherwise (e.g. through |ssam_client_bind| or
  13111. +|ssam_client_link|). The writer part guards any transitions that will change
  13112. +the state, i.e. initialization, destruction, suspension, and resumption.
  13113. +
  13114. +The controller state may be accessed (read-only) outside the state lock for
  13115. +smoke-testing against invalid API usage (e.g. in |ssam_request_sync_submit|).
  13116. +Note that such checks are not supposed to (and will not) protect against all
  13117. +invalid usages, but rather aim to help catch them. In those cases, proper
  13118. +variable access is ensured by employing ``WRITE_ONCE()`` and ``READ_ONCE()``.
  13119. +
  13120. +Assuming any preconditions on the state not changing have been satisfied,
  13121. +all non-initialization and non-shutdown functions may run concurrently with
  13122. +each other. This includes |ssam_notifier_register|, |ssam_notifier_unregister|,
  13123. +|ssam_request_sync_submit|, as well as all functions building on top of those.
  13124. diff --git a/Documentation/driver-api/surface_aggregator/overview.rst b/Documentation/driver-api/surface_aggregator/overview.rst
  13125. new file mode 100644
  13126. index 000000000000..1e9d57e50063
  13127. --- /dev/null
  13128. +++ b/Documentation/driver-api/surface_aggregator/overview.rst
  13129. @@ -0,0 +1,77 @@
  13130. +.. SPDX-License-Identifier: GPL-2.0+
  13131. +
  13132. +========
  13133. +Overview
  13134. +========
  13135. +
  13136. +The Surface/System Aggregator Module (SAM, SSAM) is an (arguably *the*)
  13137. +embedded controller (EC) on Microsoft Surface devices. It has been originally
  13138. +introduced on 4th generation devices (Surface Pro 4, Surface Book 1), but
  13139. +its responsibilities and feature-set have since been expanded significantly
  13140. +with the following generations.
  13141. +
  13142. +
  13143. +Features and Integration
  13144. +========================
  13145. +
  13146. +Not much is currently known about SAM on 4th generation devices (Surface Pro
  13147. +4, Surface Book 1), due to the use of a different communication interface
  13148. +between host and EC (as detailed below). On 5th (Surface Pro 2017, Surface
  13149. +Book 2, Surface Laptop 1) and later generation devices, SAM is responsible
  13150. +for providing battery information (both current status and static values,
  13151. +such as maximum capacity etc.), as well as an assortment of temperature
  13152. +sensors (e.g. skin temperature) and cooling/performance-mode setting to the
  13153. +host. On the Surface Book 2, specifically, it additionally provides an
  13154. +interface for properly handling clipboard detachment (i.e. separating the
  13155. +display part from the keyboard part of the device), on the Surface Laptop 1
  13156. +and 2 it is required for keyboard HID input. This HID subsystem has been
  13157. +restructured for 7th generation devices and on those, specifically Surface
  13158. +Laptop 3 and Surface Book 3, is responsible for all major HID input (i.e.
  13159. +keyboard and touchpad).
  13160. +
  13161. +While features have not changed much on a coarse level since the 5th
  13162. +generation, internal interfaces have undergone some rather large changes. On
  13163. +5th and 6th generation devices, both battery and temperature information is
  13164. +exposed to ACPI via a shim driver (referred to as Surface ACPI Notify, or
  13165. +SAN), translating ACPI generic serial bus write-/read-accesses to SAM
  13166. +requests. On 7th generation devices, this additional layer is gone and these
  13167. +devices require a driver hooking directly into the SAM interface. Equally,
  13168. +on newer generations, less devices are declared in ACPI, making them a bit
  13169. +harder to discover and requiring us to hard-code a sort of device registry.
  13170. +Due to this, a SSAM bus and subsystem with client devices
  13171. +(:c:type:`struct ssam_device <ssam_device>`) has been implemented.
  13172. +
  13173. +
  13174. +Communication
  13175. +=============
  13176. +
  13177. +The type of communication interface between host and EC depends on the
  13178. +generation of the Surface device. On 4th generation devices, host and EC
  13179. +communicate via HID, specifically using a HID-over-I2C device, whereas on
  13180. +5th and later generations, communication takes place via a USART serial
  13181. +device. In accordance to the drivers found on other operating systems, we
  13182. +refer to the serial device and its driver as Surface Serial Hub (SSH). When
  13183. +needed, we differentiate between both types of SAM by referring to them as
  13184. +SAM-over-SSH and SAM-over-HID.
  13185. +
  13186. +Currently, this subsystem only supports SAM-over-SSH. The SSH communication
  13187. +interface is described in more detail below. The HID interface has not been
  13188. +reverse engineered yet and it is, at the moment, unclear how many (and
  13189. +which) concepts of the SSH interface detailed below can be transferred to
  13190. +it.
  13191. +
  13192. +Surface Serial Hub
  13193. +------------------
  13194. +
  13195. +As already elaborated above, the Surface Serial Hub (SSH) is the
  13196. +communication interface for SAM on 5th- and all later-generation Surface
  13197. +devices. On the highest level, communication can be separated into two main
  13198. +types: Requests, messages sent from host to EC that may trigger a direct
  13199. +response from the EC (explicitly associated with the request), and events
  13200. +(sometimes also referred to as notifications), sent from EC to host without
  13201. +being a direct response to a previous request. We may also refer to requests
  13202. +without response as commands. In general, events need to be enabled via one
  13203. +of multiple dedicated requests before they are sent by the EC.
  13204. +
  13205. +See :doc:`ssh` for a more technical protocol documentation and
  13206. +:doc:`internal` for an overview of the internal driver architecture.
  13207. diff --git a/Documentation/driver-api/surface_aggregator/ssh.rst b/Documentation/driver-api/surface_aggregator/ssh.rst
  13208. new file mode 100644
  13209. index 000000000000..bf007d6c9873
  13210. --- /dev/null
  13211. +++ b/Documentation/driver-api/surface_aggregator/ssh.rst
  13212. @@ -0,0 +1,344 @@
  13213. +.. SPDX-License-Identifier: GPL-2.0+
  13214. +
  13215. +.. |u8| replace:: :c:type:`u8 <u8>`
  13216. +.. |u16| replace:: :c:type:`u16 <u16>`
  13217. +.. |TYPE| replace:: ``TYPE``
  13218. +.. |LEN| replace:: ``LEN``
  13219. +.. |SEQ| replace:: ``SEQ``
  13220. +.. |SYN| replace:: ``SYN``
  13221. +.. |NAK| replace:: ``NAK``
  13222. +.. |ACK| replace:: ``ACK``
  13223. +.. |DATA| replace:: ``DATA``
  13224. +.. |DATA_SEQ| replace:: ``DATA_SEQ``
  13225. +.. |DATA_NSQ| replace:: ``DATA_NSQ``
  13226. +.. |TC| replace:: ``TC``
  13227. +.. |TID| replace:: ``TID``
  13228. +.. |IID| replace:: ``IID``
  13229. +.. |RQID| replace:: ``RQID``
  13230. +.. |CID| replace:: ``CID``
  13231. +
  13232. +===========================
  13233. +Surface Serial Hub Protocol
  13234. +===========================
  13235. +
  13236. +The Surface Serial Hub (SSH) is the central communication interface for the
  13237. +embedded Surface Aggregator Module controller (SAM or EC), found on newer
  13238. +Surface generations. We will refer to this protocol and interface as
  13239. +SAM-over-SSH, as opposed to SAM-over-HID for the older generations.
  13240. +
  13241. +On Surface devices with SAM-over-SSH, SAM is connected to the host via UART
  13242. +and defined in ACPI as device with ID ``MSHW0084``. On these devices,
  13243. +significant functionality is provided via SAM, including access to battery
  13244. +and power information and events, thermal read-outs and events, and many
  13245. +more. For Surface Laptops, keyboard input is handled via HID directed
  13246. +through SAM, on the Surface Laptop 3 and Surface Book 3 this also includes
  13247. +touchpad input.
  13248. +
  13249. +Note that the standard disclaimer for this subsystem also applies to this
  13250. +document: All of this has been reverse-engineered and may thus be erroneous
  13251. +and/or incomplete.
  13252. +
  13253. +All CRCs used in the following are two-byte ``crc_ccitt_false(0xffff, ...)``.
  13254. +All multi-byte values are little-endian, there is no implicit padding between
  13255. +values.
  13256. +
  13257. +
  13258. +SSH Packet Protocol: Definitions
  13259. +================================
  13260. +
  13261. +The fundamental communication unit of the SSH protocol is a frame
  13262. +(:c:type:`struct ssh_frame <ssh_frame>`). A frame consists of the following
  13263. +fields, packed together and in order:
  13264. +
  13265. +.. flat-table:: SSH Frame
  13266. + :widths: 1 1 4
  13267. + :header-rows: 1
  13268. +
  13269. + * - Field
  13270. + - Type
  13271. + - Description
  13272. +
  13273. + * - |TYPE|
  13274. + - |u8|
  13275. + - Type identifier of the frame.
  13276. +
  13277. + * - |LEN|
  13278. + - |u16|
  13279. + - Length of the payload associated with the frame.
  13280. +
  13281. + * - |SEQ|
  13282. + - |u8|
  13283. + - Sequence ID (see explanation below).
  13284. +
  13285. +Each frame structure is followed by a CRC over this structure. The CRC over
  13286. +the frame structure (|TYPE|, |LEN|, and |SEQ| fields) is placed directly
  13287. +after the frame structure and before the payload. The payload is followed by
  13288. +its own CRC (over all payload bytes). If the payload is not present (i.e.
  13289. +the frame has ``LEN=0``), the CRC of the payload is still present and will
  13290. +evaluate to ``0xffff``. The |LEN| field does not include any of the CRCs, it
  13291. +equals the number of bytes inbetween the CRC of the frame and the CRC of the
  13292. +payload.
  13293. +
  13294. +Additionally, the following fixed two-byte sequences are used:
  13295. +
  13296. +.. flat-table:: SSH Byte Sequences
  13297. + :widths: 1 1 4
  13298. + :header-rows: 1
  13299. +
  13300. + * - Name
  13301. + - Value
  13302. + - Description
  13303. +
  13304. + * - |SYN|
  13305. + - ``[0xAA, 0x55]``
  13306. + - Synchronization bytes.
  13307. +
  13308. +A message consists of |SYN|, followed by the frame (|TYPE|, |LEN|, |SEQ| and
  13309. +CRC) and, if specified in the frame (i.e. ``LEN > 0``), payload bytes,
  13310. +followed finally, regardless if the payload is present, the payload CRC. The
  13311. +messages corresponding to an exchange are, in part, identified by having the
  13312. +same sequence ID (|SEQ|), stored inside the frame (more on this in the next
  13313. +section). The sequence ID is a wrapping counter.
  13314. +
  13315. +A frame can have the following types
  13316. +(:c:type:`enum ssh_frame_type <ssh_frame_type>`):
  13317. +
  13318. +.. flat-table:: SSH Frame Types
  13319. + :widths: 1 1 4
  13320. + :header-rows: 1
  13321. +
  13322. + * - Name
  13323. + - Value
  13324. + - Short Description
  13325. +
  13326. + * - |NAK|
  13327. + - ``0x04``
  13328. + - Sent on error in previously received message.
  13329. +
  13330. + * - |ACK|
  13331. + - ``0x40``
  13332. + - Sent to acknowledge receival of |DATA| frame.
  13333. +
  13334. + * - |DATA_SEQ|
  13335. + - ``0x80``
  13336. + - Sent to transfer data. Sequenced.
  13337. +
  13338. + * - |DATA_NSQ|
  13339. + - ``0x00``
  13340. + - Same as |DATA_SEQ|, but does not need to be ACKed.
  13341. +
  13342. +Both |NAK|- and |ACK|-type frames are used to control flow of messages and
  13343. +thus do not carry a payload. |DATA_SEQ|- and |DATA_NSQ|-type frames on the
  13344. +other hand must carry a payload. The flow sequence and interaction of
  13345. +different frame types will be described in more depth in the next section.
  13346. +
  13347. +
  13348. +SSH Packet Protocol: Flow Sequence
  13349. +==================================
  13350. +
  13351. +Each exchange begins with |SYN|, followed by a |DATA_SEQ|- or
  13352. +|DATA_NSQ|-type frame, followed by its CRC, payload, and payload CRC. In
  13353. +case of a |DATA_NSQ|-type frame, the exchange is then finished. In case of a
  13354. +|DATA_SEQ|-type frame, the receiving party has to acknowledge receival of
  13355. +the frame by responding with a message containing an |ACK|-type frame with
  13356. +the same sequence ID of the |DATA| frame. In other words, the sequence ID of
  13357. +the |ACK| frame specifies the |DATA| frame to be acknowledged. In case of an
  13358. +error, e.g. an invalid CRC, the receiving party responds with a message
  13359. +containing an |NAK|-type frame. As the sequence ID of the previous data
  13360. +frame, for which an error is indicated via the |NAK| frame, cannot be relied
  13361. +upon, the sequence ID of the |NAK| frame should not be used and is set to
  13362. +zero. After receival of an |NAK| frame, the sending party should re-send all
  13363. +outstanding (non-ACKed) messages.
  13364. +
  13365. +Sequence IDs are not synchronized between the two parties, meaning that they
  13366. +are managed independently for each party. Identifying the messages
  13367. +corresponding to a single exchange thus relies on the sequence ID as well as
  13368. +the type of the message, and the context. Specifically, the sequence ID is
  13369. +used to associate an ``ACK`` with its ``DATA_SEQ``-type frame, but not
  13370. +``DATA_SEQ``- or ``DATA_NSQ``-type frames with other ``DATA``- type frames.
  13371. +
  13372. +An example exchange might look like this:
  13373. +
  13374. +::
  13375. +
  13376. + tx: -- SYN FRAME(D) CRC(F) PAYLOAD CRC(P) -----------------------------
  13377. + rx: ------------------------------------- SYN FRAME(A) CRC(F) CRC(P) --
  13378. +
  13379. +where both frames have the same sequence ID (``SEQ``). Here, ``FRAME(D)``
  13380. +indicates a |DATA_SEQ|-type frame, ``FRAME(A)`` an ``ACK``-type frame,
  13381. +``CRC(F)`` the CRC over the previous frame, ``CRC(P)`` the CRC over the
  13382. +previous payload. In case of an error, the exchange would look like this:
  13383. +
  13384. +::
  13385. +
  13386. + tx: -- SYN FRAME(D) CRC(F) PAYLOAD CRC(P) -----------------------------
  13387. + rx: ------------------------------------- SYN FRAME(N) CRC(F) CRC(P) --
  13388. +
  13389. +upon which the sender should re-send the message. ``FRAME(N)`` indicates an
  13390. +|NAK|-type frame. Note that the sequence ID of the |NAK|-type frame is fixed
  13391. +to zero. For |DATA_NSQ|-type frames, both exchanges are the same:
  13392. +
  13393. +::
  13394. +
  13395. + tx: -- SYN FRAME(DATA_NSQ) CRC(F) PAYLOAD CRC(P) ----------------------
  13396. + rx: -------------------------------------------------------------------
  13397. +
  13398. +Here, an error can be detected, but not corrected or indicated to the
  13399. +sending party. These exchanges are symmetric, i.e. switching ``rx`` and
  13400. +``tx`` results again in a valid exchange. Currently, no longer exchanges are
  13401. +known.
  13402. +
  13403. +
  13404. +Commands: Requests, Responses, and Events
  13405. +=========================================
  13406. +
  13407. +Commands are sent as payload inside a data frame. Currently, this is the
  13408. +only known payload type of |DATA| frames, with a payload-type value of
  13409. +``0x80`` (:c:type:`SSH_PLD_TYPE_CMD <ssh_payload_type>`).
  13410. +
  13411. +The command-type payload (:c:type:`struct ssh_command <ssh_command>`)
  13412. +consists of an eight-byte command structure, followed by optional and
  13413. +variable length command data. The length of this optional data is derived
  13414. +from the frame payload length given in the corresponding frame, i.e. it is
  13415. +``frame.len - sizeof(struct ssh_command)``. The command struct contains the
  13416. +following fields, packed together and in order:
  13417. +
  13418. +.. flat-table:: SSH Command
  13419. + :widths: 1 1 4
  13420. + :header-rows: 1
  13421. +
  13422. + * - Field
  13423. + - Type
  13424. + - Description
  13425. +
  13426. + * - |TYPE|
  13427. + - |u8|
  13428. + - Type of the payload. For commands always ``0x80``.
  13429. +
  13430. + * - |TC|
  13431. + - |u8|
  13432. + - Target category.
  13433. +
  13434. + * - |TID| (out)
  13435. + - |u8|
  13436. + - Target ID for outgoing (host to EC) commands.
  13437. +
  13438. + * - |TID| (in)
  13439. + - |u8|
  13440. + - Target ID for incoming (EC to host) commands.
  13441. +
  13442. + * - |IID|
  13443. + - |u8|
  13444. + - Instance ID.
  13445. +
  13446. + * - |RQID|
  13447. + - |u16|
  13448. + - Request ID.
  13449. +
  13450. + * - |CID|
  13451. + - |u8|
  13452. + - Command ID.
  13453. +
  13454. +The command struct and data, in general, does not contain any failure
  13455. +detection mechanism (e.g. CRCs), this is solely done on the frame level.
  13456. +
  13457. +Command-type payloads are used by the host to send commands and requests to
  13458. +the EC as well as by the EC to send responses and events back to the host.
  13459. +We differentiate between requests (sent by the host), responses (sent by the
  13460. +EC in response to a request), and events (sent by the EC without a preceding
  13461. +request).
  13462. +
  13463. +Commands and events are uniquely identified by their target category
  13464. +(``TC``) and command ID (``CID``). The target category specifies a general
  13465. +category for the command (e.g. system in general, vs. battery and AC, vs.
  13466. +temperature, and so on), while the command ID specifies the command inside
  13467. +that category. Only the combination of |TC| + |CID| is unique. Additionally,
  13468. +commands have an instance ID (``IID``), which is used to differentiate
  13469. +between different sub-devices. For example ``TC=3`` ``CID=1`` is a
  13470. +request to get the temperature on a thermal sensor, where |IID| specifies
  13471. +the respective sensor. If the instance ID is not used, it should be set to
  13472. +zero. If instance IDs are used, they, in general, start with a value of one,
  13473. +whereas zero may be used for instance independent queries, if applicable. A
  13474. +response to a request should have the same target category, command ID, and
  13475. +instance ID as the corresponding request.
  13476. +
  13477. +Responses are matched to their corresponding request via the request ID
  13478. +(``RQID``) field. This is a 16 bit wrapping counter similar to the sequence
  13479. +ID on the frames. Note that the sequence ID of the frames for a
  13480. +request-response pair does not match. Only the request ID has to match.
  13481. +Frame-protocol wise these are two separate exchanges, and may even be
  13482. +separated, e.g. by an event being sent after the request but before the
  13483. +response. Not all commands produce a response, and this is not detectable by
  13484. +|TC| + |CID|. It is the responsibility of the issuing party to wait for a
  13485. +response (or signal this to the communication framework, as is done in
  13486. +SAN/ACPI via the ``SNC`` flag).
  13487. +
  13488. +Events are identified by unique and reserved request IDs. These IDs should
  13489. +not be used by the host when sending a new request. They are used on the
  13490. +host to, first, detect events and, second, match them with a registered
  13491. +event handler. Request IDs for events are chosen by the host and directed to
  13492. +the EC when setting up and enabling an event source (via the
  13493. +enable-event-source request). The EC then uses the specified request ID for
  13494. +events sent from the respective source. Note that an event should still be
  13495. +identified by its target category, command ID, and, if applicable, instance
  13496. +ID, as a single event source can send multiple different event types. In
  13497. +general, however, a single target category should map to a single reserved
  13498. +event request ID.
  13499. +
  13500. +Furthermore, requests, responses, and events have an associated target ID
  13501. +(``TID``). This target ID is split into output (host to EC) and input (EC to
  13502. +host) fields, with the respecting other field (e.g. output field on incoming
  13503. +messages) set to zero. Two ``TID`` values are known: Primary (``0x01``) and
  13504. +secondary (``0x02``). In general, the response to a request should have the
  13505. +same ``TID`` value, however, the field (output vs. input) should be used in
  13506. +accordance to the direction in which the response is sent (i.e. on the input
  13507. +field, as responses are generally sent from the EC to the host).
  13508. +
  13509. +Note that, even though requests and events should be uniquely identifiable
  13510. +by target category and command ID alone, the EC may require specific
  13511. +target ID and instance ID values to accept a command. A command that is
  13512. +accepted for ``TID=1``, for example, may not be accepted for ``TID=2``
  13513. +and vice versa.
  13514. +
  13515. +
  13516. +Limitations and Observations
  13517. +============================
  13518. +
  13519. +The protocol can, in theory, handle up to ``U8_MAX`` frames in parallel,
  13520. +with up to ``U16_MAX`` pending requests (neglecting request IDs reserved for
  13521. +events). In practice, however, this is more limited. From our testing
  13522. +(although via a python and thus a user-space program), it seems that the EC
  13523. +can handle up to four requests (mostly) reliably in parallel at a certain
  13524. +time. With five or more requests in parallel, consistent discarding of
  13525. +commands (ACKed frame but no command response) has been observed. For five
  13526. +simultaneous commands, this reproducibly resulted in one command being
  13527. +dropped and four commands being handled.
  13528. +
  13529. +However, it has also been noted that, even with three requests in parallel,
  13530. +occasional frame drops happen. Apart from this, with a limit of three
  13531. +pending requests, no dropped commands (i.e. command being dropped but frame
  13532. +carrying command being ACKed) have been observed. In any case, frames (and
  13533. +possibly also commands) should be re-sent by the host if a certain timeout
  13534. +is exceeded. This is done by the EC for frames with a timeout of one second,
  13535. +up to two re-tries (i.e. three transmissions in total). The limit of
  13536. +re-tries also applies to received NAKs, and, in a worst case scenario, can
  13537. +lead to entire messages being dropped.
  13538. +
  13539. +While this also seems to work fine for pending data frames as long as no
  13540. +transmission failures occur, implementation and handling of these seems to
  13541. +depend on the assumption that there is only one non-acknowledged data frame.
  13542. +In particular, the detection of repeated frames relies on the last sequence
  13543. +number. This means that, if a frame that has been successfully received by
  13544. +the EC is sent again, e.g. due to the host not receiving an |ACK|, the EC
  13545. +will only detect this if it has the sequence ID of the last frame received
  13546. +by the EC. As an example: Sending two frames with ``SEQ=0`` and ``SEQ=1``
  13547. +followed by a repetition of ``SEQ=0`` will not detect the second ``SEQ=0``
  13548. +frame as such, and thus execute the command in this frame each time it has
  13549. +been received, i.e. twice in this example. Sending ``SEQ=0``, ``SEQ=1`` and
  13550. +then repeating ``SEQ=1`` will detect the second ``SEQ=1`` as repetition of
  13551. +the first one and ignore it, thus executing the contained command only once.
  13552. +
  13553. +In conclusion, this suggests a limit of at most one pending un-ACKed frame
  13554. +(per party, effectively leading to synchronous communication regarding
  13555. +frames) and at most three pending commands. The limit to synchronous frame
  13556. +transfers seems to be consistent with behavior observed on Windows.
  13557. diff --git a/MAINTAINERS b/MAINTAINERS
  13558. index 530792c869c4..8e6fe82c1072 100644
  13559. --- a/MAINTAINERS
  13560. +++ b/MAINTAINERS
  13561. @@ -11811,6 +11811,7 @@ M: Maximilian Luz <luzmaximilian@gmail.com>
  13562. S: Maintained
  13563. W: https://github.com/linux-surface/surface-aggregator-module
  13564. C: irc://chat.freenode.net/##linux-surface
  13565. +F: Documentation/driver-api/surface_aggregator/
  13566. F: drivers/platform/surface/aggregator/
  13567. F: include/linux/surface_aggregator/
  13568. --
  13569. 2.31.0
  13570. From 461efa8828105b740589ec8673adfe78a403945c Mon Sep 17 00:00:00 2001
  13571. From: Maximilian Luz <luzmaximilian@gmail.com>
  13572. Date: Mon, 21 Dec 2020 19:39:58 +0100
  13573. Subject: [PATCH] platform/surface: Add Surface Aggregator user-space interface
  13574. Add a misc-device providing user-space access to the Surface Aggregator
  13575. EC, mainly intended for debugging, testing, and reverse-engineering.
  13576. This interface gives user-space applications the ability to send
  13577. requests to the EC and receive the corresponding responses.
  13578. The device-file is managed by a pseudo platform-device and corresponding
  13579. driver to avoid dependence on the dedicated bus, allowing it to be
  13580. loaded in a minimal configuration.
  13581. A python library and scripts to access this device can be found at [1].
  13582. [1]: https://github.com/linux-surface/surface-aggregator-module/tree/master/scripts/ssam
  13583. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  13584. Link: https://lore.kernel.org/r/20201221183959.1186143-9-luzmaximilian@gmail.com
  13585. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  13586. Patchset: surface-sam
  13587. ---
  13588. .../surface_aggregator/clients/cdev.rst | 87 +++++
  13589. .../surface_aggregator/clients/index.rst | 12 +-
  13590. .../userspace-api/ioctl/ioctl-number.rst | 2 +
  13591. MAINTAINERS | 2 +
  13592. drivers/platform/surface/Kconfig | 17 +
  13593. drivers/platform/surface/Makefile | 1 +
  13594. .../surface/surface_aggregator_cdev.c | 303 ++++++++++++++++++
  13595. include/uapi/linux/surface_aggregator/cdev.h | 78 +++++
  13596. 8 files changed, 501 insertions(+), 1 deletion(-)
  13597. create mode 100644 Documentation/driver-api/surface_aggregator/clients/cdev.rst
  13598. create mode 100644 drivers/platform/surface/surface_aggregator_cdev.c
  13599. create mode 100644 include/uapi/linux/surface_aggregator/cdev.h
  13600. diff --git a/Documentation/driver-api/surface_aggregator/clients/cdev.rst b/Documentation/driver-api/surface_aggregator/clients/cdev.rst
  13601. new file mode 100644
  13602. index 000000000000..248c1372d879
  13603. --- /dev/null
  13604. +++ b/Documentation/driver-api/surface_aggregator/clients/cdev.rst
  13605. @@ -0,0 +1,87 @@
  13606. +.. SPDX-License-Identifier: GPL-2.0+
  13607. +
  13608. +.. |u8| replace:: :c:type:`u8 <u8>`
  13609. +.. |u16| replace:: :c:type:`u16 <u16>`
  13610. +.. |ssam_cdev_request| replace:: :c:type:`struct ssam_cdev_request <ssam_cdev_request>`
  13611. +.. |ssam_cdev_request_flags| replace:: :c:type:`enum ssam_cdev_request_flags <ssam_cdev_request_flags>`
  13612. +
  13613. +==============================
  13614. +User-Space EC Interface (cdev)
  13615. +==============================
  13616. +
  13617. +The ``surface_aggregator_cdev`` module provides a misc-device for the SSAM
  13618. +controller to allow for a (more or less) direct connection from user-space to
  13619. +the SAM EC. It is intended to be used for development and debugging, and
  13620. +therefore should not be used or relied upon in any other way. Note that this
  13621. +module is not loaded automatically, but instead must be loaded manually.
  13622. +
  13623. +The provided interface is accessible through the ``/dev/surface/aggregator``
  13624. +device-file. All functionality of this interface is provided via IOCTLs.
  13625. +These IOCTLs and their respective input/output parameter structs are defined in
  13626. +``include/uapi/linux/surface_aggregator/cdev.h``.
  13627. +
  13628. +A small python library and scripts for accessing this interface can be found
  13629. +at https://github.com/linux-surface/surface-aggregator-module/tree/master/scripts/ssam.
  13630. +
  13631. +
  13632. +Controller IOCTLs
  13633. +=================
  13634. +
  13635. +The following IOCTLs are provided:
  13636. +
  13637. +.. flat-table:: Controller IOCTLs
  13638. + :widths: 1 1 1 1 4
  13639. + :header-rows: 1
  13640. +
  13641. + * - Type
  13642. + - Number
  13643. + - Direction
  13644. + - Name
  13645. + - Description
  13646. +
  13647. + * - ``0xA5``
  13648. + - ``1``
  13649. + - ``WR``
  13650. + - ``REQUEST``
  13651. + - Perform synchronous SAM request.
  13652. +
  13653. +
  13654. +``REQUEST``
  13655. +-----------
  13656. +
  13657. +Defined as ``_IOWR(0xA5, 1, struct ssam_cdev_request)``.
  13658. +
  13659. +Executes a synchronous SAM request. The request specification is passed in
  13660. +as argument of type |ssam_cdev_request|, which is then written to/modified
  13661. +by the IOCTL to return status and result of the request.
  13662. +
  13663. +Request payload data must be allocated separately and is passed in via the
  13664. +``payload.data`` and ``payload.length`` members. If a response is required,
  13665. +the response buffer must be allocated by the caller and passed in via the
  13666. +``response.data`` member. The ``response.length`` member must be set to the
  13667. +capacity of this buffer, or if no response is required, zero. Upon
  13668. +completion of the request, the call will write the response to the response
  13669. +buffer (if its capacity allows it) and overwrite the length field with the
  13670. +actual size of the response, in bytes.
  13671. +
  13672. +Additionally, if the request has a response, this must be indicated via the
  13673. +request flags, as is done with in-kernel requests. Request flags can be set
  13674. +via the ``flags`` member and the values correspond to the values found in
  13675. +|ssam_cdev_request_flags|.
  13676. +
  13677. +Finally, the status of the request itself is returned in the ``status``
  13678. +member (a negative errno value indicating failure). Note that failure
  13679. +indication of the IOCTL is separated from failure indication of the request:
  13680. +The IOCTL returns a negative status code if anything failed during setup of
  13681. +the request (``-EFAULT``) or if the provided argument or any of its fields
  13682. +are invalid (``-EINVAL``). In this case, the status value of the request
  13683. +argument may be set, providing more detail on what went wrong (e.g.
  13684. +``-ENOMEM`` for out-of-memory), but this value may also be zero. The IOCTL
  13685. +will return with a zero status code in case the request has been set up,
  13686. +submitted, and completed (i.e. handed back to user-space) successfully from
  13687. +inside the IOCTL, but the request ``status`` member may still be negative in
  13688. +case the actual execution of the request failed after it has been submitted.
  13689. +
  13690. +A full definition of the argument struct is provided below:
  13691. +
  13692. +.. kernel-doc:: include/uapi/linux/surface_aggregator/cdev.h
  13693. diff --git a/Documentation/driver-api/surface_aggregator/clients/index.rst b/Documentation/driver-api/surface_aggregator/clients/index.rst
  13694. index 31e026d96102..ab260ec82cfb 100644
  13695. --- a/Documentation/driver-api/surface_aggregator/clients/index.rst
  13696. +++ b/Documentation/driver-api/surface_aggregator/clients/index.rst
  13697. @@ -7,4 +7,14 @@ Client Driver Documentation
  13698. This is the documentation for client drivers themselves. Refer to
  13699. :doc:`../client` for documentation on how to write client drivers.
  13700. -.. Place documentation for individual client drivers here.
  13701. +.. toctree::
  13702. + :maxdepth: 1
  13703. +
  13704. + cdev
  13705. +
  13706. +.. only:: subproject and html
  13707. +
  13708. + Indices
  13709. + =======
  13710. +
  13711. + * :ref:`genindex`
  13712. diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
  13713. index a4c75a28c839..b5231d7f9200 100644
  13714. --- a/Documentation/userspace-api/ioctl/ioctl-number.rst
  13715. +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
  13716. @@ -324,6 +324,8 @@ Code Seq# Include File Comments
  13717. 0xA3 90-9F linux/dtlk.h
  13718. 0xA4 00-1F uapi/linux/tee.h Generic TEE subsystem
  13719. 0xA4 00-1F uapi/asm/sgx.h <mailto:linux-sgx@vger.kernel.org>
  13720. +0xA5 01 linux/surface_aggregator/cdev.h Microsoft Surface Platform System Aggregator
  13721. + <mailto:luzmaximilian@gmail.com>
  13722. 0xAA 00-3F linux/uapi/linux/userfaultfd.h
  13723. 0xAB 00-1F linux/nbd.h
  13724. 0xAC 00-1F linux/raw.h
  13725. diff --git a/MAINTAINERS b/MAINTAINERS
  13726. index 8e6fe82c1072..b45df8ec687f 100644
  13727. --- a/MAINTAINERS
  13728. +++ b/MAINTAINERS
  13729. @@ -11813,7 +11813,9 @@ W: https://github.com/linux-surface/surface-aggregator-module
  13730. C: irc://chat.freenode.net/##linux-surface
  13731. F: Documentation/driver-api/surface_aggregator/
  13732. F: drivers/platform/surface/aggregator/
  13733. +F: drivers/platform/surface/surface_aggregator_cdev.c
  13734. F: include/linux/surface_aggregator/
  13735. +F: include/uapi/linux/surface_aggregator/
  13736. MICROTEK X6 SCANNER
  13737. M: Oliver Neukum <oliver@neukum.org>
  13738. diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig
  13739. index ef6b4051e7c8..82fbcfedc6dc 100644
  13740. --- a/drivers/platform/surface/Kconfig
  13741. +++ b/drivers/platform/surface/Kconfig
  13742. @@ -41,6 +41,23 @@ config SURFACE_3_POWER_OPREGION
  13743. This driver provides support for ACPI operation
  13744. region of the Surface 3 battery platform driver.
  13745. +config SURFACE_AGGREGATOR_CDEV
  13746. + tristate "Surface System Aggregator Module User-Space Interface"
  13747. + depends on SURFACE_AGGREGATOR
  13748. + help
  13749. + Provides a misc-device interface to the Surface System Aggregator
  13750. + Module (SSAM) controller.
  13751. +
  13752. + This option provides a module (called surface_aggregator_cdev), that,
  13753. + when loaded, will add a client device (and its respective driver) to
  13754. + the SSAM controller. Said client device manages a misc-device
  13755. + interface (/dev/surface/aggregator), which can be used by user-space
  13756. + tools to directly communicate with the SSAM EC by sending requests and
  13757. + receiving the corresponding responses.
  13758. +
  13759. + The provided interface is intended for debugging and development only,
  13760. + and should not be used otherwise.
  13761. +
  13762. config SURFACE_BOOK1_DGPU_SWITCH
  13763. tristate "Surface Book 1 dGPU Switch Driver"
  13764. depends on SYSFS
  13765. diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile
  13766. index c5392098cfb9..644c7511f64d 100644
  13767. --- a/drivers/platform/surface/Makefile
  13768. +++ b/drivers/platform/surface/Makefile
  13769. @@ -8,6 +8,7 @@ obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
  13770. obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
  13771. obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o
  13772. obj-$(CONFIG_SURFACE_AGGREGATOR) += aggregator/
  13773. +obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o
  13774. obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o
  13775. obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o
  13776. obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
  13777. diff --git a/drivers/platform/surface/surface_aggregator_cdev.c b/drivers/platform/surface/surface_aggregator_cdev.c
  13778. new file mode 100644
  13779. index 000000000000..340d15b148b9
  13780. --- /dev/null
  13781. +++ b/drivers/platform/surface/surface_aggregator_cdev.c
  13782. @@ -0,0 +1,303 @@
  13783. +// SPDX-License-Identifier: GPL-2.0+
  13784. +/*
  13785. + * Provides user-space access to the SSAM EC via the /dev/surface/aggregator
  13786. + * misc device. Intended for debugging and development.
  13787. + *
  13788. + * Copyright (C) 2020 Maximilian Luz <luzmaximilian@gmail.com>
  13789. + */
  13790. +
  13791. +#include <linux/fs.h>
  13792. +#include <linux/kernel.h>
  13793. +#include <linux/kref.h>
  13794. +#include <linux/miscdevice.h>
  13795. +#include <linux/module.h>
  13796. +#include <linux/platform_device.h>
  13797. +#include <linux/rwsem.h>
  13798. +#include <linux/slab.h>
  13799. +#include <linux/uaccess.h>
  13800. +
  13801. +#include <linux/surface_aggregator/cdev.h>
  13802. +#include <linux/surface_aggregator/controller.h>
  13803. +
  13804. +#define SSAM_CDEV_DEVICE_NAME "surface_aggregator_cdev"
  13805. +
  13806. +struct ssam_cdev {
  13807. + struct kref kref;
  13808. + struct rw_semaphore lock;
  13809. + struct ssam_controller *ctrl;
  13810. + struct miscdevice mdev;
  13811. +};
  13812. +
  13813. +static void __ssam_cdev_release(struct kref *kref)
  13814. +{
  13815. + kfree(container_of(kref, struct ssam_cdev, kref));
  13816. +}
  13817. +
  13818. +static struct ssam_cdev *ssam_cdev_get(struct ssam_cdev *cdev)
  13819. +{
  13820. + if (cdev)
  13821. + kref_get(&cdev->kref);
  13822. +
  13823. + return cdev;
  13824. +}
  13825. +
  13826. +static void ssam_cdev_put(struct ssam_cdev *cdev)
  13827. +{
  13828. + if (cdev)
  13829. + kref_put(&cdev->kref, __ssam_cdev_release);
  13830. +}
  13831. +
  13832. +static int ssam_cdev_device_open(struct inode *inode, struct file *filp)
  13833. +{
  13834. + struct miscdevice *mdev = filp->private_data;
  13835. + struct ssam_cdev *cdev = container_of(mdev, struct ssam_cdev, mdev);
  13836. +
  13837. + filp->private_data = ssam_cdev_get(cdev);
  13838. + return stream_open(inode, filp);
  13839. +}
  13840. +
  13841. +static int ssam_cdev_device_release(struct inode *inode, struct file *filp)
  13842. +{
  13843. + ssam_cdev_put(filp->private_data);
  13844. + return 0;
  13845. +}
  13846. +
  13847. +static long ssam_cdev_request(struct ssam_cdev *cdev, unsigned long arg)
  13848. +{
  13849. + struct ssam_cdev_request __user *r;
  13850. + struct ssam_cdev_request rqst;
  13851. + struct ssam_request spec;
  13852. + struct ssam_response rsp;
  13853. + const void __user *plddata;
  13854. + void __user *rspdata;
  13855. + int status = 0, ret = 0, tmp;
  13856. +
  13857. + r = (struct ssam_cdev_request __user *)arg;
  13858. + ret = copy_struct_from_user(&rqst, sizeof(rqst), r, sizeof(*r));
  13859. + if (ret)
  13860. + goto out;
  13861. +
  13862. + plddata = u64_to_user_ptr(rqst.payload.data);
  13863. + rspdata = u64_to_user_ptr(rqst.response.data);
  13864. +
  13865. + /* Setup basic request fields. */
  13866. + spec.target_category = rqst.target_category;
  13867. + spec.target_id = rqst.target_id;
  13868. + spec.command_id = rqst.command_id;
  13869. + spec.instance_id = rqst.instance_id;
  13870. + spec.flags = 0;
  13871. + spec.length = rqst.payload.length;
  13872. + spec.payload = NULL;
  13873. +
  13874. + if (rqst.flags & SSAM_CDEV_REQUEST_HAS_RESPONSE)
  13875. + spec.flags |= SSAM_REQUEST_HAS_RESPONSE;
  13876. +
  13877. + if (rqst.flags & SSAM_CDEV_REQUEST_UNSEQUENCED)
  13878. + spec.flags |= SSAM_REQUEST_UNSEQUENCED;
  13879. +
  13880. + rsp.capacity = rqst.response.length;
  13881. + rsp.length = 0;
  13882. + rsp.pointer = NULL;
  13883. +
  13884. + /* Get request payload from user-space. */
  13885. + if (spec.length) {
  13886. + if (!plddata) {
  13887. + ret = -EINVAL;
  13888. + goto out;
  13889. + }
  13890. +
  13891. + spec.payload = kzalloc(spec.length, GFP_KERNEL);
  13892. + if (!spec.payload) {
  13893. + ret = -ENOMEM;
  13894. + goto out;
  13895. + }
  13896. +
  13897. + if (copy_from_user((void *)spec.payload, plddata, spec.length)) {
  13898. + ret = -EFAULT;
  13899. + goto out;
  13900. + }
  13901. + }
  13902. +
  13903. + /* Allocate response buffer. */
  13904. + if (rsp.capacity) {
  13905. + if (!rspdata) {
  13906. + ret = -EINVAL;
  13907. + goto out;
  13908. + }
  13909. +
  13910. + rsp.pointer = kzalloc(rsp.capacity, GFP_KERNEL);
  13911. + if (!rsp.pointer) {
  13912. + ret = -ENOMEM;
  13913. + goto out;
  13914. + }
  13915. + }
  13916. +
  13917. + /* Perform request. */
  13918. + status = ssam_request_sync(cdev->ctrl, &spec, &rsp);
  13919. + if (status)
  13920. + goto out;
  13921. +
  13922. + /* Copy response to user-space. */
  13923. + if (rsp.length && copy_to_user(rspdata, rsp.pointer, rsp.length))
  13924. + ret = -EFAULT;
  13925. +
  13926. +out:
  13927. + /* Always try to set response-length and status. */
  13928. + tmp = put_user(rsp.length, &r->response.length);
  13929. + if (tmp)
  13930. + ret = tmp;
  13931. +
  13932. + tmp = put_user(status, &r->status);
  13933. + if (tmp)
  13934. + ret = tmp;
  13935. +
  13936. + /* Cleanup. */
  13937. + kfree(spec.payload);
  13938. + kfree(rsp.pointer);
  13939. +
  13940. + return ret;
  13941. +}
  13942. +
  13943. +static long __ssam_cdev_device_ioctl(struct ssam_cdev *cdev, unsigned int cmd,
  13944. + unsigned long arg)
  13945. +{
  13946. + switch (cmd) {
  13947. + case SSAM_CDEV_REQUEST:
  13948. + return ssam_cdev_request(cdev, arg);
  13949. +
  13950. + default:
  13951. + return -ENOTTY;
  13952. + }
  13953. +}
  13954. +
  13955. +static long ssam_cdev_device_ioctl(struct file *file, unsigned int cmd,
  13956. + unsigned long arg)
  13957. +{
  13958. + struct ssam_cdev *cdev = file->private_data;
  13959. + long status;
  13960. +
  13961. + /* Ensure that controller is valid for as long as we need it. */
  13962. + if (down_read_killable(&cdev->lock))
  13963. + return -ERESTARTSYS;
  13964. +
  13965. + if (!cdev->ctrl) {
  13966. + up_read(&cdev->lock);
  13967. + return -ENODEV;
  13968. + }
  13969. +
  13970. + status = __ssam_cdev_device_ioctl(cdev, cmd, arg);
  13971. +
  13972. + up_read(&cdev->lock);
  13973. + return status;
  13974. +}
  13975. +
  13976. +static const struct file_operations ssam_controller_fops = {
  13977. + .owner = THIS_MODULE,
  13978. + .open = ssam_cdev_device_open,
  13979. + .release = ssam_cdev_device_release,
  13980. + .unlocked_ioctl = ssam_cdev_device_ioctl,
  13981. + .compat_ioctl = ssam_cdev_device_ioctl,
  13982. + .llseek = noop_llseek,
  13983. +};
  13984. +
  13985. +static int ssam_dbg_device_probe(struct platform_device *pdev)
  13986. +{
  13987. + struct ssam_controller *ctrl;
  13988. + struct ssam_cdev *cdev;
  13989. + int status;
  13990. +
  13991. + ctrl = ssam_client_bind(&pdev->dev);
  13992. + if (IS_ERR(ctrl))
  13993. + return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl);
  13994. +
  13995. + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
  13996. + if (!cdev)
  13997. + return -ENOMEM;
  13998. +
  13999. + kref_init(&cdev->kref);
  14000. + init_rwsem(&cdev->lock);
  14001. + cdev->ctrl = ctrl;
  14002. +
  14003. + cdev->mdev.parent = &pdev->dev;
  14004. + cdev->mdev.minor = MISC_DYNAMIC_MINOR;
  14005. + cdev->mdev.name = "surface_aggregator";
  14006. + cdev->mdev.nodename = "surface/aggregator";
  14007. + cdev->mdev.fops = &ssam_controller_fops;
  14008. +
  14009. + status = misc_register(&cdev->mdev);
  14010. + if (status) {
  14011. + kfree(cdev);
  14012. + return status;
  14013. + }
  14014. +
  14015. + platform_set_drvdata(pdev, cdev);
  14016. + return 0;
  14017. +}
  14018. +
  14019. +static int ssam_dbg_device_remove(struct platform_device *pdev)
  14020. +{
  14021. + struct ssam_cdev *cdev = platform_get_drvdata(pdev);
  14022. +
  14023. + misc_deregister(&cdev->mdev);
  14024. +
  14025. + /*
  14026. + * The controller is only guaranteed to be valid for as long as the
  14027. + * driver is bound. Remove controller so that any lingering open files
  14028. + * cannot access it any more after we're gone.
  14029. + */
  14030. + down_write(&cdev->lock);
  14031. + cdev->ctrl = NULL;
  14032. + up_write(&cdev->lock);
  14033. +
  14034. + ssam_cdev_put(cdev);
  14035. + return 0;
  14036. +}
  14037. +
  14038. +static struct platform_device *ssam_cdev_device;
  14039. +
  14040. +static struct platform_driver ssam_cdev_driver = {
  14041. + .probe = ssam_dbg_device_probe,
  14042. + .remove = ssam_dbg_device_remove,
  14043. + .driver = {
  14044. + .name = SSAM_CDEV_DEVICE_NAME,
  14045. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  14046. + },
  14047. +};
  14048. +
  14049. +static int __init ssam_debug_init(void)
  14050. +{
  14051. + int status;
  14052. +
  14053. + ssam_cdev_device = platform_device_alloc(SSAM_CDEV_DEVICE_NAME,
  14054. + PLATFORM_DEVID_NONE);
  14055. + if (!ssam_cdev_device)
  14056. + return -ENOMEM;
  14057. +
  14058. + status = platform_device_add(ssam_cdev_device);
  14059. + if (status)
  14060. + goto err_device;
  14061. +
  14062. + status = platform_driver_register(&ssam_cdev_driver);
  14063. + if (status)
  14064. + goto err_driver;
  14065. +
  14066. + return 0;
  14067. +
  14068. +err_driver:
  14069. + platform_device_del(ssam_cdev_device);
  14070. +err_device:
  14071. + platform_device_put(ssam_cdev_device);
  14072. + return status;
  14073. +}
  14074. +module_init(ssam_debug_init);
  14075. +
  14076. +static void __exit ssam_debug_exit(void)
  14077. +{
  14078. + platform_driver_unregister(&ssam_cdev_driver);
  14079. + platform_device_unregister(ssam_cdev_device);
  14080. +}
  14081. +module_exit(ssam_debug_exit);
  14082. +
  14083. +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  14084. +MODULE_DESCRIPTION("User-space interface for Surface System Aggregator Module");
  14085. +MODULE_LICENSE("GPL");
  14086. diff --git a/include/uapi/linux/surface_aggregator/cdev.h b/include/uapi/linux/surface_aggregator/cdev.h
  14087. new file mode 100644
  14088. index 000000000000..fbcce04abfe9
  14089. --- /dev/null
  14090. +++ b/include/uapi/linux/surface_aggregator/cdev.h
  14091. @@ -0,0 +1,78 @@
  14092. +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
  14093. +/*
  14094. + * Surface System Aggregator Module (SSAM) user-space EC interface.
  14095. + *
  14096. + * Definitions, structs, and IOCTLs for the /dev/surface/aggregator misc
  14097. + * device. This device provides direct user-space access to the SSAM EC.
  14098. + * Intended for debugging and development.
  14099. + *
  14100. + * Copyright (C) 2020 Maximilian Luz <luzmaximilian@gmail.com>
  14101. + */
  14102. +
  14103. +#ifndef _UAPI_LINUX_SURFACE_AGGREGATOR_CDEV_H
  14104. +#define _UAPI_LINUX_SURFACE_AGGREGATOR_CDEV_H
  14105. +
  14106. +#include <linux/ioctl.h>
  14107. +#include <linux/types.h>
  14108. +
  14109. +/**
  14110. + * enum ssam_cdev_request_flags - Request flags for SSAM cdev request IOCTL.
  14111. + *
  14112. + * @SSAM_CDEV_REQUEST_HAS_RESPONSE:
  14113. + * Specifies that the request expects a response. If not set, the request
  14114. + * will be directly completed after its underlying packet has been
  14115. + * transmitted. If set, the request transport system waits for a response
  14116. + * of the request.
  14117. + *
  14118. + * @SSAM_CDEV_REQUEST_UNSEQUENCED:
  14119. + * Specifies that the request should be transmitted via an unsequenced
  14120. + * packet. If set, the request must not have a response, meaning that this
  14121. + * flag and the %SSAM_CDEV_REQUEST_HAS_RESPONSE flag are mutually
  14122. + * exclusive.
  14123. + */
  14124. +enum ssam_cdev_request_flags {
  14125. + SSAM_CDEV_REQUEST_HAS_RESPONSE = 0x01,
  14126. + SSAM_CDEV_REQUEST_UNSEQUENCED = 0x02,
  14127. +};
  14128. +
  14129. +/**
  14130. + * struct ssam_cdev_request - Controller request IOCTL argument.
  14131. + * @target_category: Target category of the SAM request.
  14132. + * @target_id: Target ID of the SAM request.
  14133. + * @command_id: Command ID of the SAM request.
  14134. + * @instance_id: Instance ID of the SAM request.
  14135. + * @flags: Request flags (see &enum ssam_cdev_request_flags).
  14136. + * @status: Request status (output).
  14137. + * @payload: Request payload (input data).
  14138. + * @payload.data: Pointer to request payload data.
  14139. + * @payload.length: Length of request payload data (in bytes).
  14140. + * @response: Request response (output data).
  14141. + * @response.data: Pointer to response buffer.
  14142. + * @response.length: On input: Capacity of response buffer (in bytes).
  14143. + * On output: Length of request response (number of bytes
  14144. + * in the buffer that are actually used).
  14145. + */
  14146. +struct ssam_cdev_request {
  14147. + __u8 target_category;
  14148. + __u8 target_id;
  14149. + __u8 command_id;
  14150. + __u8 instance_id;
  14151. + __u16 flags;
  14152. + __s16 status;
  14153. +
  14154. + struct {
  14155. + __u64 data;
  14156. + __u16 length;
  14157. + __u8 __pad[6];
  14158. + } payload;
  14159. +
  14160. + struct {
  14161. + __u64 data;
  14162. + __u16 length;
  14163. + __u8 __pad[6];
  14164. + } response;
  14165. +} __attribute__((__packed__));
  14166. +
  14167. +#define SSAM_CDEV_REQUEST _IOWR(0xA5, 1, struct ssam_cdev_request)
  14168. +
  14169. +#endif /* _UAPI_LINUX_SURFACE_AGGREGATOR_CDEV_H */
  14170. --
  14171. 2.31.0
  14172. From 3a1ade8f72b937629858465ebc82c0e4673bb751 Mon Sep 17 00:00:00 2001
  14173. From: Maximilian Luz <luzmaximilian@gmail.com>
  14174. Date: Mon, 21 Dec 2020 19:39:59 +0100
  14175. Subject: [PATCH] platform/surface: Add Surface ACPI Notify driver
  14176. The Surface ACPI Notify (SAN) device provides an ACPI interface to the
  14177. Surface Aggregator EC, specifically the Surface Serial Hub interface.
  14178. This interface allows EC requests to be made from ACPI code and can
  14179. convert a subset of EC events back to ACPI notifications.
  14180. Specifically, this interface provides a GenericSerialBus operation
  14181. region ACPI code can execute a request by writing the request command
  14182. data and payload to this operation region and reading back the
  14183. corresponding response via a write-then-read operation. Furthermore,
  14184. this interface provides a _DSM method to be called when certain events
  14185. from the EC have been received, essentially turning them into ACPI
  14186. notifications.
  14187. The driver provided in this commit essentially takes care of translating
  14188. the request data written to the operation region, executing the request,
  14189. waiting for it to finish, and finally writing and translating back the
  14190. response (if the request has one). Furthermore, this driver takes care
  14191. of enabling the events handled via ACPI _DSM calls. Lastly, this driver
  14192. also exposes an interface providing discrete GPU (dGPU) power-on
  14193. notifications on the Surface Book 2, which are also received via the
  14194. operation region interface (but not handled by the SAN driver directly),
  14195. making them accessible to other drivers (such as a dGPU hot-plug driver
  14196. that may be added later on).
  14197. On 5th and 6th generation Surface devices (Surface Pro 5/2017, Pro 6,
  14198. Book 2, Laptop 1 and 2), the SAN interface provides full battery and
  14199. thermal subsystem access, as well as other EC based functionality. On
  14200. those models, battery and thermal sensor devices are implemented as
  14201. standard ACPI devices of that type, however, forward ACPI calls to the
  14202. corresponding Surface Aggregator EC request via the SAN interface and
  14203. receive corresponding notifications (e.g. battery information change)
  14204. from it. This interface is therefore required to provide said
  14205. functionality on those devices.
  14206. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  14207. Reviewed-by: Hans de Goede <hdegoede@redhat.com>
  14208. Link: https://lore.kernel.org/r/20201221183959.1186143-10-luzmaximilian@gmail.com
  14209. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  14210. Patchset: surface-sam
  14211. ---
  14212. .../surface_aggregator/clients/index.rst | 1 +
  14213. .../surface_aggregator/clients/san.rst | 44 +
  14214. MAINTAINERS | 2 +
  14215. drivers/platform/surface/Kconfig | 19 +
  14216. drivers/platform/surface/Makefile | 1 +
  14217. .../platform/surface/surface_acpi_notify.c | 886 ++++++++++++++++++
  14218. include/linux/surface_acpi_notify.h | 39 +
  14219. 7 files changed, 992 insertions(+)
  14220. create mode 100644 Documentation/driver-api/surface_aggregator/clients/san.rst
  14221. create mode 100644 drivers/platform/surface/surface_acpi_notify.c
  14222. create mode 100644 include/linux/surface_acpi_notify.h
  14223. diff --git a/Documentation/driver-api/surface_aggregator/clients/index.rst b/Documentation/driver-api/surface_aggregator/clients/index.rst
  14224. index ab260ec82cfb..3ccabce23271 100644
  14225. --- a/Documentation/driver-api/surface_aggregator/clients/index.rst
  14226. +++ b/Documentation/driver-api/surface_aggregator/clients/index.rst
  14227. @@ -11,6 +11,7 @@ This is the documentation for client drivers themselves. Refer to
  14228. :maxdepth: 1
  14229. cdev
  14230. + san
  14231. .. only:: subproject and html
  14232. diff --git a/Documentation/driver-api/surface_aggregator/clients/san.rst b/Documentation/driver-api/surface_aggregator/clients/san.rst
  14233. new file mode 100644
  14234. index 000000000000..38c2580e7758
  14235. --- /dev/null
  14236. +++ b/Documentation/driver-api/surface_aggregator/clients/san.rst
  14237. @@ -0,0 +1,44 @@
  14238. +.. SPDX-License-Identifier: GPL-2.0+
  14239. +
  14240. +.. |san_client_link| replace:: :c:func:`san_client_link`
  14241. +.. |san_dgpu_notifier_register| replace:: :c:func:`san_dgpu_notifier_register`
  14242. +.. |san_dgpu_notifier_unregister| replace:: :c:func:`san_dgpu_notifier_unregister`
  14243. +
  14244. +===================
  14245. +Surface ACPI Notify
  14246. +===================
  14247. +
  14248. +The Surface ACPI Notify (SAN) device provides the bridge between ACPI and
  14249. +SAM controller. Specifically, ACPI code can execute requests and handle
  14250. +battery and thermal events via this interface. In addition to this, events
  14251. +relating to the discrete GPU (dGPU) of the Surface Book 2 can be sent from
  14252. +ACPI code (note: the Surface Book 3 uses a different method for this). The
  14253. +only currently known event sent via this interface is a dGPU power-on
  14254. +notification. While this driver handles the former part internally, it only
  14255. +relays the dGPU events to any other driver interested via its public API and
  14256. +does not handle them.
  14257. +
  14258. +The public interface of this driver is split into two parts: Client
  14259. +registration and notifier-block registration.
  14260. +
  14261. +A client to the SAN interface can be linked as consumer to the SAN device
  14262. +via |san_client_link|. This can be used to ensure that the a client
  14263. +receiving dGPU events does not miss any events due to the SAN interface not
  14264. +being set up as this forces the client driver to unbind once the SAN driver
  14265. +is unbound.
  14266. +
  14267. +Notifier-blocks can be registered by any device for as long as the module is
  14268. +loaded, regardless of being linked as client or not. Registration is done
  14269. +with |san_dgpu_notifier_register|. If the notifier is not needed any more, it
  14270. +should be unregistered via |san_dgpu_notifier_unregister|.
  14271. +
  14272. +Consult the API documentation below for more details.
  14273. +
  14274. +
  14275. +API Documentation
  14276. +=================
  14277. +
  14278. +.. kernel-doc:: include/linux/surface_acpi_notify.h
  14279. +
  14280. +.. kernel-doc:: drivers/platform/surface/surface_acpi_notify.c
  14281. + :export:
  14282. diff --git a/MAINTAINERS b/MAINTAINERS
  14283. index b45df8ec687f..dfe4f4e1da7a 100644
  14284. --- a/MAINTAINERS
  14285. +++ b/MAINTAINERS
  14286. @@ -11813,7 +11813,9 @@ W: https://github.com/linux-surface/surface-aggregator-module
  14287. C: irc://chat.freenode.net/##linux-surface
  14288. F: Documentation/driver-api/surface_aggregator/
  14289. F: drivers/platform/surface/aggregator/
  14290. +F: drivers/platform/surface/surface_acpi_notify.c
  14291. F: drivers/platform/surface/surface_aggregator_cdev.c
  14292. +F: include/linux/surface_acpi_notify.h
  14293. F: include/linux/surface_aggregator/
  14294. F: include/uapi/linux/surface_aggregator/
  14295. diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig
  14296. index 82fbcfedc6dc..b0b91fa2f6a1 100644
  14297. --- a/drivers/platform/surface/Kconfig
  14298. +++ b/drivers/platform/surface/Kconfig
  14299. @@ -41,6 +41,25 @@ config SURFACE_3_POWER_OPREGION
  14300. This driver provides support for ACPI operation
  14301. region of the Surface 3 battery platform driver.
  14302. +config SURFACE_ACPI_NOTIFY
  14303. + tristate "Surface ACPI Notify Driver"
  14304. + depends on SURFACE_AGGREGATOR
  14305. + help
  14306. + Surface ACPI Notify (SAN) driver for Microsoft Surface devices.
  14307. +
  14308. + This driver provides support for the ACPI interface (called SAN) of
  14309. + the Surface System Aggregator Module (SSAM) EC. This interface is used
  14310. + on 5th- and 6th-generation Microsoft Surface devices (including
  14311. + Surface Pro 5 and 6, Surface Book 2, Surface Laptops 1 and 2, and in
  14312. + reduced functionality on the Surface Laptop 3) to execute SSAM
  14313. + requests directly from ACPI code, as well as receive SSAM events and
  14314. + turn them into ACPI notifications. It essentially acts as a
  14315. + translation layer between the SSAM controller and ACPI.
  14316. +
  14317. + Specifically, this driver may be needed for battery status reporting,
  14318. + thermal sensor access, and real-time clock information, depending on
  14319. + the Surface device in question.
  14320. +
  14321. config SURFACE_AGGREGATOR_CDEV
  14322. tristate "Surface System Aggregator Module User-Space Interface"
  14323. depends on SURFACE_AGGREGATOR
  14324. diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile
  14325. index 644c7511f64d..72f4d9fbb6be 100644
  14326. --- a/drivers/platform/surface/Makefile
  14327. +++ b/drivers/platform/surface/Makefile
  14328. @@ -7,6 +7,7 @@
  14329. obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o
  14330. obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
  14331. obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o
  14332. +obj-$(CONFIG_SURFACE_ACPI_NOTIFY) += surface_acpi_notify.o
  14333. obj-$(CONFIG_SURFACE_AGGREGATOR) += aggregator/
  14334. obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o
  14335. obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o
  14336. diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c
  14337. new file mode 100644
  14338. index 000000000000..8cd67a669c86
  14339. --- /dev/null
  14340. +++ b/drivers/platform/surface/surface_acpi_notify.c
  14341. @@ -0,0 +1,886 @@
  14342. +// SPDX-License-Identifier: GPL-2.0+
  14343. +/*
  14344. + * Driver for the Surface ACPI Notify (SAN) interface/shim.
  14345. + *
  14346. + * Translates communication from ACPI to Surface System Aggregator Module
  14347. + * (SSAM/SAM) requests and back, specifically SAM-over-SSH. Translates SSAM
  14348. + * events back to ACPI notifications. Allows handling of discrete GPU
  14349. + * notifications sent from ACPI via the SAN interface by providing them to any
  14350. + * registered external driver.
  14351. + *
  14352. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  14353. + */
  14354. +
  14355. +#include <asm/unaligned.h>
  14356. +#include <linux/acpi.h>
  14357. +#include <linux/delay.h>
  14358. +#include <linux/jiffies.h>
  14359. +#include <linux/kernel.h>
  14360. +#include <linux/module.h>
  14361. +#include <linux/notifier.h>
  14362. +#include <linux/platform_device.h>
  14363. +#include <linux/rwsem.h>
  14364. +
  14365. +#include <linux/surface_aggregator/controller.h>
  14366. +#include <linux/surface_acpi_notify.h>
  14367. +
  14368. +struct san_data {
  14369. + struct device *dev;
  14370. + struct ssam_controller *ctrl;
  14371. +
  14372. + struct acpi_connection_info info;
  14373. +
  14374. + struct ssam_event_notifier nf_bat;
  14375. + struct ssam_event_notifier nf_tmp;
  14376. +};
  14377. +
  14378. +#define to_san_data(ptr, member) \
  14379. + container_of(ptr, struct san_data, member)
  14380. +
  14381. +
  14382. +/* -- dGPU notifier interface. ---------------------------------------------- */
  14383. +
  14384. +struct san_rqsg_if {
  14385. + struct rw_semaphore lock;
  14386. + struct device *dev;
  14387. + struct blocking_notifier_head nh;
  14388. +};
  14389. +
  14390. +static struct san_rqsg_if san_rqsg_if = {
  14391. + .lock = __RWSEM_INITIALIZER(san_rqsg_if.lock),
  14392. + .dev = NULL,
  14393. + .nh = BLOCKING_NOTIFIER_INIT(san_rqsg_if.nh),
  14394. +};
  14395. +
  14396. +static int san_set_rqsg_interface_device(struct device *dev)
  14397. +{
  14398. + int status = 0;
  14399. +
  14400. + down_write(&san_rqsg_if.lock);
  14401. + if (!san_rqsg_if.dev && dev)
  14402. + san_rqsg_if.dev = dev;
  14403. + else
  14404. + status = -EBUSY;
  14405. + up_write(&san_rqsg_if.lock);
  14406. +
  14407. + return status;
  14408. +}
  14409. +
  14410. +/**
  14411. + * san_client_link() - Link client as consumer to SAN device.
  14412. + * @client: The client to link.
  14413. + *
  14414. + * Sets up a device link between the provided client device as consumer and
  14415. + * the SAN device as provider. This function can be used to ensure that the
  14416. + * SAN interface has been set up and will be set up for as long as the driver
  14417. + * of the client device is bound. This guarantees that, during that time, all
  14418. + * dGPU events will be received by any registered notifier.
  14419. + *
  14420. + * The link will be automatically removed once the client device's driver is
  14421. + * unbound.
  14422. + *
  14423. + * Return: Returns zero on success, %-ENXIO if the SAN interface has not been
  14424. + * set up yet, and %-ENOMEM if device link creation failed.
  14425. + */
  14426. +int san_client_link(struct device *client)
  14427. +{
  14428. + const u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_CONSUMER;
  14429. + struct device_link *link;
  14430. +
  14431. + down_read(&san_rqsg_if.lock);
  14432. +
  14433. + if (!san_rqsg_if.dev) {
  14434. + up_read(&san_rqsg_if.lock);
  14435. + return -ENXIO;
  14436. + }
  14437. +
  14438. + link = device_link_add(client, san_rqsg_if.dev, flags);
  14439. + if (!link) {
  14440. + up_read(&san_rqsg_if.lock);
  14441. + return -ENOMEM;
  14442. + }
  14443. +
  14444. + if (READ_ONCE(link->status) == DL_STATE_SUPPLIER_UNBIND) {
  14445. + up_read(&san_rqsg_if.lock);
  14446. + return -ENXIO;
  14447. + }
  14448. +
  14449. + up_read(&san_rqsg_if.lock);
  14450. + return 0;
  14451. +}
  14452. +EXPORT_SYMBOL_GPL(san_client_link);
  14453. +
  14454. +/**
  14455. + * san_dgpu_notifier_register() - Register a SAN dGPU notifier.
  14456. + * @nb: The notifier-block to register.
  14457. + *
  14458. + * Registers a SAN dGPU notifier, receiving any new SAN dGPU events sent from
  14459. + * ACPI. The registered notifier will be called with &struct san_dgpu_event
  14460. + * as notifier data and the command ID of that event as notifier action.
  14461. + */
  14462. +int san_dgpu_notifier_register(struct notifier_block *nb)
  14463. +{
  14464. + return blocking_notifier_chain_register(&san_rqsg_if.nh, nb);
  14465. +}
  14466. +EXPORT_SYMBOL_GPL(san_dgpu_notifier_register);
  14467. +
  14468. +/**
  14469. + * san_dgpu_notifier_unregister() - Unregister a SAN dGPU notifier.
  14470. + * @nb: The notifier-block to unregister.
  14471. + */
  14472. +int san_dgpu_notifier_unregister(struct notifier_block *nb)
  14473. +{
  14474. + return blocking_notifier_chain_unregister(&san_rqsg_if.nh, nb);
  14475. +}
  14476. +EXPORT_SYMBOL_GPL(san_dgpu_notifier_unregister);
  14477. +
  14478. +static int san_dgpu_notifier_call(struct san_dgpu_event *evt)
  14479. +{
  14480. + int ret;
  14481. +
  14482. + ret = blocking_notifier_call_chain(&san_rqsg_if.nh, evt->command, evt);
  14483. + return notifier_to_errno(ret);
  14484. +}
  14485. +
  14486. +
  14487. +/* -- ACPI _DSM event relay. ------------------------------------------------ */
  14488. +
  14489. +#define SAN_DSM_REVISION 0
  14490. +
  14491. +/* 93b666c5-70c6-469f-a215-3d487c91ab3c */
  14492. +static const guid_t SAN_DSM_UUID =
  14493. + GUID_INIT(0x93b666c5, 0x70c6, 0x469f, 0xa2, 0x15, 0x3d,
  14494. + 0x48, 0x7c, 0x91, 0xab, 0x3c);
  14495. +
  14496. +enum san_dsm_event_fn {
  14497. + SAN_DSM_EVENT_FN_BAT1_STAT = 0x03,
  14498. + SAN_DSM_EVENT_FN_BAT1_INFO = 0x04,
  14499. + SAN_DSM_EVENT_FN_ADP1_STAT = 0x05,
  14500. + SAN_DSM_EVENT_FN_ADP1_INFO = 0x06,
  14501. + SAN_DSM_EVENT_FN_BAT2_STAT = 0x07,
  14502. + SAN_DSM_EVENT_FN_BAT2_INFO = 0x08,
  14503. + SAN_DSM_EVENT_FN_THERMAL = 0x09,
  14504. + SAN_DSM_EVENT_FN_DPTF = 0x0a,
  14505. +};
  14506. +
  14507. +enum sam_event_cid_bat {
  14508. + SAM_EVENT_CID_BAT_BIX = 0x15,
  14509. + SAM_EVENT_CID_BAT_BST = 0x16,
  14510. + SAM_EVENT_CID_BAT_ADP = 0x17,
  14511. + SAM_EVENT_CID_BAT_PROT = 0x18,
  14512. + SAM_EVENT_CID_BAT_DPTF = 0x4f,
  14513. +};
  14514. +
  14515. +enum sam_event_cid_tmp {
  14516. + SAM_EVENT_CID_TMP_TRIP = 0x0b,
  14517. +};
  14518. +
  14519. +struct san_event_work {
  14520. + struct delayed_work work;
  14521. + struct device *dev;
  14522. + struct ssam_event event; /* must be last */
  14523. +};
  14524. +
  14525. +static int san_acpi_notify_event(struct device *dev, u64 func,
  14526. + union acpi_object *param)
  14527. +{
  14528. + acpi_handle san = ACPI_HANDLE(dev);
  14529. + union acpi_object *obj;
  14530. + int status = 0;
  14531. +
  14532. + if (!acpi_check_dsm(san, &SAN_DSM_UUID, SAN_DSM_REVISION, 1 << func))
  14533. + return 0;
  14534. +
  14535. + dev_dbg(dev, "notify event %#04llx\n", func);
  14536. +
  14537. + obj = acpi_evaluate_dsm_typed(san, &SAN_DSM_UUID, SAN_DSM_REVISION,
  14538. + func, param, ACPI_TYPE_BUFFER);
  14539. + if (!obj)
  14540. + return -EFAULT;
  14541. +
  14542. + if (obj->buffer.length != 1 || obj->buffer.pointer[0] != 0) {
  14543. + dev_err(dev, "got unexpected result from _DSM\n");
  14544. + status = -EPROTO;
  14545. + }
  14546. +
  14547. + ACPI_FREE(obj);
  14548. + return status;
  14549. +}
  14550. +
  14551. +static int san_evt_bat_adp(struct device *dev, const struct ssam_event *event)
  14552. +{
  14553. + int status;
  14554. +
  14555. + status = san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_ADP1_STAT, NULL);
  14556. + if (status)
  14557. + return status;
  14558. +
  14559. + /*
  14560. + * Ensure that the battery states get updated correctly. When the
  14561. + * battery is fully charged and an adapter is plugged in, it sometimes
  14562. + * is not updated correctly, instead showing it as charging.
  14563. + * Explicitly trigger battery updates to fix this.
  14564. + */
  14565. +
  14566. + status = san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_BAT1_STAT, NULL);
  14567. + if (status)
  14568. + return status;
  14569. +
  14570. + return san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_BAT2_STAT, NULL);
  14571. +}
  14572. +
  14573. +static int san_evt_bat_bix(struct device *dev, const struct ssam_event *event)
  14574. +{
  14575. + enum san_dsm_event_fn fn;
  14576. +
  14577. + if (event->instance_id == 0x02)
  14578. + fn = SAN_DSM_EVENT_FN_BAT2_INFO;
  14579. + else
  14580. + fn = SAN_DSM_EVENT_FN_BAT1_INFO;
  14581. +
  14582. + return san_acpi_notify_event(dev, fn, NULL);
  14583. +}
  14584. +
  14585. +static int san_evt_bat_bst(struct device *dev, const struct ssam_event *event)
  14586. +{
  14587. + enum san_dsm_event_fn fn;
  14588. +
  14589. + if (event->instance_id == 0x02)
  14590. + fn = SAN_DSM_EVENT_FN_BAT2_STAT;
  14591. + else
  14592. + fn = SAN_DSM_EVENT_FN_BAT1_STAT;
  14593. +
  14594. + return san_acpi_notify_event(dev, fn, NULL);
  14595. +}
  14596. +
  14597. +static int san_evt_bat_dptf(struct device *dev, const struct ssam_event *event)
  14598. +{
  14599. + union acpi_object payload;
  14600. +
  14601. + /*
  14602. + * The Surface ACPI expects a buffer and not a package. It specifically
  14603. + * checks for ObjectType (Arg3) == 0x03. This will cause a warning in
  14604. + * acpica/nsarguments.c, but that warning can be safely ignored.
  14605. + */
  14606. + payload.type = ACPI_TYPE_BUFFER;
  14607. + payload.buffer.length = event->length;
  14608. + payload.buffer.pointer = (u8 *)&event->data[0];
  14609. +
  14610. + return san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_DPTF, &payload);
  14611. +}
  14612. +
  14613. +static unsigned long san_evt_bat_delay(u8 cid)
  14614. +{
  14615. + switch (cid) {
  14616. + case SAM_EVENT_CID_BAT_ADP:
  14617. + /*
  14618. + * Wait for battery state to update before signaling adapter
  14619. + * change.
  14620. + */
  14621. + return msecs_to_jiffies(5000);
  14622. +
  14623. + case SAM_EVENT_CID_BAT_BST:
  14624. + /* Ensure we do not miss anything important due to caching. */
  14625. + return msecs_to_jiffies(2000);
  14626. +
  14627. + default:
  14628. + return 0;
  14629. + }
  14630. +}
  14631. +
  14632. +static bool san_evt_bat(const struct ssam_event *event, struct device *dev)
  14633. +{
  14634. + int status;
  14635. +
  14636. + switch (event->command_id) {
  14637. + case SAM_EVENT_CID_BAT_BIX:
  14638. + status = san_evt_bat_bix(dev, event);
  14639. + break;
  14640. +
  14641. + case SAM_EVENT_CID_BAT_BST:
  14642. + status = san_evt_bat_bst(dev, event);
  14643. + break;
  14644. +
  14645. + case SAM_EVENT_CID_BAT_ADP:
  14646. + status = san_evt_bat_adp(dev, event);
  14647. + break;
  14648. +
  14649. + case SAM_EVENT_CID_BAT_PROT:
  14650. + /*
  14651. + * TODO: Implement support for battery protection status change
  14652. + * event.
  14653. + */
  14654. + return true;
  14655. +
  14656. + case SAM_EVENT_CID_BAT_DPTF:
  14657. + status = san_evt_bat_dptf(dev, event);
  14658. + break;
  14659. +
  14660. + default:
  14661. + return false;
  14662. + }
  14663. +
  14664. + if (status) {
  14665. + dev_err(dev, "error handling power event (cid = %#04x)\n",
  14666. + event->command_id);
  14667. + }
  14668. +
  14669. + return true;
  14670. +}
  14671. +
  14672. +static void san_evt_bat_workfn(struct work_struct *work)
  14673. +{
  14674. + struct san_event_work *ev;
  14675. +
  14676. + ev = container_of(work, struct san_event_work, work.work);
  14677. + san_evt_bat(&ev->event, ev->dev);
  14678. + kfree(ev);
  14679. +}
  14680. +
  14681. +static u32 san_evt_bat_nf(struct ssam_event_notifier *nf,
  14682. + const struct ssam_event *event)
  14683. +{
  14684. + struct san_data *d = to_san_data(nf, nf_bat);
  14685. + struct san_event_work *work;
  14686. + unsigned long delay = san_evt_bat_delay(event->command_id);
  14687. +
  14688. + if (delay == 0)
  14689. + return san_evt_bat(event, d->dev) ? SSAM_NOTIF_HANDLED : 0;
  14690. +
  14691. + work = kzalloc(sizeof(*work) + event->length, GFP_KERNEL);
  14692. + if (!work)
  14693. + return ssam_notifier_from_errno(-ENOMEM);
  14694. +
  14695. + INIT_DELAYED_WORK(&work->work, san_evt_bat_workfn);
  14696. + work->dev = d->dev;
  14697. +
  14698. + memcpy(&work->event, event, sizeof(struct ssam_event) + event->length);
  14699. +
  14700. + schedule_delayed_work(&work->work, delay);
  14701. + return SSAM_NOTIF_HANDLED;
  14702. +}
  14703. +
  14704. +static int san_evt_tmp_trip(struct device *dev, const struct ssam_event *event)
  14705. +{
  14706. + union acpi_object param;
  14707. +
  14708. + /*
  14709. + * The Surface ACPI expects an integer and not a package. This will
  14710. + * cause a warning in acpica/nsarguments.c, but that warning can be
  14711. + * safely ignored.
  14712. + */
  14713. + param.type = ACPI_TYPE_INTEGER;
  14714. + param.integer.value = event->instance_id;
  14715. +
  14716. + return san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_THERMAL, &param);
  14717. +}
  14718. +
  14719. +static bool san_evt_tmp(const struct ssam_event *event, struct device *dev)
  14720. +{
  14721. + int status;
  14722. +
  14723. + switch (event->command_id) {
  14724. + case SAM_EVENT_CID_TMP_TRIP:
  14725. + status = san_evt_tmp_trip(dev, event);
  14726. + break;
  14727. +
  14728. + default:
  14729. + return false;
  14730. + }
  14731. +
  14732. + if (status) {
  14733. + dev_err(dev, "error handling thermal event (cid = %#04x)\n",
  14734. + event->command_id);
  14735. + }
  14736. +
  14737. + return true;
  14738. +}
  14739. +
  14740. +static u32 san_evt_tmp_nf(struct ssam_event_notifier *nf,
  14741. + const struct ssam_event *event)
  14742. +{
  14743. + struct san_data *d = to_san_data(nf, nf_tmp);
  14744. +
  14745. + return san_evt_tmp(event, d->dev) ? SSAM_NOTIF_HANDLED : 0;
  14746. +}
  14747. +
  14748. +
  14749. +/* -- ACPI GSB OperationRegion handler -------------------------------------- */
  14750. +
  14751. +struct gsb_data_in {
  14752. + u8 cv;
  14753. +} __packed;
  14754. +
  14755. +struct gsb_data_rqsx {
  14756. + u8 cv; /* Command value (san_gsb_request_cv). */
  14757. + u8 tc; /* Target category. */
  14758. + u8 tid; /* Target ID. */
  14759. + u8 iid; /* Instance ID. */
  14760. + u8 snc; /* Expect-response-flag. */
  14761. + u8 cid; /* Command ID. */
  14762. + u16 cdl; /* Payload length. */
  14763. + u8 pld[]; /* Payload. */
  14764. +} __packed;
  14765. +
  14766. +struct gsb_data_etwl {
  14767. + u8 cv; /* Command value (should be 0x02). */
  14768. + u8 etw3; /* Unknown. */
  14769. + u8 etw4; /* Unknown. */
  14770. + u8 msg[]; /* Error message (ASCIIZ). */
  14771. +} __packed;
  14772. +
  14773. +struct gsb_data_out {
  14774. + u8 status; /* _SSH communication status. */
  14775. + u8 len; /* _SSH payload length. */
  14776. + u8 pld[]; /* _SSH payload. */
  14777. +} __packed;
  14778. +
  14779. +union gsb_buffer_data {
  14780. + struct gsb_data_in in; /* Common input. */
  14781. + struct gsb_data_rqsx rqsx; /* RQSX input. */
  14782. + struct gsb_data_etwl etwl; /* ETWL input. */
  14783. + struct gsb_data_out out; /* Output. */
  14784. +};
  14785. +
  14786. +struct gsb_buffer {
  14787. + u8 status; /* GSB AttribRawProcess status. */
  14788. + u8 len; /* GSB AttribRawProcess length. */
  14789. + union gsb_buffer_data data;
  14790. +} __packed;
  14791. +
  14792. +#define SAN_GSB_MAX_RQSX_PAYLOAD (U8_MAX - 2 - sizeof(struct gsb_data_rqsx))
  14793. +#define SAN_GSB_MAX_RESPONSE (U8_MAX - 2 - sizeof(struct gsb_data_out))
  14794. +
  14795. +#define SAN_GSB_COMMAND 0
  14796. +
  14797. +enum san_gsb_request_cv {
  14798. + SAN_GSB_REQUEST_CV_RQST = 0x01,
  14799. + SAN_GSB_REQUEST_CV_ETWL = 0x02,
  14800. + SAN_GSB_REQUEST_CV_RQSG = 0x03,
  14801. +};
  14802. +
  14803. +#define SAN_REQUEST_NUM_TRIES 5
  14804. +
  14805. +static acpi_status san_etwl(struct san_data *d, struct gsb_buffer *b)
  14806. +{
  14807. + struct gsb_data_etwl *etwl = &b->data.etwl;
  14808. +
  14809. + if (b->len < sizeof(struct gsb_data_etwl)) {
  14810. + dev_err(d->dev, "invalid ETWL package (len = %d)\n", b->len);
  14811. + return AE_OK;
  14812. + }
  14813. +
  14814. + dev_err(d->dev, "ETWL(%#04x, %#04x): %.*s\n", etwl->etw3, etwl->etw4,
  14815. + (unsigned int)(b->len - sizeof(struct gsb_data_etwl)),
  14816. + (char *)etwl->msg);
  14817. +
  14818. + /* Indicate success. */
  14819. + b->status = 0x00;
  14820. + b->len = 0x00;
  14821. +
  14822. + return AE_OK;
  14823. +}
  14824. +
  14825. +static
  14826. +struct gsb_data_rqsx *san_validate_rqsx(struct device *dev, const char *type,
  14827. + struct gsb_buffer *b)
  14828. +{
  14829. + struct gsb_data_rqsx *rqsx = &b->data.rqsx;
  14830. +
  14831. + if (b->len < sizeof(struct gsb_data_rqsx)) {
  14832. + dev_err(dev, "invalid %s package (len = %d)\n", type, b->len);
  14833. + return NULL;
  14834. + }
  14835. +
  14836. + if (get_unaligned(&rqsx->cdl) != b->len - sizeof(struct gsb_data_rqsx)) {
  14837. + dev_err(dev, "bogus %s package (len = %d, cdl = %d)\n",
  14838. + type, b->len, get_unaligned(&rqsx->cdl));
  14839. + return NULL;
  14840. + }
  14841. +
  14842. + if (get_unaligned(&rqsx->cdl) > SAN_GSB_MAX_RQSX_PAYLOAD) {
  14843. + dev_err(dev, "payload for %s package too large (cdl = %d)\n",
  14844. + type, get_unaligned(&rqsx->cdl));
  14845. + return NULL;
  14846. + }
  14847. +
  14848. + return rqsx;
  14849. +}
  14850. +
  14851. +static void gsb_rqsx_response_error(struct gsb_buffer *gsb, int status)
  14852. +{
  14853. + gsb->status = 0x00;
  14854. + gsb->len = 0x02;
  14855. + gsb->data.out.status = (u8)(-status);
  14856. + gsb->data.out.len = 0x00;
  14857. +}
  14858. +
  14859. +static void gsb_rqsx_response_success(struct gsb_buffer *gsb, u8 *ptr, size_t len)
  14860. +{
  14861. + gsb->status = 0x00;
  14862. + gsb->len = len + 2;
  14863. + gsb->data.out.status = 0x00;
  14864. + gsb->data.out.len = len;
  14865. +
  14866. + if (len)
  14867. + memcpy(&gsb->data.out.pld[0], ptr, len);
  14868. +}
  14869. +
  14870. +static acpi_status san_rqst_fixup_suspended(struct san_data *d,
  14871. + struct ssam_request *rqst,
  14872. + struct gsb_buffer *gsb)
  14873. +{
  14874. + if (rqst->target_category == SSAM_SSH_TC_BAS && rqst->command_id == 0x0D) {
  14875. + u8 base_state = 1;
  14876. +
  14877. + /* Base state quirk:
  14878. + * The base state may be queried from ACPI when the EC is still
  14879. + * suspended. In this case it will return '-EPERM'. This query
  14880. + * will only be triggered from the ACPI lid GPE interrupt, thus
  14881. + * we are either in laptop or studio mode (base status 0x01 or
  14882. + * 0x02). Furthermore, we will only get here if the device (and
  14883. + * EC) have been suspended.
  14884. + *
  14885. + * We now assume that the device is in laptop mode (0x01). This
  14886. + * has the drawback that it will wake the device when unfolding
  14887. + * it in studio mode, but it also allows us to avoid actively
  14888. + * waiting for the EC to wake up, which may incur a notable
  14889. + * delay.
  14890. + */
  14891. +
  14892. + dev_dbg(d->dev, "rqst: fixup: base-state quirk\n");
  14893. +
  14894. + gsb_rqsx_response_success(gsb, &base_state, sizeof(base_state));
  14895. + return AE_OK;
  14896. + }
  14897. +
  14898. + gsb_rqsx_response_error(gsb, -ENXIO);
  14899. + return AE_OK;
  14900. +}
  14901. +
  14902. +static acpi_status san_rqst(struct san_data *d, struct gsb_buffer *buffer)
  14903. +{
  14904. + u8 rspbuf[SAN_GSB_MAX_RESPONSE];
  14905. + struct gsb_data_rqsx *gsb_rqst;
  14906. + struct ssam_request rqst;
  14907. + struct ssam_response rsp;
  14908. + int status = 0;
  14909. +
  14910. + gsb_rqst = san_validate_rqsx(d->dev, "RQST", buffer);
  14911. + if (!gsb_rqst)
  14912. + return AE_OK;
  14913. +
  14914. + rqst.target_category = gsb_rqst->tc;
  14915. + rqst.target_id = gsb_rqst->tid;
  14916. + rqst.command_id = gsb_rqst->cid;
  14917. + rqst.instance_id = gsb_rqst->iid;
  14918. + rqst.flags = gsb_rqst->snc ? SSAM_REQUEST_HAS_RESPONSE : 0;
  14919. + rqst.length = get_unaligned(&gsb_rqst->cdl);
  14920. + rqst.payload = &gsb_rqst->pld[0];
  14921. +
  14922. + rsp.capacity = ARRAY_SIZE(rspbuf);
  14923. + rsp.length = 0;
  14924. + rsp.pointer = &rspbuf[0];
  14925. +
  14926. + /* Handle suspended device. */
  14927. + if (d->dev->power.is_suspended) {
  14928. + dev_warn(d->dev, "rqst: device is suspended, not executing\n");
  14929. + return san_rqst_fixup_suspended(d, &rqst, buffer);
  14930. + }
  14931. +
  14932. + status = __ssam_retry(ssam_request_sync_onstack, SAN_REQUEST_NUM_TRIES,
  14933. + d->ctrl, &rqst, &rsp, SAN_GSB_MAX_RQSX_PAYLOAD);
  14934. +
  14935. + if (!status) {
  14936. + gsb_rqsx_response_success(buffer, rsp.pointer, rsp.length);
  14937. + } else {
  14938. + dev_err(d->dev, "rqst: failed with error %d\n", status);
  14939. + gsb_rqsx_response_error(buffer, status);
  14940. + }
  14941. +
  14942. + return AE_OK;
  14943. +}
  14944. +
  14945. +static acpi_status san_rqsg(struct san_data *d, struct gsb_buffer *buffer)
  14946. +{
  14947. + struct gsb_data_rqsx *gsb_rqsg;
  14948. + struct san_dgpu_event evt;
  14949. + int status;
  14950. +
  14951. + gsb_rqsg = san_validate_rqsx(d->dev, "RQSG", buffer);
  14952. + if (!gsb_rqsg)
  14953. + return AE_OK;
  14954. +
  14955. + evt.category = gsb_rqsg->tc;
  14956. + evt.target = gsb_rqsg->tid;
  14957. + evt.command = gsb_rqsg->cid;
  14958. + evt.instance = gsb_rqsg->iid;
  14959. + evt.length = get_unaligned(&gsb_rqsg->cdl);
  14960. + evt.payload = &gsb_rqsg->pld[0];
  14961. +
  14962. + status = san_dgpu_notifier_call(&evt);
  14963. + if (!status) {
  14964. + gsb_rqsx_response_success(buffer, NULL, 0);
  14965. + } else {
  14966. + dev_err(d->dev, "rqsg: failed with error %d\n", status);
  14967. + gsb_rqsx_response_error(buffer, status);
  14968. + }
  14969. +
  14970. + return AE_OK;
  14971. +}
  14972. +
  14973. +static acpi_status san_opreg_handler(u32 function, acpi_physical_address command,
  14974. + u32 bits, u64 *value64, void *opreg_context,
  14975. + void *region_context)
  14976. +{
  14977. + struct san_data *d = to_san_data(opreg_context, info);
  14978. + struct gsb_buffer *buffer = (struct gsb_buffer *)value64;
  14979. + int accessor_type = (function & 0xFFFF0000) >> 16;
  14980. +
  14981. + if (command != SAN_GSB_COMMAND) {
  14982. + dev_warn(d->dev, "unsupported command: %#04llx\n", command);
  14983. + return AE_OK;
  14984. + }
  14985. +
  14986. + if (accessor_type != ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS) {
  14987. + dev_err(d->dev, "invalid access type: %#04x\n", accessor_type);
  14988. + return AE_OK;
  14989. + }
  14990. +
  14991. + /* Buffer must have at least contain the command-value. */
  14992. + if (buffer->len == 0) {
  14993. + dev_err(d->dev, "request-package too small\n");
  14994. + return AE_OK;
  14995. + }
  14996. +
  14997. + switch (buffer->data.in.cv) {
  14998. + case SAN_GSB_REQUEST_CV_RQST:
  14999. + return san_rqst(d, buffer);
  15000. +
  15001. + case SAN_GSB_REQUEST_CV_ETWL:
  15002. + return san_etwl(d, buffer);
  15003. +
  15004. + case SAN_GSB_REQUEST_CV_RQSG:
  15005. + return san_rqsg(d, buffer);
  15006. +
  15007. + default:
  15008. + dev_warn(d->dev, "unsupported SAN0 request (cv: %#04x)\n",
  15009. + buffer->data.in.cv);
  15010. + return AE_OK;
  15011. + }
  15012. +}
  15013. +
  15014. +
  15015. +/* -- Driver setup. --------------------------------------------------------- */
  15016. +
  15017. +static int san_events_register(struct platform_device *pdev)
  15018. +{
  15019. + struct san_data *d = platform_get_drvdata(pdev);
  15020. + int status;
  15021. +
  15022. + d->nf_bat.base.priority = 1;
  15023. + d->nf_bat.base.fn = san_evt_bat_nf;
  15024. + d->nf_bat.event.reg = SSAM_EVENT_REGISTRY_SAM;
  15025. + d->nf_bat.event.id.target_category = SSAM_SSH_TC_BAT;
  15026. + d->nf_bat.event.id.instance = 0;
  15027. + d->nf_bat.event.mask = SSAM_EVENT_MASK_TARGET;
  15028. + d->nf_bat.event.flags = SSAM_EVENT_SEQUENCED;
  15029. +
  15030. + d->nf_tmp.base.priority = 1;
  15031. + d->nf_tmp.base.fn = san_evt_tmp_nf;
  15032. + d->nf_tmp.event.reg = SSAM_EVENT_REGISTRY_SAM;
  15033. + d->nf_tmp.event.id.target_category = SSAM_SSH_TC_TMP;
  15034. + d->nf_tmp.event.id.instance = 0;
  15035. + d->nf_tmp.event.mask = SSAM_EVENT_MASK_TARGET;
  15036. + d->nf_tmp.event.flags = SSAM_EVENT_SEQUENCED;
  15037. +
  15038. + status = ssam_notifier_register(d->ctrl, &d->nf_bat);
  15039. + if (status)
  15040. + return status;
  15041. +
  15042. + status = ssam_notifier_register(d->ctrl, &d->nf_tmp);
  15043. + if (status)
  15044. + ssam_notifier_unregister(d->ctrl, &d->nf_bat);
  15045. +
  15046. + return status;
  15047. +}
  15048. +
  15049. +static void san_events_unregister(struct platform_device *pdev)
  15050. +{
  15051. + struct san_data *d = platform_get_drvdata(pdev);
  15052. +
  15053. + ssam_notifier_unregister(d->ctrl, &d->nf_bat);
  15054. + ssam_notifier_unregister(d->ctrl, &d->nf_tmp);
  15055. +}
  15056. +
  15057. +#define san_consumer_printk(level, dev, handle, fmt, ...) \
  15058. +do { \
  15059. + char *path = "<error getting consumer path>"; \
  15060. + struct acpi_buffer buffer = { \
  15061. + .length = ACPI_ALLOCATE_BUFFER, \
  15062. + .pointer = NULL, \
  15063. + }; \
  15064. + \
  15065. + if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) \
  15066. + path = buffer.pointer; \
  15067. + \
  15068. + dev_##level(dev, "[%s]: " fmt, path, ##__VA_ARGS__); \
  15069. + kfree(buffer.pointer); \
  15070. +} while (0)
  15071. +
  15072. +#define san_consumer_dbg(dev, handle, fmt, ...) \
  15073. + san_consumer_printk(dbg, dev, handle, fmt, ##__VA_ARGS__)
  15074. +
  15075. +#define san_consumer_warn(dev, handle, fmt, ...) \
  15076. + san_consumer_printk(warn, dev, handle, fmt, ##__VA_ARGS__)
  15077. +
  15078. +static bool is_san_consumer(struct platform_device *pdev, acpi_handle handle)
  15079. +{
  15080. + struct acpi_handle_list dep_devices;
  15081. + acpi_handle supplier = ACPI_HANDLE(&pdev->dev);
  15082. + acpi_status status;
  15083. + int i;
  15084. +
  15085. + if (!acpi_has_method(handle, "_DEP"))
  15086. + return false;
  15087. +
  15088. + status = acpi_evaluate_reference(handle, "_DEP", NULL, &dep_devices);
  15089. + if (ACPI_FAILURE(status)) {
  15090. + san_consumer_dbg(&pdev->dev, handle, "failed to evaluate _DEP\n");
  15091. + return false;
  15092. + }
  15093. +
  15094. + for (i = 0; i < dep_devices.count; i++) {
  15095. + if (dep_devices.handles[i] == supplier)
  15096. + return true;
  15097. + }
  15098. +
  15099. + return false;
  15100. +}
  15101. +
  15102. +static acpi_status san_consumer_setup(acpi_handle handle, u32 lvl,
  15103. + void *context, void **rv)
  15104. +{
  15105. + const u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_SUPPLIER;
  15106. + struct platform_device *pdev = context;
  15107. + struct acpi_device *adev;
  15108. + struct device_link *link;
  15109. +
  15110. + if (!is_san_consumer(pdev, handle))
  15111. + return AE_OK;
  15112. +
  15113. + /* Ignore ACPI devices that are not present. */
  15114. + if (acpi_bus_get_device(handle, &adev) != 0)
  15115. + return AE_OK;
  15116. +
  15117. + san_consumer_dbg(&pdev->dev, handle, "creating device link\n");
  15118. +
  15119. + /* Try to set up device links, ignore but log errors. */
  15120. + link = device_link_add(&adev->dev, &pdev->dev, flags);
  15121. + if (!link) {
  15122. + san_consumer_warn(&pdev->dev, handle, "failed to create device link\n");
  15123. + return AE_OK;
  15124. + }
  15125. +
  15126. + return AE_OK;
  15127. +}
  15128. +
  15129. +static int san_consumer_links_setup(struct platform_device *pdev)
  15130. +{
  15131. + acpi_status status;
  15132. +
  15133. + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
  15134. + ACPI_UINT32_MAX, san_consumer_setup, NULL,
  15135. + pdev, NULL);
  15136. +
  15137. + return status ? -EFAULT : 0;
  15138. +}
  15139. +
  15140. +static int san_probe(struct platform_device *pdev)
  15141. +{
  15142. + acpi_handle san = ACPI_HANDLE(&pdev->dev);
  15143. + struct ssam_controller *ctrl;
  15144. + struct san_data *data;
  15145. + acpi_status astatus;
  15146. + int status;
  15147. +
  15148. + ctrl = ssam_client_bind(&pdev->dev);
  15149. + if (IS_ERR(ctrl))
  15150. + return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl);
  15151. +
  15152. + status = san_consumer_links_setup(pdev);
  15153. + if (status)
  15154. + return status;
  15155. +
  15156. + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
  15157. + if (!data)
  15158. + return -ENOMEM;
  15159. +
  15160. + data->dev = &pdev->dev;
  15161. + data->ctrl = ctrl;
  15162. +
  15163. + platform_set_drvdata(pdev, data);
  15164. +
  15165. + astatus = acpi_install_address_space_handler(san, ACPI_ADR_SPACE_GSBUS,
  15166. + &san_opreg_handler, NULL,
  15167. + &data->info);
  15168. + if (ACPI_FAILURE(astatus))
  15169. + return -ENXIO;
  15170. +
  15171. + status = san_events_register(pdev);
  15172. + if (status)
  15173. + goto err_enable_events;
  15174. +
  15175. + status = san_set_rqsg_interface_device(&pdev->dev);
  15176. + if (status)
  15177. + goto err_install_dev;
  15178. +
  15179. + acpi_walk_dep_device_list(san);
  15180. + return 0;
  15181. +
  15182. +err_install_dev:
  15183. + san_events_unregister(pdev);
  15184. +err_enable_events:
  15185. + acpi_remove_address_space_handler(san, ACPI_ADR_SPACE_GSBUS,
  15186. + &san_opreg_handler);
  15187. + return status;
  15188. +}
  15189. +
  15190. +static int san_remove(struct platform_device *pdev)
  15191. +{
  15192. + acpi_handle san = ACPI_HANDLE(&pdev->dev);
  15193. +
  15194. + san_set_rqsg_interface_device(NULL);
  15195. + acpi_remove_address_space_handler(san, ACPI_ADR_SPACE_GSBUS,
  15196. + &san_opreg_handler);
  15197. + san_events_unregister(pdev);
  15198. +
  15199. + /*
  15200. + * We have unregistered our event sources. Now we need to ensure that
  15201. + * all delayed works they may have spawned are run to completion.
  15202. + */
  15203. + flush_scheduled_work();
  15204. +
  15205. + return 0;
  15206. +}
  15207. +
  15208. +static const struct acpi_device_id san_match[] = {
  15209. + { "MSHW0091" },
  15210. + { },
  15211. +};
  15212. +MODULE_DEVICE_TABLE(acpi, san_match);
  15213. +
  15214. +static struct platform_driver surface_acpi_notify = {
  15215. + .probe = san_probe,
  15216. + .remove = san_remove,
  15217. + .driver = {
  15218. + .name = "surface_acpi_notify",
  15219. + .acpi_match_table = san_match,
  15220. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  15221. + },
  15222. +};
  15223. +module_platform_driver(surface_acpi_notify);
  15224. +
  15225. +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  15226. +MODULE_DESCRIPTION("Surface ACPI Notify driver for Surface System Aggregator Module");
  15227. +MODULE_LICENSE("GPL");
  15228. diff --git a/include/linux/surface_acpi_notify.h b/include/linux/surface_acpi_notify.h
  15229. new file mode 100644
  15230. index 000000000000..8e3e86c7d78c
  15231. --- /dev/null
  15232. +++ b/include/linux/surface_acpi_notify.h
  15233. @@ -0,0 +1,39 @@
  15234. +/* SPDX-License-Identifier: GPL-2.0+ */
  15235. +/*
  15236. + * Interface for Surface ACPI Notify (SAN) driver.
  15237. + *
  15238. + * Provides access to discrete GPU notifications sent from ACPI via the SAN
  15239. + * driver, which are not handled by this driver directly.
  15240. + *
  15241. + * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com>
  15242. + */
  15243. +
  15244. +#ifndef _LINUX_SURFACE_ACPI_NOTIFY_H
  15245. +#define _LINUX_SURFACE_ACPI_NOTIFY_H
  15246. +
  15247. +#include <linux/notifier.h>
  15248. +#include <linux/types.h>
  15249. +
  15250. +/**
  15251. + * struct san_dgpu_event - Discrete GPU ACPI event.
  15252. + * @category: Category of the event.
  15253. + * @target: Target ID of the event source.
  15254. + * @command: Command ID of the event.
  15255. + * @instance: Instance ID of the event source.
  15256. + * @length: Length of the event's payload data (in bytes).
  15257. + * @payload: Pointer to the event's payload data.
  15258. + */
  15259. +struct san_dgpu_event {
  15260. + u8 category;
  15261. + u8 target;
  15262. + u8 command;
  15263. + u8 instance;
  15264. + u16 length;
  15265. + u8 *payload;
  15266. +};
  15267. +
  15268. +int san_client_link(struct device *client);
  15269. +int san_dgpu_notifier_register(struct notifier_block *nb);
  15270. +int san_dgpu_notifier_unregister(struct notifier_block *nb);
  15271. +
  15272. +#endif /* _LINUX_SURFACE_ACPI_NOTIFY_H */
  15273. --
  15274. 2.31.0
  15275. From f4a7514d778da6ff5180ac88e58c53d7573b8ae2 Mon Sep 17 00:00:00 2001
  15276. From: Colin Ian King <colin.king@canonical.com>
  15277. Date: Mon, 11 Jan 2021 14:46:48 +0000
  15278. Subject: [PATCH] platform/surface: fix potential integer overflow on shift of
  15279. a int
  15280. The left shift of int 32 bit integer constant 1 is evaluated using 32 bit
  15281. arithmetic and then passed as a 64 bit function argument. In the case where
  15282. func is 32 or more this can lead to an oveflow. Avoid this by shifting
  15283. using the BIT_ULL macro instead.
  15284. Addresses-Coverity: ("Unintentional integer overflow")
  15285. Fixes: fc00bc8ac1da ("platform/surface: Add Surface ACPI Notify driver")
  15286. Signed-off-by: Colin Ian King <colin.king@canonical.com>
  15287. Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com>
  15288. Link: https://lore.kernel.org/r/20210111144648.20498-1-colin.king@canonical.com
  15289. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  15290. Patchset: surface-sam
  15291. ---
  15292. drivers/platform/surface/surface_acpi_notify.c | 2 +-
  15293. 1 file changed, 1 insertion(+), 1 deletion(-)
  15294. diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c
  15295. index 8cd67a669c86..ef9c1f8e8336 100644
  15296. --- a/drivers/platform/surface/surface_acpi_notify.c
  15297. +++ b/drivers/platform/surface/surface_acpi_notify.c
  15298. @@ -188,7 +188,7 @@ static int san_acpi_notify_event(struct device *dev, u64 func,
  15299. union acpi_object *obj;
  15300. int status = 0;
  15301. - if (!acpi_check_dsm(san, &SAN_DSM_UUID, SAN_DSM_REVISION, 1 << func))
  15302. + if (!acpi_check_dsm(san, &SAN_DSM_UUID, SAN_DSM_REVISION, BIT_ULL(func)))
  15303. return 0;
  15304. dev_dbg(dev, "notify event %#04llx\n", func);
  15305. --
  15306. 2.31.0
  15307. From f459f702ea23d66f9e550b3db3435d27a0491a0e Mon Sep 17 00:00:00 2001
  15308. From: Maximilian Luz <luzmaximilian@gmail.com>
  15309. Date: Mon, 11 Jan 2021 16:48:50 +0100
  15310. Subject: [PATCH] platform/surface: aggregator_cdev: Fix access of
  15311. uninitialized variables
  15312. When copy_struct_from_user() in ssam_cdev_request() fails, we directly
  15313. jump to the 'out' label. In this case, however 'spec' and 'rsp' are not
  15314. initialized, but we still access fields of those variables. Fix this by
  15315. initializing them at the time of their declaration.
  15316. Reported-by: Colin Ian King <colin.king@canonical.com>
  15317. Fixes: 178f6ab77e61 ("platform/surface: Add Surface Aggregator user-space interface")
  15318. Addresses-Coverity: ("Uninitialized pointer read")
  15319. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  15320. Link: https://lore.kernel.org/r/20210111154851.325404-2-luzmaximilian@gmail.com
  15321. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  15322. Patchset: surface-sam
  15323. ---
  15324. drivers/platform/surface/surface_aggregator_cdev.c | 4 ++--
  15325. 1 file changed, 2 insertions(+), 2 deletions(-)
  15326. diff --git a/drivers/platform/surface/surface_aggregator_cdev.c b/drivers/platform/surface/surface_aggregator_cdev.c
  15327. index 340d15b148b9..979340cdd9de 100644
  15328. --- a/drivers/platform/surface/surface_aggregator_cdev.c
  15329. +++ b/drivers/platform/surface/surface_aggregator_cdev.c
  15330. @@ -66,8 +66,8 @@ static long ssam_cdev_request(struct ssam_cdev *cdev, unsigned long arg)
  15331. {
  15332. struct ssam_cdev_request __user *r;
  15333. struct ssam_cdev_request rqst;
  15334. - struct ssam_request spec;
  15335. - struct ssam_response rsp;
  15336. + struct ssam_request spec = {};
  15337. + struct ssam_response rsp = {};
  15338. const void __user *plddata;
  15339. void __user *rspdata;
  15340. int status = 0, ret = 0, tmp;
  15341. --
  15342. 2.31.0
  15343. From 3580c235191512dfffa9b9cdc2ded467c33fe4ce Mon Sep 17 00:00:00 2001
  15344. From: Maximilian Luz <luzmaximilian@gmail.com>
  15345. Date: Mon, 11 Jan 2021 16:48:51 +0100
  15346. Subject: [PATCH] platform/surface: aggregator_cdev: Add comments regarding
  15347. unchecked allocation size
  15348. CI static analysis complains about the allocation size in payload and
  15349. response buffers being unchecked. In general, these allocations should
  15350. be safe as the user-input is u16 and thus limited to U16_MAX, which is
  15351. only slightly larger than the theoretical maximum imposed by the
  15352. underlying SSH protocol.
  15353. All bounds on these values required by the underlying protocol are
  15354. enforced in ssam_request_sync() (or rather the functions called by it),
  15355. thus bounds here are only relevant for allocation.
  15356. Add comments explaining that this should be safe.
  15357. Reported-by: Colin Ian King <colin.king@canonical.com>
  15358. Fixes: 178f6ab77e61 ("platform/surface: Add Surface Aggregator user-space interface")
  15359. Addresses-Coverity: ("Untrusted allocation size")
  15360. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  15361. Link: https://lore.kernel.org/r/20210111154851.325404-3-luzmaximilian@gmail.com
  15362. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  15363. Patchset: surface-sam
  15364. ---
  15365. .../surface/surface_aggregator_cdev.c | 19 +++++++++++++++++++
  15366. 1 file changed, 19 insertions(+)
  15367. diff --git a/drivers/platform/surface/surface_aggregator_cdev.c b/drivers/platform/surface/surface_aggregator_cdev.c
  15368. index 979340cdd9de..79e28fab7e40 100644
  15369. --- a/drivers/platform/surface/surface_aggregator_cdev.c
  15370. +++ b/drivers/platform/surface/surface_aggregator_cdev.c
  15371. @@ -106,6 +106,15 @@ static long ssam_cdev_request(struct ssam_cdev *cdev, unsigned long arg)
  15372. goto out;
  15373. }
  15374. + /*
  15375. + * Note: spec.length is limited to U16_MAX bytes via struct
  15376. + * ssam_cdev_request. This is slightly larger than the
  15377. + * theoretical maximum (SSH_COMMAND_MAX_PAYLOAD_SIZE) of the
  15378. + * underlying protocol (note that nothing remotely this size
  15379. + * should ever be allocated in any normal case). This size is
  15380. + * validated later in ssam_request_sync(), for allocation the
  15381. + * bound imposed by u16 should be enough.
  15382. + */
  15383. spec.payload = kzalloc(spec.length, GFP_KERNEL);
  15384. if (!spec.payload) {
  15385. ret = -ENOMEM;
  15386. @@ -125,6 +134,16 @@ static long ssam_cdev_request(struct ssam_cdev *cdev, unsigned long arg)
  15387. goto out;
  15388. }
  15389. + /*
  15390. + * Note: rsp.capacity is limited to U16_MAX bytes via struct
  15391. + * ssam_cdev_request. This is slightly larger than the
  15392. + * theoretical maximum (SSH_COMMAND_MAX_PAYLOAD_SIZE) of the
  15393. + * underlying protocol (note that nothing remotely this size
  15394. + * should ever be allocated in any normal case). In later use,
  15395. + * this capacity does not have to be strictly bounded, as it
  15396. + * is only used as an output buffer to be written to. For
  15397. + * allocation the bound imposed by u16 should be enough.
  15398. + */
  15399. rsp.pointer = kzalloc(rsp.capacity, GFP_KERNEL);
  15400. if (!rsp.pointer) {
  15401. ret = -ENOMEM;
  15402. --
  15403. 2.31.0
  15404. From 08feed5fe75ced960fb3db8193f1fde8597b2d11 Mon Sep 17 00:00:00 2001
  15405. From: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
  15406. Date: Thu, 14 Jan 2021 09:04:52 +0100
  15407. Subject: [PATCH] platform/surface: aggregator: fix a kernel-doc markup
  15408. A function has a different name between their prototype
  15409. and its kernel-doc markup:
  15410. ../drivers/platform/surface/aggregator/ssh_request_layer.c:1065: warning: expecting prototype for ssh_rtl_tx_start(). Prototype was for ssh_rtl_start() instead
  15411. Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
  15412. Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com>
  15413. Link: https://lore.kernel.org/r/4a6bf33cfbd06654d78294127f2b6d354d073089.1610610937.git.mchehab+huawei@kernel.org
  15414. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  15415. Patchset: surface-sam
  15416. ---
  15417. drivers/platform/surface/aggregator/ssh_request_layer.c | 2 +-
  15418. 1 file changed, 1 insertion(+), 1 deletion(-)
  15419. diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c
  15420. index bb1c862411a2..25db4d638cfa 100644
  15421. --- a/drivers/platform/surface/aggregator/ssh_request_layer.c
  15422. +++ b/drivers/platform/surface/aggregator/ssh_request_layer.c
  15423. @@ -1056,7 +1056,7 @@ void ssh_rtl_destroy(struct ssh_rtl *rtl)
  15424. }
  15425. /**
  15426. - * ssh_rtl_tx_start() - Start request transmitter and receiver.
  15427. + * ssh_rtl_start() - Start request transmitter and receiver.
  15428. * @rtl: The request transport layer.
  15429. *
  15430. * Return: Returns zero on success, a negative error code on failure.
  15431. --
  15432. 2.31.0
  15433. From 58ae3b353f5cf89469766b3f2e2bdc461f145b2c Mon Sep 17 00:00:00 2001
  15434. From: Maximilian Luz <luzmaximilian@gmail.com>
  15435. Date: Thu, 14 Jan 2021 16:08:26 +0100
  15436. Subject: [PATCH] platform/surface: aggregator: Fix kernel-doc references
  15437. Both, ssh_rtl_rx_start() and ssh_rtl_tx_start() functions, do not exist
  15438. and have been consolidated into ssh_rtl_start(). Nevertheless,
  15439. kernel-doc references the former functions. Replace those references
  15440. with references to ssh_rtl_start().
  15441. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  15442. Link: https://lore.kernel.org/r/20210114150826.19109-1-luzmaximilian@gmail.com
  15443. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  15444. Patchset: surface-sam
  15445. ---
  15446. drivers/platform/surface/aggregator/ssh_request_layer.c | 5 ++---
  15447. 1 file changed, 2 insertions(+), 3 deletions(-)
  15448. diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c
  15449. index 25db4d638cfa..52a83a8fcf82 100644
  15450. --- a/drivers/platform/surface/aggregator/ssh_request_layer.c
  15451. +++ b/drivers/platform/surface/aggregator/ssh_request_layer.c
  15452. @@ -1004,9 +1004,8 @@ int ssh_request_init(struct ssh_request *rqst, enum ssam_request_flags flags,
  15453. *
  15454. * Initializes the given request transport layer and associated packet
  15455. * transport layer. Transmitter and receiver threads must be started
  15456. - * separately via ssh_rtl_tx_start() and ssh_rtl_rx_start(), after the
  15457. - * request-layer has been initialized and the lower-level serial device layer
  15458. - * has been set up.
  15459. + * separately via ssh_rtl_start(), after the request-layer has been
  15460. + * initialized and the lower-level serial device layer has been set up.
  15461. *
  15462. * Return: Returns zero on success and a nonzero error code on failure.
  15463. */
  15464. --
  15465. 2.31.0
  15466. From 975e2951520f6cda4c23bbb4a0f4ab81c9a7304b Mon Sep 17 00:00:00 2001
  15467. From: Maximilian Luz <luzmaximilian@gmail.com>
  15468. Date: Tue, 26 Jan 2021 18:22:02 +0100
  15469. Subject: [PATCH] platform/surface: aggregator: Fix braces in if condition with
  15470. unlikely() macro
  15471. The braces of the unlikely() macro inside the if condition only cover
  15472. the subtraction part, not the whole statement. This causes the result of
  15473. the subtraction to be converted to zero or one. While that still works
  15474. in this context, it causes static analysis tools to complain (and is
  15475. just plain wrong).
  15476. Fix the bracket placement and, while at it, simplify the if-condition.
  15477. Also add a comment to the if-condition explaining what we expect the
  15478. result to be and what happens on the failure path, as it seems to have
  15479. caused a bit of confusion.
  15480. This commit should not cause any difference in behavior or generated
  15481. code.
  15482. Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
  15483. Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem")
  15484. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  15485. Link: https://lore.kernel.org/r/20210126172202.1428367-1-luzmaximilian@gmail.com
  15486. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  15487. Patchset: surface-sam
  15488. ---
  15489. .../surface/aggregator/ssh_packet_layer.c | 19 ++++++++++++++++++-
  15490. 1 file changed, 18 insertions(+), 1 deletion(-)
  15491. diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c
  15492. index 74f0faaa2b27..583315db8b02 100644
  15493. --- a/drivers/platform/surface/aggregator/ssh_packet_layer.c
  15494. +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c
  15495. @@ -1694,7 +1694,24 @@ static size_t ssh_ptl_rx_eval(struct ssh_ptl *ptl, struct ssam_span *source)
  15496. /* Find SYN. */
  15497. syn_found = sshp_find_syn(source, &aligned);
  15498. - if (unlikely(aligned.ptr - source->ptr) > 0) {
  15499. + if (unlikely(aligned.ptr != source->ptr)) {
  15500. + /*
  15501. + * We expect aligned.ptr == source->ptr. If this is not the
  15502. + * case, then aligned.ptr > source->ptr and we've encountered
  15503. + * some unexpected data where we'd expect the start of a new
  15504. + * message (i.e. the SYN sequence).
  15505. + *
  15506. + * This can happen when a CRC check for the previous message
  15507. + * failed and we start actively searching for the next one
  15508. + * (via the call to sshp_find_syn() above), or the first bytes
  15509. + * of a message got dropped or corrupted.
  15510. + *
  15511. + * In any case, we issue a warning, send a NAK to the EC to
  15512. + * request re-transmission of any data we haven't acknowledged
  15513. + * yet, and finally, skip everything up to the next SYN
  15514. + * sequence.
  15515. + */
  15516. +
  15517. ptl_warn(ptl, "rx: parser: invalid start of frame, skipping\n");
  15518. /*
  15519. --
  15520. 2.31.0
  15521. From c34c49f35d59cbe74005ec7a1b4fda147272f2ba Mon Sep 17 00:00:00 2001
  15522. From: Maximilian Luz <luzmaximilian@gmail.com>
  15523. Date: Thu, 11 Feb 2021 13:41:49 +0100
  15524. Subject: [PATCH] platform/surface: aggregator: Fix access of unaligned value
  15525. The raw message frame length is unaligned and explicitly marked as
  15526. little endian. It should not be accessed without the appropriate
  15527. accessor functions. Fix this.
  15528. Note that payload.len already contains the correct length after parsing
  15529. via sshp_parse_frame(), so we can simply use that instead.
  15530. Reported-by: kernel-test-robot <lkp@intel.com>
  15531. Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem")
  15532. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  15533. Acked-by: Mark Gross <mgross@linux.intel.com>
  15534. Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
  15535. Link: https://lore.kernel.org/r/20210211124149.2439007-1-luzmaximilian@gmail.com
  15536. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  15537. Patchset: surface-sam
  15538. ---
  15539. drivers/platform/surface/aggregator/ssh_packet_layer.c | 2 +-
  15540. 1 file changed, 1 insertion(+), 1 deletion(-)
  15541. diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c
  15542. index 583315db8b02..15d96eac6811 100644
  15543. --- a/drivers/platform/surface/aggregator/ssh_packet_layer.c
  15544. +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c
  15545. @@ -1774,7 +1774,7 @@ static size_t ssh_ptl_rx_eval(struct ssh_ptl *ptl, struct ssam_span *source)
  15546. break;
  15547. }
  15548. - return aligned.ptr - source->ptr + SSH_MESSAGE_LENGTH(frame->len);
  15549. + return aligned.ptr - source->ptr + SSH_MESSAGE_LENGTH(payload.len);
  15550. }
  15551. static int ssh_ptl_rx_threadfn(void *data)
  15552. --
  15553. 2.31.0
  15554. From 99804626530d972c92ed6670e9f46c901251dba4 Mon Sep 17 00:00:00 2001
  15555. From: Maximilian Luz <luzmaximilian@gmail.com>
  15556. Date: Sun, 7 Feb 2021 03:42:45 +0100
  15557. Subject: [PATCH] platform/surface: Set up Surface Aggregator device registry
  15558. The Surface System Aggregator Module (SSAM) subsystem provides various
  15559. functionalities, which are separated by spreading them across multiple
  15560. devices and corresponding drivers. Parts of that functionality / some of
  15561. those devices, however, can (as far as we currently know) not be
  15562. auto-detected by conventional means. While older (specifically 5th- and
  15563. 6th-)generation models do advertise most of their functionality via
  15564. standard platform devices in ACPI, newer generations do not.
  15565. As we are currently also not aware of any feasible way to query said
  15566. functionalities dynamically, this poses a problem. There is, however, a
  15567. device in ACPI that seems to be used by Windows for identifying
  15568. different Surface models: The Windows Surface Integration Device (WSID).
  15569. This device seems to have a HID corresponding to the overall set of
  15570. functionalities SSAM provides for the associated model.
  15571. This commit introduces a registry providing non-detectable device
  15572. information via software nodes. In addition, a SSAM platform hub driver
  15573. is introduced, which takes care of creating and managing the SSAM
  15574. devices specified in this registry. This approach allows for a
  15575. hierarchical setup akin to ACPI and is easily extendable, e.g. via
  15576. firmware node properties.
  15577. Note that this commit only provides the basis for the platform hub and
  15578. registry, and does not add any content to it. The registry will be
  15579. expanded in subsequent commits.
  15580. Patchset: surface-sam
  15581. ---
  15582. MAINTAINERS | 1 +
  15583. drivers/platform/surface/Kconfig | 27 ++
  15584. drivers/platform/surface/Makefile | 1 +
  15585. .../surface/surface_aggregator_registry.c | 284 ++++++++++++++++++
  15586. 4 files changed, 313 insertions(+)
  15587. create mode 100644 drivers/platform/surface/surface_aggregator_registry.c
  15588. diff --git a/MAINTAINERS b/MAINTAINERS
  15589. index dfe4f4e1da7a..1fd2fd35d5b7 100644
  15590. --- a/MAINTAINERS
  15591. +++ b/MAINTAINERS
  15592. @@ -11815,6 +11815,7 @@ F: Documentation/driver-api/surface_aggregator/
  15593. F: drivers/platform/surface/aggregator/
  15594. F: drivers/platform/surface/surface_acpi_notify.c
  15595. F: drivers/platform/surface/surface_aggregator_cdev.c
  15596. +F: drivers/platform/surface/surface_aggregator_registry.c
  15597. F: include/linux/surface_acpi_notify.h
  15598. F: include/linux/surface_aggregator/
  15599. F: include/uapi/linux/surface_aggregator/
  15600. diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig
  15601. index b0b91fa2f6a1..97e08dd35992 100644
  15602. --- a/drivers/platform/surface/Kconfig
  15603. +++ b/drivers/platform/surface/Kconfig
  15604. @@ -77,6 +77,33 @@ config SURFACE_AGGREGATOR_CDEV
  15605. The provided interface is intended for debugging and development only,
  15606. and should not be used otherwise.
  15607. +config SURFACE_AGGREGATOR_REGISTRY
  15608. + tristate "Surface System Aggregator Module Device Registry"
  15609. + depends on SURFACE_AGGREGATOR
  15610. + depends on SURFACE_AGGREGATOR_BUS
  15611. + help
  15612. + Device-registry and device-hubs for Surface System Aggregator Module
  15613. + (SSAM) devices.
  15614. +
  15615. + Provides a module and driver which act as a device-registry for SSAM
  15616. + client devices that cannot be detected automatically, e.g. via ACPI.
  15617. + Such devices are instead provided via this registry and attached via
  15618. + device hubs, also provided in this module.
  15619. +
  15620. + Devices provided via this registry are:
  15621. + - Platform profile (performance-/cooling-mode) device (5th- and later
  15622. + generations).
  15623. + - Battery/AC devices (7th-generation).
  15624. + - HID input devices (7th-generation).
  15625. +
  15626. + Select M (recommended) or Y here if you want support for the above
  15627. + mentioned devices on the corresponding Surface models. Without this
  15628. + module, the respective devices will not be instantiated and thus any
  15629. + functionality provided by them will be missing, even when drivers for
  15630. + these devices are present. In other words, this module only provides
  15631. + the respective client devices. Drivers for these devices still need to
  15632. + be selected via the other options.
  15633. +
  15634. config SURFACE_BOOK1_DGPU_SWITCH
  15635. tristate "Surface Book 1 dGPU Switch Driver"
  15636. depends on SYSFS
  15637. diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile
  15638. index 72f4d9fbb6be..30a212aefd35 100644
  15639. --- a/drivers/platform/surface/Makefile
  15640. +++ b/drivers/platform/surface/Makefile
  15641. @@ -10,6 +10,7 @@ obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o
  15642. obj-$(CONFIG_SURFACE_ACPI_NOTIFY) += surface_acpi_notify.o
  15643. obj-$(CONFIG_SURFACE_AGGREGATOR) += aggregator/
  15644. obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o
  15645. +obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o
  15646. obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o
  15647. obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o
  15648. obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
  15649. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  15650. new file mode 100644
  15651. index 000000000000..a051d941ad96
  15652. --- /dev/null
  15653. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  15654. @@ -0,0 +1,284 @@
  15655. +// SPDX-License-Identifier: GPL-2.0+
  15656. +/*
  15657. + * Surface System Aggregator Module (SSAM) client device registry.
  15658. + *
  15659. + * Registry for non-platform/non-ACPI SSAM client devices, i.e. devices that
  15660. + * cannot be auto-detected. Provides device-hubs and performs instantiation
  15661. + * for these devices.
  15662. + *
  15663. + * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com>
  15664. + */
  15665. +
  15666. +#include <linux/acpi.h>
  15667. +#include <linux/kernel.h>
  15668. +#include <linux/module.h>
  15669. +#include <linux/platform_device.h>
  15670. +#include <linux/property.h>
  15671. +
  15672. +#include <linux/surface_aggregator/controller.h>
  15673. +#include <linux/surface_aggregator/device.h>
  15674. +
  15675. +
  15676. +/* -- Device registry. ------------------------------------------------------ */
  15677. +
  15678. +/*
  15679. + * SSAM device names follow the SSAM module alias, meaning they are prefixed
  15680. + * with 'ssam:', followed by domain, category, target ID, instance ID, and
  15681. + * function, each encoded as two-digit hexadecimal, separated by ':'. In other
  15682. + * words, it follows the scheme
  15683. + *
  15684. + * ssam:dd:cc:tt:ii:ff
  15685. + *
  15686. + * Where, 'dd', 'cc', 'tt', 'ii', and 'ff' are the two-digit hexadecimal
  15687. + * values mentioned above, respectively.
  15688. + */
  15689. +
  15690. +/* Root node. */
  15691. +static const struct software_node ssam_node_root = {
  15692. + .name = "ssam_platform_hub",
  15693. +};
  15694. +
  15695. +/* Devices for Surface Book 2. */
  15696. +static const struct software_node *ssam_node_group_sb2[] = {
  15697. + &ssam_node_root,
  15698. + NULL,
  15699. +};
  15700. +
  15701. +/* Devices for Surface Book 3. */
  15702. +static const struct software_node *ssam_node_group_sb3[] = {
  15703. + &ssam_node_root,
  15704. + NULL,
  15705. +};
  15706. +
  15707. +/* Devices for Surface Laptop 1. */
  15708. +static const struct software_node *ssam_node_group_sl1[] = {
  15709. + &ssam_node_root,
  15710. + NULL,
  15711. +};
  15712. +
  15713. +/* Devices for Surface Laptop 2. */
  15714. +static const struct software_node *ssam_node_group_sl2[] = {
  15715. + &ssam_node_root,
  15716. + NULL,
  15717. +};
  15718. +
  15719. +/* Devices for Surface Laptop 3. */
  15720. +static const struct software_node *ssam_node_group_sl3[] = {
  15721. + &ssam_node_root,
  15722. + NULL,
  15723. +};
  15724. +
  15725. +/* Devices for Surface Laptop Go. */
  15726. +static const struct software_node *ssam_node_group_slg1[] = {
  15727. + &ssam_node_root,
  15728. + NULL,
  15729. +};
  15730. +
  15731. +/* Devices for Surface Pro 5. */
  15732. +static const struct software_node *ssam_node_group_sp5[] = {
  15733. + &ssam_node_root,
  15734. + NULL,
  15735. +};
  15736. +
  15737. +/* Devices for Surface Pro 6. */
  15738. +static const struct software_node *ssam_node_group_sp6[] = {
  15739. + &ssam_node_root,
  15740. + NULL,
  15741. +};
  15742. +
  15743. +/* Devices for Surface Pro 7. */
  15744. +static const struct software_node *ssam_node_group_sp7[] = {
  15745. + &ssam_node_root,
  15746. + NULL,
  15747. +};
  15748. +
  15749. +
  15750. +/* -- Device registry helper functions. ------------------------------------- */
  15751. +
  15752. +static int ssam_uid_from_string(const char *str, struct ssam_device_uid *uid)
  15753. +{
  15754. + u8 d, tc, tid, iid, fn;
  15755. + int n;
  15756. +
  15757. + n = sscanf(str, "ssam:%hhx:%hhx:%hhx:%hhx:%hhx", &d, &tc, &tid, &iid, &fn);
  15758. + if (n != 5)
  15759. + return -EINVAL;
  15760. +
  15761. + uid->domain = d;
  15762. + uid->category = tc;
  15763. + uid->target = tid;
  15764. + uid->instance = iid;
  15765. + uid->function = fn;
  15766. +
  15767. + return 0;
  15768. +}
  15769. +
  15770. +static int ssam_hub_remove_devices_fn(struct device *dev, void *data)
  15771. +{
  15772. + if (!is_ssam_device(dev))
  15773. + return 0;
  15774. +
  15775. + ssam_device_remove(to_ssam_device(dev));
  15776. + return 0;
  15777. +}
  15778. +
  15779. +static void ssam_hub_remove_devices(struct device *parent)
  15780. +{
  15781. + device_for_each_child_reverse(parent, NULL, ssam_hub_remove_devices_fn);
  15782. +}
  15783. +
  15784. +static int ssam_hub_add_device(struct device *parent, struct ssam_controller *ctrl,
  15785. + struct fwnode_handle *node)
  15786. +{
  15787. + struct ssam_device_uid uid;
  15788. + struct ssam_device *sdev;
  15789. + int status;
  15790. +
  15791. + status = ssam_uid_from_string(fwnode_get_name(node), &uid);
  15792. + if (status)
  15793. + return status;
  15794. +
  15795. + sdev = ssam_device_alloc(ctrl, uid);
  15796. + if (!sdev)
  15797. + return -ENOMEM;
  15798. +
  15799. + sdev->dev.parent = parent;
  15800. + sdev->dev.fwnode = node;
  15801. +
  15802. + status = ssam_device_add(sdev);
  15803. + if (status)
  15804. + ssam_device_put(sdev);
  15805. +
  15806. + return status;
  15807. +}
  15808. +
  15809. +static int ssam_hub_add_devices(struct device *parent, struct ssam_controller *ctrl,
  15810. + struct fwnode_handle *node)
  15811. +{
  15812. + struct fwnode_handle *child;
  15813. + int status;
  15814. +
  15815. + fwnode_for_each_child_node(node, child) {
  15816. + /*
  15817. + * Try to add the device specified in the firmware node. If
  15818. + * this fails with -EINVAL, the node does not specify any SSAM
  15819. + * device, so ignore it and continue with the next one.
  15820. + */
  15821. +
  15822. + status = ssam_hub_add_device(parent, ctrl, child);
  15823. + if (status && status != -EINVAL)
  15824. + goto err;
  15825. + }
  15826. +
  15827. + return 0;
  15828. +err:
  15829. + ssam_hub_remove_devices(parent);
  15830. + return status;
  15831. +}
  15832. +
  15833. +
  15834. +/* -- SSAM platform/meta-hub driver. ---------------------------------------- */
  15835. +
  15836. +static const struct acpi_device_id ssam_platform_hub_match[] = {
  15837. + /* Surface Pro 4, 5, and 6 (OMBR < 0x10) */
  15838. + { "MSHW0081", (unsigned long)ssam_node_group_sp5 },
  15839. +
  15840. + /* Surface Pro 6 (OMBR >= 0x10) */
  15841. + { "MSHW0111", (unsigned long)ssam_node_group_sp6 },
  15842. +
  15843. + /* Surface Pro 7 */
  15844. + { "MSHW0116", (unsigned long)ssam_node_group_sp7 },
  15845. +
  15846. + /* Surface Book 2 */
  15847. + { "MSHW0107", (unsigned long)ssam_node_group_sb2 },
  15848. +
  15849. + /* Surface Book 3 */
  15850. + { "MSHW0117", (unsigned long)ssam_node_group_sb3 },
  15851. +
  15852. + /* Surface Laptop 1 */
  15853. + { "MSHW0086", (unsigned long)ssam_node_group_sl1 },
  15854. +
  15855. + /* Surface Laptop 2 */
  15856. + { "MSHW0112", (unsigned long)ssam_node_group_sl2 },
  15857. +
  15858. + /* Surface Laptop 3 (13", Intel) */
  15859. + { "MSHW0114", (unsigned long)ssam_node_group_sl3 },
  15860. +
  15861. + /* Surface Laptop 3 (15", AMD) */
  15862. + { "MSHW0110", (unsigned long)ssam_node_group_sl3 },
  15863. +
  15864. + /* Surface Laptop Go 1 */
  15865. + { "MSHW0118", (unsigned long)ssam_node_group_slg1 },
  15866. +
  15867. + { },
  15868. +};
  15869. +MODULE_DEVICE_TABLE(acpi, ssam_platform_hub_match);
  15870. +
  15871. +static int ssam_platform_hub_probe(struct platform_device *pdev)
  15872. +{
  15873. + const struct software_node **nodes;
  15874. + struct ssam_controller *ctrl;
  15875. + struct fwnode_handle *root;
  15876. + int status;
  15877. +
  15878. + nodes = (const struct software_node **)acpi_device_get_match_data(&pdev->dev);
  15879. + if (!nodes)
  15880. + return -ENODEV;
  15881. +
  15882. + /*
  15883. + * As we're adding the SSAM client devices as children under this device
  15884. + * and not the SSAM controller, we need to add a device link to the
  15885. + * controller to ensure that we remove all of our devices before the
  15886. + * controller is removed. This also guarantees proper ordering for
  15887. + * suspend/resume of the devices on this hub.
  15888. + */
  15889. + ctrl = ssam_client_bind(&pdev->dev);
  15890. + if (IS_ERR(ctrl))
  15891. + return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl);
  15892. +
  15893. + status = software_node_register_node_group(nodes);
  15894. + if (status)
  15895. + return status;
  15896. +
  15897. + root = software_node_fwnode(&ssam_node_root);
  15898. + if (!root) {
  15899. + software_node_unregister_node_group(nodes);
  15900. + return -ENOENT;
  15901. + }
  15902. +
  15903. + set_secondary_fwnode(&pdev->dev, root);
  15904. +
  15905. + status = ssam_hub_add_devices(&pdev->dev, ctrl, root);
  15906. + if (status) {
  15907. + set_secondary_fwnode(&pdev->dev, NULL);
  15908. + software_node_unregister_node_group(nodes);
  15909. + }
  15910. +
  15911. + platform_set_drvdata(pdev, nodes);
  15912. + return status;
  15913. +}
  15914. +
  15915. +static int ssam_platform_hub_remove(struct platform_device *pdev)
  15916. +{
  15917. + const struct software_node **nodes = platform_get_drvdata(pdev);
  15918. +
  15919. + ssam_hub_remove_devices(&pdev->dev);
  15920. + set_secondary_fwnode(&pdev->dev, NULL);
  15921. + software_node_unregister_node_group(nodes);
  15922. + return 0;
  15923. +}
  15924. +
  15925. +static struct platform_driver ssam_platform_hub_driver = {
  15926. + .probe = ssam_platform_hub_probe,
  15927. + .remove = ssam_platform_hub_remove,
  15928. + .driver = {
  15929. + .name = "surface_aggregator_platform_hub",
  15930. + .acpi_match_table = ssam_platform_hub_match,
  15931. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  15932. + },
  15933. +};
  15934. +module_platform_driver(ssam_platform_hub_driver);
  15935. +
  15936. +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  15937. +MODULE_DESCRIPTION("Device-registry for Surface System Aggregator Module");
  15938. +MODULE_LICENSE("GPL");
  15939. --
  15940. 2.31.0
  15941. From a72e5aa8093f8325e96e1d997de0b18f09d62746 Mon Sep 17 00:00:00 2001
  15942. From: Maximilian Luz <luzmaximilian@gmail.com>
  15943. Date: Sun, 7 Feb 2021 04:14:35 +0100
  15944. Subject: [PATCH] platform/surface: aggregator_registry: Add base device hub
  15945. The Surface Book 3 has a detachable base part. While the top part
  15946. (so-called clipboard) contains the CPU, touchscreen, and primary
  15947. battery, the base contains, among other things, a keyboard, touchpad,
  15948. and secondary battery.
  15949. Those devices do not react well to being accessed when the base part is
  15950. detached and should thus be removed and added in sync with the base. To
  15951. facilitate this, we introduce a virtual base device hub, which
  15952. automatically removes or adds the devices registered under it.
  15953. Patchset: surface-sam
  15954. ---
  15955. .../surface/surface_aggregator_registry.c | 261 +++++++++++++++++-
  15956. 1 file changed, 260 insertions(+), 1 deletion(-)
  15957. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  15958. index a051d941ad96..6c23d75a044c 100644
  15959. --- a/drivers/platform/surface/surface_aggregator_registry.c
  15960. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  15961. @@ -11,9 +11,12 @@
  15962. #include <linux/acpi.h>
  15963. #include <linux/kernel.h>
  15964. +#include <linux/limits.h>
  15965. #include <linux/module.h>
  15966. +#include <linux/mutex.h>
  15967. #include <linux/platform_device.h>
  15968. #include <linux/property.h>
  15969. +#include <linux/types.h>
  15970. #include <linux/surface_aggregator/controller.h>
  15971. #include <linux/surface_aggregator/device.h>
  15972. @@ -38,6 +41,12 @@ static const struct software_node ssam_node_root = {
  15973. .name = "ssam_platform_hub",
  15974. };
  15975. +/* Base device hub (devices attached to Surface Book 3 base). */
  15976. +static const struct software_node ssam_node_hub_base = {
  15977. + .name = "ssam:00:00:02:00:00",
  15978. + .parent = &ssam_node_root,
  15979. +};
  15980. +
  15981. /* Devices for Surface Book 2. */
  15982. static const struct software_node *ssam_node_group_sb2[] = {
  15983. &ssam_node_root,
  15984. @@ -47,6 +56,7 @@ static const struct software_node *ssam_node_group_sb2[] = {
  15985. /* Devices for Surface Book 3. */
  15986. static const struct software_node *ssam_node_group_sb3[] = {
  15987. &ssam_node_root,
  15988. + &ssam_node_hub_base,
  15989. NULL,
  15990. };
  15991. @@ -177,6 +187,230 @@ static int ssam_hub_add_devices(struct device *parent, struct ssam_controller *c
  15992. }
  15993. +/* -- SSAM base-hub driver. ------------------------------------------------- */
  15994. +
  15995. +enum ssam_base_hub_state {
  15996. + SSAM_BASE_HUB_UNINITIALIZED,
  15997. + SSAM_BASE_HUB_CONNECTED,
  15998. + SSAM_BASE_HUB_DISCONNECTED,
  15999. +};
  16000. +
  16001. +struct ssam_base_hub {
  16002. + struct ssam_device *sdev;
  16003. +
  16004. + struct mutex lock; /* Guards state update checks and transitions. */
  16005. + enum ssam_base_hub_state state;
  16006. +
  16007. + struct ssam_event_notifier notif;
  16008. +};
  16009. +
  16010. +static SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, {
  16011. + .target_category = SSAM_SSH_TC_BAS,
  16012. + .target_id = 0x01,
  16013. + .command_id = 0x0d,
  16014. + .instance_id = 0x00,
  16015. +});
  16016. +
  16017. +#define SSAM_BAS_OPMODE_TABLET 0x00
  16018. +#define SSAM_EVENT_BAS_CID_CONNECTION 0x0c
  16019. +
  16020. +static int ssam_base_hub_query_state(struct ssam_base_hub *hub, enum ssam_base_hub_state *state)
  16021. +{
  16022. + u8 opmode;
  16023. + int status;
  16024. +
  16025. + status = ssam_retry(ssam_bas_query_opmode, hub->sdev->ctrl, &opmode);
  16026. + if (status < 0) {
  16027. + dev_err(&hub->sdev->dev, "failed to query base state: %d\n", status);
  16028. + return status;
  16029. + }
  16030. +
  16031. + if (opmode != SSAM_BAS_OPMODE_TABLET)
  16032. + *state = SSAM_BASE_HUB_CONNECTED;
  16033. + else
  16034. + *state = SSAM_BASE_HUB_DISCONNECTED;
  16035. +
  16036. + return 0;
  16037. +}
  16038. +
  16039. +static ssize_t ssam_base_hub_state_show(struct device *dev, struct device_attribute *attr,
  16040. + char *buf)
  16041. +{
  16042. + struct ssam_base_hub *hub = dev_get_drvdata(dev);
  16043. + bool connected;
  16044. +
  16045. + mutex_lock(&hub->lock);
  16046. + connected = hub->state == SSAM_BASE_HUB_CONNECTED;
  16047. + mutex_unlock(&hub->lock);
  16048. +
  16049. + return sysfs_emit(buf, "%d\n", connected);
  16050. +}
  16051. +
  16052. +static struct device_attribute ssam_base_hub_attr_state =
  16053. + __ATTR(state, 0444, ssam_base_hub_state_show, NULL);
  16054. +
  16055. +static struct attribute *ssam_base_hub_attrs[] = {
  16056. + &ssam_base_hub_attr_state.attr,
  16057. + NULL,
  16058. +};
  16059. +
  16060. +const struct attribute_group ssam_base_hub_group = {
  16061. + .attrs = ssam_base_hub_attrs,
  16062. +};
  16063. +
  16064. +static int __ssam_base_hub_update(struct ssam_base_hub *hub, enum ssam_base_hub_state new)
  16065. +{
  16066. + struct fwnode_handle *node = dev_fwnode(&hub->sdev->dev);
  16067. + int status = 0;
  16068. +
  16069. + lockdep_assert_held(&hub->lock);
  16070. +
  16071. + if (hub->state == new)
  16072. + return 0;
  16073. + hub->state = new;
  16074. +
  16075. + if (hub->state == SSAM_BASE_HUB_CONNECTED)
  16076. + status = ssam_hub_add_devices(&hub->sdev->dev, hub->sdev->ctrl, node);
  16077. + else
  16078. + ssam_hub_remove_devices(&hub->sdev->dev);
  16079. +
  16080. + if (status)
  16081. + dev_err(&hub->sdev->dev, "failed to update base-hub devices: %d\n", status);
  16082. +
  16083. + return status;
  16084. +}
  16085. +
  16086. +static int ssam_base_hub_update(struct ssam_base_hub *hub)
  16087. +{
  16088. + enum ssam_base_hub_state state;
  16089. + int status;
  16090. +
  16091. + mutex_lock(&hub->lock);
  16092. +
  16093. + status = ssam_base_hub_query_state(hub, &state);
  16094. + if (!status)
  16095. + status = __ssam_base_hub_update(hub, state);
  16096. +
  16097. + mutex_unlock(&hub->lock);
  16098. + return status;
  16099. +}
  16100. +
  16101. +static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event)
  16102. +{
  16103. + struct ssam_base_hub *hub;
  16104. + struct ssam_device *sdev;
  16105. + enum ssam_base_hub_state new;
  16106. +
  16107. + hub = container_of(nf, struct ssam_base_hub, notif);
  16108. + sdev = hub->sdev;
  16109. +
  16110. + if (event->command_id != SSAM_EVENT_BAS_CID_CONNECTION)
  16111. + return 0;
  16112. +
  16113. + if (event->length < 1) {
  16114. + dev_err(&sdev->dev, "unexpected payload size: %u\n",
  16115. + event->length);
  16116. + return 0;
  16117. + }
  16118. +
  16119. + if (event->data[0])
  16120. + new = SSAM_BASE_HUB_CONNECTED;
  16121. + else
  16122. + new = SSAM_BASE_HUB_DISCONNECTED;
  16123. +
  16124. + mutex_lock(&hub->lock);
  16125. + __ssam_base_hub_update(hub, new);
  16126. + mutex_unlock(&hub->lock);
  16127. +
  16128. + /*
  16129. + * Do not return SSAM_NOTIF_HANDLED: The event should be picked up and
  16130. + * consumed by the detachment system driver. We're just a (more or less)
  16131. + * silent observer.
  16132. + */
  16133. + return 0;
  16134. +}
  16135. +
  16136. +static int __maybe_unused ssam_base_hub_resume(struct device *dev)
  16137. +{
  16138. + return ssam_base_hub_update(dev_get_drvdata(dev));
  16139. +}
  16140. +static SIMPLE_DEV_PM_OPS(ssam_base_hub_pm_ops, NULL, ssam_base_hub_resume);
  16141. +
  16142. +static int ssam_base_hub_probe(struct ssam_device *sdev)
  16143. +{
  16144. + struct ssam_base_hub *hub;
  16145. + int status;
  16146. +
  16147. + hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL);
  16148. + if (!hub)
  16149. + return -ENOMEM;
  16150. +
  16151. + mutex_init(&hub->lock);
  16152. +
  16153. + hub->sdev = sdev;
  16154. + hub->state = SSAM_BASE_HUB_UNINITIALIZED;
  16155. +
  16156. + hub->notif.base.priority = INT_MAX; /* This notifier should run first. */
  16157. + hub->notif.base.fn = ssam_base_hub_notif;
  16158. + hub->notif.event.reg = SSAM_EVENT_REGISTRY_SAM;
  16159. + hub->notif.event.id.target_category = SSAM_SSH_TC_BAS,
  16160. + hub->notif.event.id.instance = 0,
  16161. + hub->notif.event.mask = SSAM_EVENT_MASK_NONE;
  16162. + hub->notif.event.flags = SSAM_EVENT_SEQUENCED;
  16163. +
  16164. + ssam_device_set_drvdata(sdev, hub);
  16165. +
  16166. + status = ssam_notifier_register(sdev->ctrl, &hub->notif);
  16167. + if (status)
  16168. + goto err_register;
  16169. +
  16170. + status = ssam_base_hub_update(hub);
  16171. + if (status)
  16172. + goto err_update;
  16173. +
  16174. + status = sysfs_create_group(&sdev->dev.kobj, &ssam_base_hub_group);
  16175. + if (status)
  16176. + goto err_update;
  16177. +
  16178. + return 0;
  16179. +
  16180. +err_update:
  16181. + ssam_notifier_unregister(sdev->ctrl, &hub->notif);
  16182. + ssam_hub_remove_devices(&sdev->dev);
  16183. +err_register:
  16184. + mutex_destroy(&hub->lock);
  16185. + return status;
  16186. +}
  16187. +
  16188. +static void ssam_base_hub_remove(struct ssam_device *sdev)
  16189. +{
  16190. + struct ssam_base_hub *hub = ssam_device_get_drvdata(sdev);
  16191. +
  16192. + sysfs_remove_group(&sdev->dev.kobj, &ssam_base_hub_group);
  16193. +
  16194. + ssam_notifier_unregister(sdev->ctrl, &hub->notif);
  16195. + ssam_hub_remove_devices(&sdev->dev);
  16196. +
  16197. + mutex_destroy(&hub->lock);
  16198. +}
  16199. +
  16200. +static const struct ssam_device_id ssam_base_hub_match[] = {
  16201. + { SSAM_VDEV(HUB, 0x02, SSAM_ANY_IID, 0x00) },
  16202. + { },
  16203. +};
  16204. +
  16205. +static struct ssam_device_driver ssam_base_hub_driver = {
  16206. + .probe = ssam_base_hub_probe,
  16207. + .remove = ssam_base_hub_remove,
  16208. + .match_table = ssam_base_hub_match,
  16209. + .driver = {
  16210. + .name = "surface_aggregator_base_hub",
  16211. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  16212. + .pm = &ssam_base_hub_pm_ops,
  16213. + },
  16214. +};
  16215. +
  16216. +
  16217. /* -- SSAM platform/meta-hub driver. ---------------------------------------- */
  16218. static const struct acpi_device_id ssam_platform_hub_match[] = {
  16219. @@ -277,7 +511,32 @@ static struct platform_driver ssam_platform_hub_driver = {
  16220. .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  16221. },
  16222. };
  16223. -module_platform_driver(ssam_platform_hub_driver);
  16224. +
  16225. +
  16226. +/* -- Module initialization. ------------------------------------------------ */
  16227. +
  16228. +static int __init ssam_device_hub_init(void)
  16229. +{
  16230. + int status;
  16231. +
  16232. + status = platform_driver_register(&ssam_platform_hub_driver);
  16233. + if (status)
  16234. + return status;
  16235. +
  16236. + status = ssam_device_driver_register(&ssam_base_hub_driver);
  16237. + if (status)
  16238. + platform_driver_unregister(&ssam_platform_hub_driver);
  16239. +
  16240. + return status;
  16241. +}
  16242. +module_init(ssam_device_hub_init);
  16243. +
  16244. +static void __exit ssam_device_hub_exit(void)
  16245. +{
  16246. + ssam_device_driver_unregister(&ssam_base_hub_driver);
  16247. + platform_driver_unregister(&ssam_platform_hub_driver);
  16248. +}
  16249. +module_exit(ssam_device_hub_exit);
  16250. MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  16251. MODULE_DESCRIPTION("Device-registry for Surface System Aggregator Module");
  16252. --
  16253. 2.31.0
  16254. From afd3b258a6bdb96e0642babad9707383ae6da152 Mon Sep 17 00:00:00 2001
  16255. From: Maximilian Luz <luzmaximilian@gmail.com>
  16256. Date: Sun, 7 Feb 2021 04:55:09 +0100
  16257. Subject: [PATCH] platform/surface: aggregator_registry: Add battery subsystem
  16258. devices
  16259. Add battery subsystem (TC=0x02) devices (battery and AC) to the SSAM
  16260. device registry. These devices need to be registered for 7th-generation
  16261. Surface models. On 5th- and 6th-generation models, these devices are
  16262. handled via the standard ACPI battery/AC interface, which in turn
  16263. accesses the same SSAM interface via the Surface ACPI Notify (SAN)
  16264. driver.
  16265. Patchset: surface-sam
  16266. ---
  16267. .../surface/surface_aggregator_registry.c | 27 +++++++++++++++++++
  16268. 1 file changed, 27 insertions(+)
  16269. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  16270. index 6c23d75a044c..cde279692842 100644
  16271. --- a/drivers/platform/surface/surface_aggregator_registry.c
  16272. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  16273. @@ -47,6 +47,24 @@ static const struct software_node ssam_node_hub_base = {
  16274. .parent = &ssam_node_root,
  16275. };
  16276. +/* AC adapter. */
  16277. +static const struct software_node ssam_node_bat_ac = {
  16278. + .name = "ssam:01:02:01:01:01",
  16279. + .parent = &ssam_node_root,
  16280. +};
  16281. +
  16282. +/* Primary battery. */
  16283. +static const struct software_node ssam_node_bat_main = {
  16284. + .name = "ssam:01:02:01:01:00",
  16285. + .parent = &ssam_node_root,
  16286. +};
  16287. +
  16288. +/* Secondary battery (Surface Book 3). */
  16289. +static const struct software_node ssam_node_bat_sb3base = {
  16290. + .name = "ssam:01:02:02:01:00",
  16291. + .parent = &ssam_node_hub_base,
  16292. +};
  16293. +
  16294. /* Devices for Surface Book 2. */
  16295. static const struct software_node *ssam_node_group_sb2[] = {
  16296. &ssam_node_root,
  16297. @@ -57,6 +75,9 @@ static const struct software_node *ssam_node_group_sb2[] = {
  16298. static const struct software_node *ssam_node_group_sb3[] = {
  16299. &ssam_node_root,
  16300. &ssam_node_hub_base,
  16301. + &ssam_node_bat_ac,
  16302. + &ssam_node_bat_main,
  16303. + &ssam_node_bat_sb3base,
  16304. NULL,
  16305. };
  16306. @@ -75,12 +96,16 @@ static const struct software_node *ssam_node_group_sl2[] = {
  16307. /* Devices for Surface Laptop 3. */
  16308. static const struct software_node *ssam_node_group_sl3[] = {
  16309. &ssam_node_root,
  16310. + &ssam_node_bat_ac,
  16311. + &ssam_node_bat_main,
  16312. NULL,
  16313. };
  16314. /* Devices for Surface Laptop Go. */
  16315. static const struct software_node *ssam_node_group_slg1[] = {
  16316. &ssam_node_root,
  16317. + &ssam_node_bat_ac,
  16318. + &ssam_node_bat_main,
  16319. NULL,
  16320. };
  16321. @@ -99,6 +124,8 @@ static const struct software_node *ssam_node_group_sp6[] = {
  16322. /* Devices for Surface Pro 7. */
  16323. static const struct software_node *ssam_node_group_sp7[] = {
  16324. &ssam_node_root,
  16325. + &ssam_node_bat_ac,
  16326. + &ssam_node_bat_main,
  16327. NULL,
  16328. };
  16329. --
  16330. 2.31.0
  16331. From 0cb17981f08cc3083bc2f84da48f49825f91fb6e Mon Sep 17 00:00:00 2001
  16332. From: Maximilian Luz <luzmaximilian@gmail.com>
  16333. Date: Sun, 7 Feb 2021 05:01:08 +0100
  16334. Subject: [PATCH] platform/surface: aggregator_registry: Add platform profile
  16335. device
  16336. Add the SSAM platform profile device to the SSAM device registry. This
  16337. device is accessible under the thermal subsystem (TC=0x03) and needs to
  16338. be registered for all Surface models.
  16339. Patchset: surface-sam
  16340. ---
  16341. .../surface/surface_aggregator_registry.c | 15 +++++++++++++++
  16342. 1 file changed, 15 insertions(+)
  16343. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  16344. index cde279692842..33904613dd4b 100644
  16345. --- a/drivers/platform/surface/surface_aggregator_registry.c
  16346. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  16347. @@ -65,9 +65,16 @@ static const struct software_node ssam_node_bat_sb3base = {
  16348. .parent = &ssam_node_hub_base,
  16349. };
  16350. +/* Platform profile / performance-mode device. */
  16351. +static const struct software_node ssam_node_tmp_pprof = {
  16352. + .name = "ssam:01:03:01:00:01",
  16353. + .parent = &ssam_node_root,
  16354. +};
  16355. +
  16356. /* Devices for Surface Book 2. */
  16357. static const struct software_node *ssam_node_group_sb2[] = {
  16358. &ssam_node_root,
  16359. + &ssam_node_tmp_pprof,
  16360. NULL,
  16361. };
  16362. @@ -78,18 +85,21 @@ static const struct software_node *ssam_node_group_sb3[] = {
  16363. &ssam_node_bat_ac,
  16364. &ssam_node_bat_main,
  16365. &ssam_node_bat_sb3base,
  16366. + &ssam_node_tmp_pprof,
  16367. NULL,
  16368. };
  16369. /* Devices for Surface Laptop 1. */
  16370. static const struct software_node *ssam_node_group_sl1[] = {
  16371. &ssam_node_root,
  16372. + &ssam_node_tmp_pprof,
  16373. NULL,
  16374. };
  16375. /* Devices for Surface Laptop 2. */
  16376. static const struct software_node *ssam_node_group_sl2[] = {
  16377. &ssam_node_root,
  16378. + &ssam_node_tmp_pprof,
  16379. NULL,
  16380. };
  16381. @@ -98,6 +108,7 @@ static const struct software_node *ssam_node_group_sl3[] = {
  16382. &ssam_node_root,
  16383. &ssam_node_bat_ac,
  16384. &ssam_node_bat_main,
  16385. + &ssam_node_tmp_pprof,
  16386. NULL,
  16387. };
  16388. @@ -106,18 +117,21 @@ static const struct software_node *ssam_node_group_slg1[] = {
  16389. &ssam_node_root,
  16390. &ssam_node_bat_ac,
  16391. &ssam_node_bat_main,
  16392. + &ssam_node_tmp_pprof,
  16393. NULL,
  16394. };
  16395. /* Devices for Surface Pro 5. */
  16396. static const struct software_node *ssam_node_group_sp5[] = {
  16397. &ssam_node_root,
  16398. + &ssam_node_tmp_pprof,
  16399. NULL,
  16400. };
  16401. /* Devices for Surface Pro 6. */
  16402. static const struct software_node *ssam_node_group_sp6[] = {
  16403. &ssam_node_root,
  16404. + &ssam_node_tmp_pprof,
  16405. NULL,
  16406. };
  16407. @@ -126,6 +140,7 @@ static const struct software_node *ssam_node_group_sp7[] = {
  16408. &ssam_node_root,
  16409. &ssam_node_bat_ac,
  16410. &ssam_node_bat_main,
  16411. + &ssam_node_tmp_pprof,
  16412. NULL,
  16413. };
  16414. --
  16415. 2.31.0
  16416. From c64ca95fc3915aa38881099919d2ef4b65b85ca9 Mon Sep 17 00:00:00 2001
  16417. From: Maximilian Luz <luzmaximilian@gmail.com>
  16418. Date: Sun, 7 Feb 2021 05:06:41 +0100
  16419. Subject: [PATCH] platform/surface: aggregator_registry: Add DTX device
  16420. Add the detachment system (DTX) SSAM device for the Surface Book 3. This
  16421. device is accessible under the base (TC=0x11) subsystem.
  16422. Patchset: surface-sam
  16423. ---
  16424. drivers/platform/surface/surface_aggregator_registry.c | 7 +++++++
  16425. 1 file changed, 7 insertions(+)
  16426. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  16427. index 33904613dd4b..dc044d06828b 100644
  16428. --- a/drivers/platform/surface/surface_aggregator_registry.c
  16429. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  16430. @@ -71,6 +71,12 @@ static const struct software_node ssam_node_tmp_pprof = {
  16431. .parent = &ssam_node_root,
  16432. };
  16433. +/* DTX / detachment-system device (Surface Book 3). */
  16434. +static const struct software_node ssam_node_bas_dtx = {
  16435. + .name = "ssam:01:11:01:00:00",
  16436. + .parent = &ssam_node_root,
  16437. +};
  16438. +
  16439. /* Devices for Surface Book 2. */
  16440. static const struct software_node *ssam_node_group_sb2[] = {
  16441. &ssam_node_root,
  16442. @@ -86,6 +92,7 @@ static const struct software_node *ssam_node_group_sb3[] = {
  16443. &ssam_node_bat_main,
  16444. &ssam_node_bat_sb3base,
  16445. &ssam_node_tmp_pprof,
  16446. + &ssam_node_bas_dtx,
  16447. NULL,
  16448. };
  16449. --
  16450. 2.31.0
  16451. From a706c777f1d1632e5c393c8e51aa0f8e3da4c757 Mon Sep 17 00:00:00 2001
  16452. From: Maximilian Luz <luzmaximilian@gmail.com>
  16453. Date: Sun, 7 Feb 2021 05:16:44 +0100
  16454. Subject: [PATCH] platform/surface: aggregator_registry: Add HID subsystem
  16455. devices
  16456. Add HID subsystem (TC=0x15) devices. These devices need to be registered
  16457. for 7th-generation Surface models. On previous generations, these
  16458. devices are either provided as platform devices via ACPI (Surface Laptop
  16459. 1 and 2) or implemented as standard USB device.
  16460. Patchset: surface-sam
  16461. ---
  16462. .../surface/surface_aggregator_registry.c | 49 +++++++++++++++++++
  16463. 1 file changed, 49 insertions(+)
  16464. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  16465. index dc044d06828b..caee90d135c5 100644
  16466. --- a/drivers/platform/surface/surface_aggregator_registry.c
  16467. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  16468. @@ -77,6 +77,48 @@ static const struct software_node ssam_node_bas_dtx = {
  16469. .parent = &ssam_node_root,
  16470. };
  16471. +/* HID keyboard. */
  16472. +static const struct software_node ssam_node_hid_main_keyboard = {
  16473. + .name = "ssam:01:15:02:01:00",
  16474. + .parent = &ssam_node_root,
  16475. +};
  16476. +
  16477. +/* HID touchpad. */
  16478. +static const struct software_node ssam_node_hid_main_touchpad = {
  16479. + .name = "ssam:01:15:02:03:00",
  16480. + .parent = &ssam_node_root,
  16481. +};
  16482. +
  16483. +/* HID device instance 5 (unknown HID device). */
  16484. +static const struct software_node ssam_node_hid_main_iid5 = {
  16485. + .name = "ssam:01:15:02:05:00",
  16486. + .parent = &ssam_node_root,
  16487. +};
  16488. +
  16489. +/* HID keyboard (base hub). */
  16490. +static const struct software_node ssam_node_hid_base_keyboard = {
  16491. + .name = "ssam:01:15:02:01:00",
  16492. + .parent = &ssam_node_hub_base,
  16493. +};
  16494. +
  16495. +/* HID touchpad (base hub). */
  16496. +static const struct software_node ssam_node_hid_base_touchpad = {
  16497. + .name = "ssam:01:15:02:03:00",
  16498. + .parent = &ssam_node_hub_base,
  16499. +};
  16500. +
  16501. +/* HID device instance 5 (unknown HID device, base hub). */
  16502. +static const struct software_node ssam_node_hid_base_iid5 = {
  16503. + .name = "ssam:01:15:02:05:00",
  16504. + .parent = &ssam_node_hub_base,
  16505. +};
  16506. +
  16507. +/* HID device instance 6 (unknown HID device, base hub). */
  16508. +static const struct software_node ssam_node_hid_base_iid6 = {
  16509. + .name = "ssam:01:15:02:06:00",
  16510. + .parent = &ssam_node_hub_base,
  16511. +};
  16512. +
  16513. /* Devices for Surface Book 2. */
  16514. static const struct software_node *ssam_node_group_sb2[] = {
  16515. &ssam_node_root,
  16516. @@ -93,6 +135,10 @@ static const struct software_node *ssam_node_group_sb3[] = {
  16517. &ssam_node_bat_sb3base,
  16518. &ssam_node_tmp_pprof,
  16519. &ssam_node_bas_dtx,
  16520. + &ssam_node_hid_base_keyboard,
  16521. + &ssam_node_hid_base_touchpad,
  16522. + &ssam_node_hid_base_iid5,
  16523. + &ssam_node_hid_base_iid6,
  16524. NULL,
  16525. };
  16526. @@ -116,6 +162,9 @@ static const struct software_node *ssam_node_group_sl3[] = {
  16527. &ssam_node_bat_ac,
  16528. &ssam_node_bat_main,
  16529. &ssam_node_tmp_pprof,
  16530. + &ssam_node_hid_main_keyboard,
  16531. + &ssam_node_hid_main_touchpad,
  16532. + &ssam_node_hid_main_iid5,
  16533. NULL,
  16534. };
  16535. --
  16536. 2.31.0
  16537. From 8558e1b824cd947857bc04c9a2c96bc3ef2a4475 Mon Sep 17 00:00:00 2001
  16538. From: Maximilian Luz <luzmaximilian@gmail.com>
  16539. Date: Tue, 9 Mar 2021 17:03:15 +0100
  16540. Subject: [PATCH] platform/surface: aggregator_registry: Add support for
  16541. Surface Pro 7+
  16542. The Surface Pro 7+ is essentially a refresh of the Surface Pro 7 with
  16543. updated hardware and a new WSID identifier.
  16544. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  16545. Patchset: surface-sam
  16546. ---
  16547. drivers/platform/surface/surface_aggregator_registry.c | 5 ++++-
  16548. 1 file changed, 4 insertions(+), 1 deletion(-)
  16549. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  16550. index caee90d135c5..6de74e893d06 100644
  16551. --- a/drivers/platform/surface/surface_aggregator_registry.c
  16552. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  16553. @@ -191,7 +191,7 @@ static const struct software_node *ssam_node_group_sp6[] = {
  16554. NULL,
  16555. };
  16556. -/* Devices for Surface Pro 7. */
  16557. +/* Devices for Surface Pro 7 and Surface Pro 7+. */
  16558. static const struct software_node *ssam_node_group_sp7[] = {
  16559. &ssam_node_root,
  16560. &ssam_node_bat_ac,
  16561. @@ -521,6 +521,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
  16562. /* Surface Pro 7 */
  16563. { "MSHW0116", (unsigned long)ssam_node_group_sp7 },
  16564. + /* Surface Pro 7+ */
  16565. + { "MSHW0119", (unsigned long)ssam_node_group_sp7 },
  16566. +
  16567. /* Surface Book 2 */
  16568. { "MSHW0107", (unsigned long)ssam_node_group_sb2 },
  16569. --
  16570. 2.31.0
  16571. From 5b6680505958324b1511d5845c51fb880686c2a4 Mon Sep 17 00:00:00 2001
  16572. From: Wei Yongjun <weiyongjun1@huawei.com>
  16573. Date: Tue, 9 Mar 2021 13:15:00 +0000
  16574. Subject: [PATCH] platform/surface: aggregator_registry: Make symbol
  16575. 'ssam_base_hub_group' static
  16576. The sparse tool complains as follows:
  16577. drivers/platform/surface/surface_aggregator_registry.c:355:30: warning:
  16578. symbol 'ssam_base_hub_group' was not declared. Should it be static?
  16579. This symbol is not used outside of surface_aggregator_registry.c, so this
  16580. commit marks it static.
  16581. Fixes: 797e78564634 ("platform/surface: aggregator_registry: Add base device hub")
  16582. Reported-by: Hulk Robot <hulkci@huawei.com>
  16583. Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>
  16584. Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com>
  16585. Link: https://lore.kernel.org/r/20210309131500.1885772-1-weiyongjun1@huawei.com
  16586. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  16587. Patchset: surface-sam
  16588. ---
  16589. drivers/platform/surface/surface_aggregator_registry.c | 2 +-
  16590. 1 file changed, 1 insertion(+), 1 deletion(-)
  16591. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  16592. index 6de74e893d06..304d601980ed 100644
  16593. --- a/drivers/platform/surface/surface_aggregator_registry.c
  16594. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  16595. @@ -352,7 +352,7 @@ static struct attribute *ssam_base_hub_attrs[] = {
  16596. NULL,
  16597. };
  16598. -const struct attribute_group ssam_base_hub_group = {
  16599. +static const struct attribute_group ssam_base_hub_group = {
  16600. .attrs = ssam_base_hub_attrs,
  16601. };
  16602. --
  16603. 2.31.0
  16604. From 329f536e5fe11a7a1c883bad0da1338f7d030c8b Mon Sep 17 00:00:00 2001
  16605. From: Maximilian Luz <luzmaximilian@gmail.com>
  16606. Date: Tue, 9 Feb 2021 02:46:40 +0100
  16607. Subject: [PATCH] platform/surface: Add DTX driver
  16608. The Microsoft Surface Book series devices consist of a so-called
  16609. clipboard part (containing the CPU, touchscreen, and primary battery)
  16610. and a base part (containing keyboard, secondary battery, and optional
  16611. discrete GPU). These parts can be separated, i.e. the clipboard can be
  16612. detached and used as tablet.
  16613. This detachment process is initiated by pressing a button. On the
  16614. Surface Book 2 and 3 (targeted with this commit), the Surface Aggregator
  16615. Module (i.e. the embedded controller on those devices) attempts to send
  16616. a notification to any listening client driver and waits for further
  16617. instructions (i.e. whether the detachment process should continue or be
  16618. aborted). If it does not receive a response in a certain time-frame, the
  16619. detachment process (by default) continues and the clipboard can be
  16620. physically separated. In other words, (by default and) without a driver,
  16621. the detachment process takes about 10 seconds to complete.
  16622. This commit introduces a driver for this detachment system (called DTX).
  16623. This driver allows a user-space daemon to control and influence the
  16624. detachment behavior. Specifically, it forwards any detachment requests
  16625. to user-space, allows user-space to make such requests itself, and
  16626. allows handling of those requests. Requests can be handled by either
  16627. aborting, continuing/allowing, or delaying (i.e. resetting the timeout
  16628. via a heartbeat commend). The user-space API is implemented via the
  16629. /dev/surface/dtx miscdevice.
  16630. In addition, user-space can change the default behavior on timeout from
  16631. allowing detachment to disallowing it, which is useful if the (optional)
  16632. discrete GPU is in use.
  16633. Furthermore, this driver allows user-space to receive notifications
  16634. about the state of the base, specifically when it is physically removed
  16635. (as opposed to detachment requested), in what manner it is connected
  16636. (i.e. in reverse-/tent-/studio- or laptop-mode), and what type of base
  16637. is connected. Based on this information, the driver also provides a
  16638. simple tablet-mode switch (aliasing all modes without keyboard access,
  16639. i.e. tablet-mode and studio-mode to its reported tablet-mode).
  16640. An implementation of such a user-space daemon, allowing configuration of
  16641. detachment behavior via scripts (e.g. safely unmounting USB devices
  16642. connected to the base before continuing) can be found at [1].
  16643. [1]: https://github.com/linux-surface/surface-dtx-daemon
  16644. Patchset: surface-sam
  16645. ---
  16646. .../userspace-api/ioctl/ioctl-number.rst | 2 +
  16647. MAINTAINERS | 7 +
  16648. drivers/platform/surface/Kconfig | 16 +
  16649. drivers/platform/surface/Makefile | 1 +
  16650. drivers/platform/surface/surface_dtx.c | 1201 +++++++++++++++++
  16651. include/uapi/linux/surface_aggregator/dtx.h | 146 ++
  16652. 6 files changed, 1373 insertions(+)
  16653. create mode 100644 drivers/platform/surface/surface_dtx.c
  16654. create mode 100644 include/uapi/linux/surface_aggregator/dtx.h
  16655. diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
  16656. index b5231d7f9200..e1dc72a8b62e 100644
  16657. --- a/Documentation/userspace-api/ioctl/ioctl-number.rst
  16658. +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
  16659. @@ -326,6 +326,8 @@ Code Seq# Include File Comments
  16660. 0xA4 00-1F uapi/asm/sgx.h <mailto:linux-sgx@vger.kernel.org>
  16661. 0xA5 01 linux/surface_aggregator/cdev.h Microsoft Surface Platform System Aggregator
  16662. <mailto:luzmaximilian@gmail.com>
  16663. +0xA5 20-2F linux/surface_aggregator/dtx.h Microsoft Surface DTX driver
  16664. + <mailto:luzmaximilian@gmail.com>
  16665. 0xAA 00-3F linux/uapi/linux/userfaultfd.h
  16666. 0xAB 00-1F linux/nbd.h
  16667. 0xAC 00-1F linux/raw.h
  16668. diff --git a/MAINTAINERS b/MAINTAINERS
  16669. index 1fd2fd35d5b7..1a60e353df38 100644
  16670. --- a/MAINTAINERS
  16671. +++ b/MAINTAINERS
  16672. @@ -11785,6 +11785,13 @@ F: drivers/scsi/smartpqi/smartpqi*.[ch]
  16673. F: include/linux/cciss*.h
  16674. F: include/uapi/linux/cciss*.h
  16675. +MICROSOFT SURFACE DTX DRIVER
  16676. +M: Maximilian Luz <luzmaximilian@gmail.com>
  16677. +L: platform-driver-x86@vger.kernel.org
  16678. +S: Maintained
  16679. +F: drivers/platform/surface/surface_dtx.c
  16680. +F: include/uapi/linux/surface_aggregator/dtx.h
  16681. +
  16682. MICROSOFT SURFACE GPE LID SUPPORT DRIVER
  16683. M: Maximilian Luz <luzmaximilian@gmail.com>
  16684. L: platform-driver-x86@vger.kernel.org
  16685. diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig
  16686. index 97e08dd35992..745f9d2eb6a7 100644
  16687. --- a/drivers/platform/surface/Kconfig
  16688. +++ b/drivers/platform/surface/Kconfig
  16689. @@ -111,6 +111,22 @@ config SURFACE_BOOK1_DGPU_SWITCH
  16690. This driver provides a sysfs switch to set the power-state of the
  16691. discrete GPU found on the Microsoft Surface Book 1.
  16692. +config SURFACE_DTX
  16693. + tristate "Surface DTX (Detachment System) Driver"
  16694. + depends on SURFACE_AGGREGATOR
  16695. + depends on INPUT
  16696. + help
  16697. + Driver for the Surface Book clipboard detachment system (DTX).
  16698. +
  16699. + On the Surface Book series devices, the display part containing the
  16700. + CPU (called the clipboard) can be detached from the base (containing a
  16701. + battery, the keyboard, and, optionally, a discrete GPU) by (if
  16702. + necessary) unlocking and opening the latch connecting both parts.
  16703. +
  16704. + This driver provides a user-space interface that can influence the
  16705. + behavior of this process, which includes the option to abort it in
  16706. + case the base is still in use or speed it up in case it is not.
  16707. +
  16708. config SURFACE_GPE
  16709. tristate "Surface GPE/Lid Support Driver"
  16710. depends on DMI
  16711. diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile
  16712. index 30a212aefd35..19b661e274c3 100644
  16713. --- a/drivers/platform/surface/Makefile
  16714. +++ b/drivers/platform/surface/Makefile
  16715. @@ -12,5 +12,6 @@ obj-$(CONFIG_SURFACE_AGGREGATOR) += aggregator/
  16716. obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o
  16717. obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o
  16718. obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o
  16719. +obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o
  16720. obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o
  16721. obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
  16722. diff --git a/drivers/platform/surface/surface_dtx.c b/drivers/platform/surface/surface_dtx.c
  16723. new file mode 100644
  16724. index 000000000000..a95adc1094aa
  16725. --- /dev/null
  16726. +++ b/drivers/platform/surface/surface_dtx.c
  16727. @@ -0,0 +1,1201 @@
  16728. +// SPDX-License-Identifier: GPL-2.0+
  16729. +/*
  16730. + * Surface Book (gen. 2 and later) detachment system (DTX) driver.
  16731. + *
  16732. + * Provides a user-space interface to properly handle clipboard/tablet
  16733. + * (containing screen and processor) detachment from the base of the device
  16734. + * (containing the keyboard and optionally a discrete GPU). Allows to
  16735. + * acknowledge (to speed things up), abort (e.g. in case the dGPU is still in
  16736. + * use), or request detachment via user-space.
  16737. + *
  16738. + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
  16739. + */
  16740. +
  16741. +#include <linux/fs.h>
  16742. +#include <linux/input.h>
  16743. +#include <linux/ioctl.h>
  16744. +#include <linux/kernel.h>
  16745. +#include <linux/kfifo.h>
  16746. +#include <linux/kref.h>
  16747. +#include <linux/miscdevice.h>
  16748. +#include <linux/module.h>
  16749. +#include <linux/mutex.h>
  16750. +#include <linux/platform_device.h>
  16751. +#include <linux/poll.h>
  16752. +#include <linux/rwsem.h>
  16753. +#include <linux/slab.h>
  16754. +#include <linux/workqueue.h>
  16755. +
  16756. +#include <linux/surface_aggregator/controller.h>
  16757. +#include <linux/surface_aggregator/dtx.h>
  16758. +
  16759. +
  16760. +/* -- SSAM interface. ------------------------------------------------------- */
  16761. +
  16762. +enum sam_event_cid_bas {
  16763. + SAM_EVENT_CID_DTX_CONNECTION = 0x0c,
  16764. + SAM_EVENT_CID_DTX_REQUEST = 0x0e,
  16765. + SAM_EVENT_CID_DTX_CANCEL = 0x0f,
  16766. + SAM_EVENT_CID_DTX_LATCH_STATUS = 0x11,
  16767. +};
  16768. +
  16769. +enum ssam_bas_base_state {
  16770. + SSAM_BAS_BASE_STATE_DETACH_SUCCESS = 0x00,
  16771. + SSAM_BAS_BASE_STATE_ATTACHED = 0x01,
  16772. + SSAM_BAS_BASE_STATE_NOT_FEASIBLE = 0x02,
  16773. +};
  16774. +
  16775. +enum ssam_bas_latch_status {
  16776. + SSAM_BAS_LATCH_STATUS_CLOSED = 0x00,
  16777. + SSAM_BAS_LATCH_STATUS_OPENED = 0x01,
  16778. + SSAM_BAS_LATCH_STATUS_FAILED_TO_OPEN = 0x02,
  16779. + SSAM_BAS_LATCH_STATUS_FAILED_TO_REMAIN_OPEN = 0x03,
  16780. + SSAM_BAS_LATCH_STATUS_FAILED_TO_CLOSE = 0x04,
  16781. +};
  16782. +
  16783. +enum ssam_bas_cancel_reason {
  16784. + SSAM_BAS_CANCEL_REASON_NOT_FEASIBLE = 0x00, /* Low battery. */
  16785. + SSAM_BAS_CANCEL_REASON_TIMEOUT = 0x02,
  16786. + SSAM_BAS_CANCEL_REASON_FAILED_TO_OPEN = 0x03,
  16787. + SSAM_BAS_CANCEL_REASON_FAILED_TO_REMAIN_OPEN = 0x04,
  16788. + SSAM_BAS_CANCEL_REASON_FAILED_TO_CLOSE = 0x05,
  16789. +};
  16790. +
  16791. +struct ssam_bas_base_info {
  16792. + u8 state;
  16793. + u8 base_id;
  16794. +} __packed;
  16795. +
  16796. +static_assert(sizeof(struct ssam_bas_base_info) == 2);
  16797. +
  16798. +static SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_lock, {
  16799. + .target_category = SSAM_SSH_TC_BAS,
  16800. + .target_id = 0x01,
  16801. + .command_id = 0x06,
  16802. + .instance_id = 0x00,
  16803. +});
  16804. +
  16805. +static SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_unlock, {
  16806. + .target_category = SSAM_SSH_TC_BAS,
  16807. + .target_id = 0x01,
  16808. + .command_id = 0x07,
  16809. + .instance_id = 0x00,
  16810. +});
  16811. +
  16812. +static SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_request, {
  16813. + .target_category = SSAM_SSH_TC_BAS,
  16814. + .target_id = 0x01,
  16815. + .command_id = 0x08,
  16816. + .instance_id = 0x00,
  16817. +});
  16818. +
  16819. +static SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_confirm, {
  16820. + .target_category = SSAM_SSH_TC_BAS,
  16821. + .target_id = 0x01,
  16822. + .command_id = 0x09,
  16823. + .instance_id = 0x00,
  16824. +});
  16825. +
  16826. +static SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_heartbeat, {
  16827. + .target_category = SSAM_SSH_TC_BAS,
  16828. + .target_id = 0x01,
  16829. + .command_id = 0x0a,
  16830. + .instance_id = 0x00,
  16831. +});
  16832. +
  16833. +static SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_cancel, {
  16834. + .target_category = SSAM_SSH_TC_BAS,
  16835. + .target_id = 0x01,
  16836. + .command_id = 0x0b,
  16837. + .instance_id = 0x00,
  16838. +});
  16839. +
  16840. +static SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_base, struct ssam_bas_base_info, {
  16841. + .target_category = SSAM_SSH_TC_BAS,
  16842. + .target_id = 0x01,
  16843. + .command_id = 0x0c,
  16844. + .instance_id = 0x00,
  16845. +});
  16846. +
  16847. +static SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_device_mode, u8, {
  16848. + .target_category = SSAM_SSH_TC_BAS,
  16849. + .target_id = 0x01,
  16850. + .command_id = 0x0d,
  16851. + .instance_id = 0x00,
  16852. +});
  16853. +
  16854. +static SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_latch_status, u8, {
  16855. + .target_category = SSAM_SSH_TC_BAS,
  16856. + .target_id = 0x01,
  16857. + .command_id = 0x11,
  16858. + .instance_id = 0x00,
  16859. +});
  16860. +
  16861. +
  16862. +/* -- Main structures. ------------------------------------------------------ */
  16863. +
  16864. +enum sdtx_device_state {
  16865. + SDTX_DEVICE_SHUTDOWN_BIT = BIT(0),
  16866. + SDTX_DEVICE_DIRTY_BASE_BIT = BIT(1),
  16867. + SDTX_DEVICE_DIRTY_MODE_BIT = BIT(2),
  16868. + SDTX_DEVICE_DIRTY_LATCH_BIT = BIT(3),
  16869. +};
  16870. +
  16871. +struct sdtx_device {
  16872. + struct kref kref;
  16873. + struct rw_semaphore lock; /* Guards device and controller reference. */
  16874. +
  16875. + struct device *dev;
  16876. + struct ssam_controller *ctrl;
  16877. + unsigned long flags;
  16878. +
  16879. + struct miscdevice mdev;
  16880. + wait_queue_head_t waitq;
  16881. + struct mutex write_lock; /* Guards order of events/notifications. */
  16882. + struct rw_semaphore client_lock; /* Guards client list. */
  16883. + struct list_head client_list;
  16884. +
  16885. + struct delayed_work state_work;
  16886. + struct {
  16887. + struct ssam_bas_base_info base;
  16888. + u8 device_mode;
  16889. + u8 latch_status;
  16890. + } state;
  16891. +
  16892. + struct delayed_work mode_work;
  16893. + struct input_dev *mode_switch;
  16894. +
  16895. + struct ssam_event_notifier notif;
  16896. +};
  16897. +
  16898. +enum sdtx_client_state {
  16899. + SDTX_CLIENT_EVENTS_ENABLED_BIT = BIT(0),
  16900. +};
  16901. +
  16902. +struct sdtx_client {
  16903. + struct sdtx_device *ddev;
  16904. + struct list_head node;
  16905. + unsigned long flags;
  16906. +
  16907. + struct fasync_struct *fasync;
  16908. +
  16909. + struct mutex read_lock; /* Guards FIFO buffer read access. */
  16910. + DECLARE_KFIFO(buffer, u8, 512);
  16911. +};
  16912. +
  16913. +static void __sdtx_device_release(struct kref *kref)
  16914. +{
  16915. + struct sdtx_device *ddev = container_of(kref, struct sdtx_device, kref);
  16916. +
  16917. + mutex_destroy(&ddev->write_lock);
  16918. + kfree(ddev);
  16919. +}
  16920. +
  16921. +static struct sdtx_device *sdtx_device_get(struct sdtx_device *ddev)
  16922. +{
  16923. + if (ddev)
  16924. + kref_get(&ddev->kref);
  16925. +
  16926. + return ddev;
  16927. +}
  16928. +
  16929. +static void sdtx_device_put(struct sdtx_device *ddev)
  16930. +{
  16931. + if (ddev)
  16932. + kref_put(&ddev->kref, __sdtx_device_release);
  16933. +}
  16934. +
  16935. +
  16936. +/* -- Firmware value translations. ------------------------------------------ */
  16937. +
  16938. +static u16 sdtx_translate_base_state(struct sdtx_device *ddev, u8 state)
  16939. +{
  16940. + switch (state) {
  16941. + case SSAM_BAS_BASE_STATE_ATTACHED:
  16942. + return SDTX_BASE_ATTACHED;
  16943. +
  16944. + case SSAM_BAS_BASE_STATE_DETACH_SUCCESS:
  16945. + return SDTX_BASE_DETACHED;
  16946. +
  16947. + case SSAM_BAS_BASE_STATE_NOT_FEASIBLE:
  16948. + return SDTX_DETACH_NOT_FEASIBLE;
  16949. +
  16950. + default:
  16951. + dev_err(ddev->dev, "unknown base state: %#04x\n", state);
  16952. + return SDTX_UNKNOWN(state);
  16953. + }
  16954. +}
  16955. +
  16956. +static u16 sdtx_translate_latch_status(struct sdtx_device *ddev, u8 status)
  16957. +{
  16958. + switch (status) {
  16959. + case SSAM_BAS_LATCH_STATUS_CLOSED:
  16960. + return SDTX_LATCH_CLOSED;
  16961. +
  16962. + case SSAM_BAS_LATCH_STATUS_OPENED:
  16963. + return SDTX_LATCH_OPENED;
  16964. +
  16965. + case SSAM_BAS_LATCH_STATUS_FAILED_TO_OPEN:
  16966. + return SDTX_ERR_FAILED_TO_OPEN;
  16967. +
  16968. + case SSAM_BAS_LATCH_STATUS_FAILED_TO_REMAIN_OPEN:
  16969. + return SDTX_ERR_FAILED_TO_REMAIN_OPEN;
  16970. +
  16971. + case SSAM_BAS_LATCH_STATUS_FAILED_TO_CLOSE:
  16972. + return SDTX_ERR_FAILED_TO_CLOSE;
  16973. +
  16974. + default:
  16975. + dev_err(ddev->dev, "unknown latch status: %#04x\n", status);
  16976. + return SDTX_UNKNOWN(status);
  16977. + }
  16978. +}
  16979. +
  16980. +static u16 sdtx_translate_cancel_reason(struct sdtx_device *ddev, u8 reason)
  16981. +{
  16982. + switch (reason) {
  16983. + case SSAM_BAS_CANCEL_REASON_NOT_FEASIBLE:
  16984. + return SDTX_DETACH_NOT_FEASIBLE;
  16985. +
  16986. + case SSAM_BAS_CANCEL_REASON_TIMEOUT:
  16987. + return SDTX_DETACH_TIMEDOUT;
  16988. +
  16989. + case SSAM_BAS_CANCEL_REASON_FAILED_TO_OPEN:
  16990. + return SDTX_ERR_FAILED_TO_OPEN;
  16991. +
  16992. + case SSAM_BAS_CANCEL_REASON_FAILED_TO_REMAIN_OPEN:
  16993. + return SDTX_ERR_FAILED_TO_REMAIN_OPEN;
  16994. +
  16995. + case SSAM_BAS_CANCEL_REASON_FAILED_TO_CLOSE:
  16996. + return SDTX_ERR_FAILED_TO_CLOSE;
  16997. +
  16998. + default:
  16999. + dev_err(ddev->dev, "unknown cancel reason: %#04x\n", reason);
  17000. + return SDTX_UNKNOWN(reason);
  17001. + }
  17002. +}
  17003. +
  17004. +
  17005. +/* -- IOCTLs. --------------------------------------------------------------- */
  17006. +
  17007. +static int sdtx_ioctl_get_base_info(struct sdtx_device *ddev,
  17008. + struct sdtx_base_info __user *buf)
  17009. +{
  17010. + struct ssam_bas_base_info raw;
  17011. + struct sdtx_base_info info;
  17012. + int status;
  17013. +
  17014. + lockdep_assert_held_read(&ddev->lock);
  17015. +
  17016. + status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &raw);
  17017. + if (status < 0)
  17018. + return status;
  17019. +
  17020. + info.state = sdtx_translate_base_state(ddev, raw.state);
  17021. + info.base_id = SDTX_BASE_TYPE_SSH(raw.base_id);
  17022. +
  17023. + if (copy_to_user(buf, &info, sizeof(info)))
  17024. + return -EFAULT;
  17025. +
  17026. + return 0;
  17027. +}
  17028. +
  17029. +static int sdtx_ioctl_get_device_mode(struct sdtx_device *ddev, u16 __user *buf)
  17030. +{
  17031. + u8 mode;
  17032. + int status;
  17033. +
  17034. + lockdep_assert_held_read(&ddev->lock);
  17035. +
  17036. + status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &mode);
  17037. + if (status < 0)
  17038. + return status;
  17039. +
  17040. + return put_user(mode, buf);
  17041. +}
  17042. +
  17043. +static int sdtx_ioctl_get_latch_status(struct sdtx_device *ddev, u16 __user *buf)
  17044. +{
  17045. + u8 latch;
  17046. + int status;
  17047. +
  17048. + lockdep_assert_held_read(&ddev->lock);
  17049. +
  17050. + status = ssam_retry(ssam_bas_get_latch_status, ddev->ctrl, &latch);
  17051. + if (status < 0)
  17052. + return status;
  17053. +
  17054. + return put_user(sdtx_translate_latch_status(ddev, latch), buf);
  17055. +}
  17056. +
  17057. +static long __surface_dtx_ioctl(struct sdtx_client *client, unsigned int cmd, unsigned long arg)
  17058. +{
  17059. + struct sdtx_device *ddev = client->ddev;
  17060. +
  17061. + lockdep_assert_held_read(&ddev->lock);
  17062. +
  17063. + switch (cmd) {
  17064. + case SDTX_IOCTL_EVENTS_ENABLE:
  17065. + set_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags);
  17066. + return 0;
  17067. +
  17068. + case SDTX_IOCTL_EVENTS_DISABLE:
  17069. + clear_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags);
  17070. + return 0;
  17071. +
  17072. + case SDTX_IOCTL_LATCH_LOCK:
  17073. + return ssam_retry(ssam_bas_latch_lock, ddev->ctrl);
  17074. +
  17075. + case SDTX_IOCTL_LATCH_UNLOCK:
  17076. + return ssam_retry(ssam_bas_latch_unlock, ddev->ctrl);
  17077. +
  17078. + case SDTX_IOCTL_LATCH_REQUEST:
  17079. + return ssam_retry(ssam_bas_latch_request, ddev->ctrl);
  17080. +
  17081. + case SDTX_IOCTL_LATCH_CONFIRM:
  17082. + return ssam_retry(ssam_bas_latch_confirm, ddev->ctrl);
  17083. +
  17084. + case SDTX_IOCTL_LATCH_HEARTBEAT:
  17085. + return ssam_retry(ssam_bas_latch_heartbeat, ddev->ctrl);
  17086. +
  17087. + case SDTX_IOCTL_LATCH_CANCEL:
  17088. + return ssam_retry(ssam_bas_latch_cancel, ddev->ctrl);
  17089. +
  17090. + case SDTX_IOCTL_GET_BASE_INFO:
  17091. + return sdtx_ioctl_get_base_info(ddev, (struct sdtx_base_info __user *)arg);
  17092. +
  17093. + case SDTX_IOCTL_GET_DEVICE_MODE:
  17094. + return sdtx_ioctl_get_device_mode(ddev, (u16 __user *)arg);
  17095. +
  17096. + case SDTX_IOCTL_GET_LATCH_STATUS:
  17097. + return sdtx_ioctl_get_latch_status(ddev, (u16 __user *)arg);
  17098. +
  17099. + default:
  17100. + return -EINVAL;
  17101. + }
  17102. +}
  17103. +
  17104. +static long surface_dtx_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  17105. +{
  17106. + struct sdtx_client *client = file->private_data;
  17107. + long status;
  17108. +
  17109. + if (down_read_killable(&client->ddev->lock))
  17110. + return -ERESTARTSYS;
  17111. +
  17112. + if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &client->ddev->flags)) {
  17113. + up_read(&client->ddev->lock);
  17114. + return -ENODEV;
  17115. + }
  17116. +
  17117. + status = __surface_dtx_ioctl(client, cmd, arg);
  17118. +
  17119. + up_read(&client->ddev->lock);
  17120. + return status;
  17121. +}
  17122. +
  17123. +
  17124. +/* -- File operations. ------------------------------------------------------ */
  17125. +
  17126. +static int surface_dtx_open(struct inode *inode, struct file *file)
  17127. +{
  17128. + struct sdtx_device *ddev = container_of(file->private_data, struct sdtx_device, mdev);
  17129. + struct sdtx_client *client;
  17130. +
  17131. + /* Initialize client. */
  17132. + client = kzalloc(sizeof(*client), GFP_KERNEL);
  17133. + if (!client)
  17134. + return -ENOMEM;
  17135. +
  17136. + client->ddev = sdtx_device_get(ddev);
  17137. +
  17138. + INIT_LIST_HEAD(&client->node);
  17139. +
  17140. + mutex_init(&client->read_lock);
  17141. + INIT_KFIFO(client->buffer);
  17142. +
  17143. + file->private_data = client;
  17144. +
  17145. + /* Attach client. */
  17146. + down_write(&ddev->client_lock);
  17147. +
  17148. + /*
  17149. + * Do not add a new client if the device has been shut down. Note that
  17150. + * it's enough to hold the client_lock here as, during shutdown, we
  17151. + * only acquire that lock and remove clients after marking the device
  17152. + * as shut down.
  17153. + */
  17154. + if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags)) {
  17155. + up_write(&ddev->client_lock);
  17156. + sdtx_device_put(client->ddev);
  17157. + kfree(client);
  17158. + return -ENODEV;
  17159. + }
  17160. +
  17161. + list_add_tail(&client->node, &ddev->client_list);
  17162. + up_write(&ddev->client_lock);
  17163. +
  17164. + stream_open(inode, file);
  17165. + return 0;
  17166. +}
  17167. +
  17168. +static int surface_dtx_release(struct inode *inode, struct file *file)
  17169. +{
  17170. + struct sdtx_client *client = file->private_data;
  17171. +
  17172. + /* Detach client. */
  17173. + down_write(&client->ddev->client_lock);
  17174. + list_del(&client->node);
  17175. + up_write(&client->ddev->client_lock);
  17176. +
  17177. + /* Free client. */
  17178. + sdtx_device_put(client->ddev);
  17179. + mutex_destroy(&client->read_lock);
  17180. + kfree(client);
  17181. +
  17182. + return 0;
  17183. +}
  17184. +
  17185. +static ssize_t surface_dtx_read(struct file *file, char __user *buf, size_t count, loff_t *offs)
  17186. +{
  17187. + struct sdtx_client *client = file->private_data;
  17188. + struct sdtx_device *ddev = client->ddev;
  17189. + unsigned int copied;
  17190. + int status = 0;
  17191. +
  17192. + if (down_read_killable(&ddev->lock))
  17193. + return -ERESTARTSYS;
  17194. +
  17195. + /* Make sure we're not shut down. */
  17196. + if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags)) {
  17197. + up_read(&ddev->lock);
  17198. + return -ENODEV;
  17199. + }
  17200. +
  17201. + do {
  17202. + /* Check availability, wait if necessary. */
  17203. + if (kfifo_is_empty(&client->buffer)) {
  17204. + up_read(&ddev->lock);
  17205. +
  17206. + if (file->f_flags & O_NONBLOCK)
  17207. + return -EAGAIN;
  17208. +
  17209. + status = wait_event_interruptible(ddev->waitq,
  17210. + !kfifo_is_empty(&client->buffer) ||
  17211. + test_bit(SDTX_DEVICE_SHUTDOWN_BIT,
  17212. + &ddev->flags));
  17213. + if (status < 0)
  17214. + return status;
  17215. +
  17216. + if (down_read_killable(&client->ddev->lock))
  17217. + return -ERESTARTSYS;
  17218. +
  17219. + /* Need to check that we're not shut down again. */
  17220. + if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags)) {
  17221. + up_read(&ddev->lock);
  17222. + return -ENODEV;
  17223. + }
  17224. + }
  17225. +
  17226. + /* Try to read from FIFO. */
  17227. + if (mutex_lock_interruptible(&client->read_lock)) {
  17228. + up_read(&ddev->lock);
  17229. + return -ERESTARTSYS;
  17230. + }
  17231. +
  17232. + status = kfifo_to_user(&client->buffer, buf, count, &copied);
  17233. + mutex_unlock(&client->read_lock);
  17234. +
  17235. + if (status < 0) {
  17236. + up_read(&ddev->lock);
  17237. + return status;
  17238. + }
  17239. +
  17240. + /* We might not have gotten anything, check this here. */
  17241. + if (copied == 0 && (file->f_flags & O_NONBLOCK)) {
  17242. + up_read(&ddev->lock);
  17243. + return -EAGAIN;
  17244. + }
  17245. + } while (copied == 0);
  17246. +
  17247. + up_read(&ddev->lock);
  17248. + return copied;
  17249. +}
  17250. +
  17251. +static __poll_t surface_dtx_poll(struct file *file, struct poll_table_struct *pt)
  17252. +{
  17253. + struct sdtx_client *client = file->private_data;
  17254. + __poll_t events = 0;
  17255. +
  17256. + if (down_read_killable(&client->ddev->lock))
  17257. + return -ERESTARTSYS;
  17258. +
  17259. + if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &client->ddev->flags)) {
  17260. + up_read(&client->ddev->lock);
  17261. + return EPOLLHUP | EPOLLERR;
  17262. + }
  17263. +
  17264. + poll_wait(file, &client->ddev->waitq, pt);
  17265. +
  17266. + if (!kfifo_is_empty(&client->buffer))
  17267. + events |= EPOLLIN | EPOLLRDNORM;
  17268. +
  17269. + up_read(&client->ddev->lock);
  17270. + return events;
  17271. +}
  17272. +
  17273. +static int surface_dtx_fasync(int fd, struct file *file, int on)
  17274. +{
  17275. + struct sdtx_client *client = file->private_data;
  17276. +
  17277. + return fasync_helper(fd, file, on, &client->fasync);
  17278. +}
  17279. +
  17280. +static const struct file_operations surface_dtx_fops = {
  17281. + .owner = THIS_MODULE,
  17282. + .open = surface_dtx_open,
  17283. + .release = surface_dtx_release,
  17284. + .read = surface_dtx_read,
  17285. + .poll = surface_dtx_poll,
  17286. + .fasync = surface_dtx_fasync,
  17287. + .unlocked_ioctl = surface_dtx_ioctl,
  17288. + .compat_ioctl = surface_dtx_ioctl,
  17289. + .llseek = no_llseek,
  17290. +};
  17291. +
  17292. +
  17293. +/* -- Event handling/forwarding. -------------------------------------------- */
  17294. +
  17295. +/*
  17296. + * The device operation mode is not immediately updated on the EC when the
  17297. + * base has been connected, i.e. querying the device mode inside the
  17298. + * connection event callback yields an outdated value. Thus, we can only
  17299. + * determine the new tablet-mode switch and device mode values after some
  17300. + * time.
  17301. + *
  17302. + * These delays have been chosen by experimenting. We first delay on connect
  17303. + * events, then check and validate the device mode against the base state and
  17304. + * if invalid delay again by the "recheck" delay.
  17305. + */
  17306. +#define SDTX_DEVICE_MODE_DELAY_CONNECT msecs_to_jiffies(100)
  17307. +#define SDTX_DEVICE_MODE_DELAY_RECHECK msecs_to_jiffies(100)
  17308. +
  17309. +struct sdtx_status_event {
  17310. + struct sdtx_event e;
  17311. + __u16 v;
  17312. +} __packed;
  17313. +
  17314. +struct sdtx_base_info_event {
  17315. + struct sdtx_event e;
  17316. + struct sdtx_base_info v;
  17317. +} __packed;
  17318. +
  17319. +union sdtx_generic_event {
  17320. + struct sdtx_event common;
  17321. + struct sdtx_status_event status;
  17322. + struct sdtx_base_info_event base;
  17323. +};
  17324. +
  17325. +static void sdtx_update_device_mode(struct sdtx_device *ddev, unsigned long delay);
  17326. +
  17327. +/* Must be executed with ddev->write_lock held. */
  17328. +static void sdtx_push_event(struct sdtx_device *ddev, struct sdtx_event *evt)
  17329. +{
  17330. + const size_t len = sizeof(struct sdtx_event) + evt->length;
  17331. + struct sdtx_client *client;
  17332. +
  17333. + lockdep_assert_held(&ddev->write_lock);
  17334. +
  17335. + down_read(&ddev->client_lock);
  17336. + list_for_each_entry(client, &ddev->client_list, node) {
  17337. + if (!test_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags))
  17338. + continue;
  17339. +
  17340. + if (likely(kfifo_avail(&client->buffer) >= len))
  17341. + kfifo_in(&client->buffer, (const u8 *)evt, len);
  17342. + else
  17343. + dev_warn(ddev->dev, "event buffer overrun\n");
  17344. +
  17345. + kill_fasync(&client->fasync, SIGIO, POLL_IN);
  17346. + }
  17347. + up_read(&ddev->client_lock);
  17348. +
  17349. + wake_up_interruptible(&ddev->waitq);
  17350. +}
  17351. +
  17352. +static u32 sdtx_notifier(struct ssam_event_notifier *nf, const struct ssam_event *in)
  17353. +{
  17354. + struct sdtx_device *ddev = container_of(nf, struct sdtx_device, notif);
  17355. + union sdtx_generic_event event;
  17356. + size_t len;
  17357. +
  17358. + /* Validate event payload length. */
  17359. + switch (in->command_id) {
  17360. + case SAM_EVENT_CID_DTX_CONNECTION:
  17361. + len = 2 * sizeof(u8);
  17362. + break;
  17363. +
  17364. + case SAM_EVENT_CID_DTX_REQUEST:
  17365. + len = 0;
  17366. + break;
  17367. +
  17368. + case SAM_EVENT_CID_DTX_CANCEL:
  17369. + len = sizeof(u8);
  17370. + break;
  17371. +
  17372. + case SAM_EVENT_CID_DTX_LATCH_STATUS:
  17373. + len = sizeof(u8);
  17374. + break;
  17375. +
  17376. + default:
  17377. + return 0;
  17378. + };
  17379. +
  17380. + if (in->length != len) {
  17381. + dev_err(ddev->dev,
  17382. + "unexpected payload size for event %#04x: got %u, expected %zu\n",
  17383. + in->command_id, in->length, len);
  17384. + return 0;
  17385. + }
  17386. +
  17387. + mutex_lock(&ddev->write_lock);
  17388. +
  17389. + /* Translate event. */
  17390. + switch (in->command_id) {
  17391. + case SAM_EVENT_CID_DTX_CONNECTION:
  17392. + clear_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags);
  17393. +
  17394. + /* If state has not changed: do not send new event. */
  17395. + if (ddev->state.base.state == in->data[0] &&
  17396. + ddev->state.base.base_id == in->data[1])
  17397. + goto out;
  17398. +
  17399. + ddev->state.base.state = in->data[0];
  17400. + ddev->state.base.base_id = in->data[1];
  17401. +
  17402. + event.base.e.length = sizeof(struct sdtx_base_info);
  17403. + event.base.e.code = SDTX_EVENT_BASE_CONNECTION;
  17404. + event.base.v.state = sdtx_translate_base_state(ddev, in->data[0]);
  17405. + event.base.v.base_id = SDTX_BASE_TYPE_SSH(in->data[1]);
  17406. + break;
  17407. +
  17408. + case SAM_EVENT_CID_DTX_REQUEST:
  17409. + event.common.code = SDTX_EVENT_REQUEST;
  17410. + event.common.length = 0;
  17411. + break;
  17412. +
  17413. + case SAM_EVENT_CID_DTX_CANCEL:
  17414. + event.status.e.length = sizeof(u16);
  17415. + event.status.e.code = SDTX_EVENT_CANCEL;
  17416. + event.status.v = sdtx_translate_cancel_reason(ddev, in->data[0]);
  17417. + break;
  17418. +
  17419. + case SAM_EVENT_CID_DTX_LATCH_STATUS:
  17420. + clear_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags);
  17421. +
  17422. + /* If state has not changed: do not send new event. */
  17423. + if (ddev->state.latch_status == in->data[0])
  17424. + goto out;
  17425. +
  17426. + ddev->state.latch_status = in->data[0];
  17427. +
  17428. + event.status.e.length = sizeof(u16);
  17429. + event.status.e.code = SDTX_EVENT_LATCH_STATUS;
  17430. + event.status.v = sdtx_translate_latch_status(ddev, in->data[0]);
  17431. + break;
  17432. + }
  17433. +
  17434. + sdtx_push_event(ddev, &event.common);
  17435. +
  17436. + /* Update device mode on base connection change. */
  17437. + if (in->command_id == SAM_EVENT_CID_DTX_CONNECTION) {
  17438. + unsigned long delay;
  17439. +
  17440. + delay = in->data[0] ? SDTX_DEVICE_MODE_DELAY_CONNECT : 0;
  17441. + sdtx_update_device_mode(ddev, delay);
  17442. + }
  17443. +
  17444. +out:
  17445. + mutex_unlock(&ddev->write_lock);
  17446. + return SSAM_NOTIF_HANDLED;
  17447. +}
  17448. +
  17449. +
  17450. +/* -- State update functions. ----------------------------------------------- */
  17451. +
  17452. +static bool sdtx_device_mode_invalid(u8 mode, u8 base_state)
  17453. +{
  17454. + return ((base_state == SSAM_BAS_BASE_STATE_ATTACHED) &&
  17455. + (mode == SDTX_DEVICE_MODE_TABLET)) ||
  17456. + ((base_state == SSAM_BAS_BASE_STATE_DETACH_SUCCESS) &&
  17457. + (mode != SDTX_DEVICE_MODE_TABLET));
  17458. +}
  17459. +
  17460. +static void sdtx_device_mode_workfn(struct work_struct *work)
  17461. +{
  17462. + struct sdtx_device *ddev = container_of(work, struct sdtx_device, mode_work.work);
  17463. + struct sdtx_status_event event;
  17464. + struct ssam_bas_base_info base;
  17465. + int status, tablet;
  17466. + u8 mode;
  17467. +
  17468. + /* Get operation mode. */
  17469. + status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &mode);
  17470. + if (status) {
  17471. + dev_err(ddev->dev, "failed to get device mode: %d\n", status);
  17472. + return;
  17473. + }
  17474. +
  17475. + /* Get base info. */
  17476. + status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &base);
  17477. + if (status) {
  17478. + dev_err(ddev->dev, "failed to get base info: %d\n", status);
  17479. + return;
  17480. + }
  17481. +
  17482. + /*
  17483. + * In some cases (specifically when attaching the base), the device
  17484. + * mode isn't updated right away. Thus we check if the device mode
  17485. + * makes sense for the given base state and try again later if it
  17486. + * doesn't.
  17487. + */
  17488. + if (sdtx_device_mode_invalid(mode, base.state)) {
  17489. + dev_dbg(ddev->dev, "device mode is invalid, trying again\n");
  17490. + sdtx_update_device_mode(ddev, SDTX_DEVICE_MODE_DELAY_RECHECK);
  17491. + return;
  17492. + }
  17493. +
  17494. + mutex_lock(&ddev->write_lock);
  17495. + clear_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags);
  17496. +
  17497. + /* Avoid sending duplicate device-mode events. */
  17498. + if (ddev->state.device_mode == mode) {
  17499. + mutex_unlock(&ddev->write_lock);
  17500. + return;
  17501. + }
  17502. +
  17503. + ddev->state.device_mode = mode;
  17504. +
  17505. + event.e.length = sizeof(u16);
  17506. + event.e.code = SDTX_EVENT_DEVICE_MODE;
  17507. + event.v = mode;
  17508. +
  17509. + sdtx_push_event(ddev, &event.e);
  17510. +
  17511. + /* Send SW_TABLET_MODE event. */
  17512. + tablet = mode != SDTX_DEVICE_MODE_LAPTOP;
  17513. + input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet);
  17514. + input_sync(ddev->mode_switch);
  17515. +
  17516. + mutex_unlock(&ddev->write_lock);
  17517. +}
  17518. +
  17519. +static void sdtx_update_device_mode(struct sdtx_device *ddev, unsigned long delay)
  17520. +{
  17521. + schedule_delayed_work(&ddev->mode_work, delay);
  17522. +}
  17523. +
  17524. +/* Must be executed with ddev->write_lock held. */
  17525. +static void __sdtx_device_state_update_base(struct sdtx_device *ddev,
  17526. + struct ssam_bas_base_info info)
  17527. +{
  17528. + struct sdtx_base_info_event event;
  17529. +
  17530. + lockdep_assert_held(&ddev->write_lock);
  17531. +
  17532. + /* Prevent duplicate events. */
  17533. + if (ddev->state.base.state == info.state &&
  17534. + ddev->state.base.base_id == info.base_id)
  17535. + return;
  17536. +
  17537. + ddev->state.base = info;
  17538. +
  17539. + event.e.length = sizeof(struct sdtx_base_info);
  17540. + event.e.code = SDTX_EVENT_BASE_CONNECTION;
  17541. + event.v.state = sdtx_translate_base_state(ddev, info.state);
  17542. + event.v.base_id = SDTX_BASE_TYPE_SSH(info.base_id);
  17543. +
  17544. + sdtx_push_event(ddev, &event.e);
  17545. +}
  17546. +
  17547. +/* Must be executed with ddev->write_lock held. */
  17548. +static void __sdtx_device_state_update_mode(struct sdtx_device *ddev, u8 mode)
  17549. +{
  17550. + struct sdtx_status_event event;
  17551. + int tablet;
  17552. +
  17553. + /*
  17554. + * Note: This function must be called after updating the base state
  17555. + * via __sdtx_device_state_update_base(), as we rely on the updated
  17556. + * base state value in the validity check below.
  17557. + */
  17558. +
  17559. + lockdep_assert_held(&ddev->write_lock);
  17560. +
  17561. + if (sdtx_device_mode_invalid(mode, ddev->state.base.state)) {
  17562. + dev_dbg(ddev->dev, "device mode is invalid, trying again\n");
  17563. + sdtx_update_device_mode(ddev, SDTX_DEVICE_MODE_DELAY_RECHECK);
  17564. + return;
  17565. + }
  17566. +
  17567. + /* Prevent duplicate events. */
  17568. + if (ddev->state.device_mode == mode)
  17569. + return;
  17570. +
  17571. + ddev->state.device_mode = mode;
  17572. +
  17573. + /* Send event. */
  17574. + event.e.length = sizeof(u16);
  17575. + event.e.code = SDTX_EVENT_DEVICE_MODE;
  17576. + event.v = mode;
  17577. +
  17578. + sdtx_push_event(ddev, &event.e);
  17579. +
  17580. + /* Send SW_TABLET_MODE event. */
  17581. + tablet = mode != SDTX_DEVICE_MODE_LAPTOP;
  17582. + input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet);
  17583. + input_sync(ddev->mode_switch);
  17584. +}
  17585. +
  17586. +/* Must be executed with ddev->write_lock held. */
  17587. +static void __sdtx_device_state_update_latch(struct sdtx_device *ddev, u8 status)
  17588. +{
  17589. + struct sdtx_status_event event;
  17590. +
  17591. + lockdep_assert_held(&ddev->write_lock);
  17592. +
  17593. + /* Prevent duplicate events. */
  17594. + if (ddev->state.latch_status == status)
  17595. + return;
  17596. +
  17597. + ddev->state.latch_status = status;
  17598. +
  17599. + event.e.length = sizeof(struct sdtx_base_info);
  17600. + event.e.code = SDTX_EVENT_BASE_CONNECTION;
  17601. + event.v = sdtx_translate_latch_status(ddev, status);
  17602. +
  17603. + sdtx_push_event(ddev, &event.e);
  17604. +}
  17605. +
  17606. +static void sdtx_device_state_workfn(struct work_struct *work)
  17607. +{
  17608. + struct sdtx_device *ddev = container_of(work, struct sdtx_device, state_work.work);
  17609. + struct ssam_bas_base_info base;
  17610. + u8 mode, latch;
  17611. + int status;
  17612. +
  17613. + /* Mark everything as dirty. */
  17614. + set_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags);
  17615. + set_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags);
  17616. + set_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags);
  17617. +
  17618. + /*
  17619. + * Ensure that the state gets marked as dirty before continuing to
  17620. + * query it. Necessary to ensure that clear_bit() calls in
  17621. + * sdtx_notifier() and sdtx_device_mode_workfn() actually clear these
  17622. + * bits if an event is received while updating the state here.
  17623. + */
  17624. + smp_mb__after_atomic();
  17625. +
  17626. + status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &base);
  17627. + if (status) {
  17628. + dev_err(ddev->dev, "failed to get base state: %d\n", status);
  17629. + return;
  17630. + }
  17631. +
  17632. + status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &mode);
  17633. + if (status) {
  17634. + dev_err(ddev->dev, "failed to get device mode: %d\n", status);
  17635. + return;
  17636. + }
  17637. +
  17638. + status = ssam_retry(ssam_bas_get_latch_status, ddev->ctrl, &latch);
  17639. + if (status) {
  17640. + dev_err(ddev->dev, "failed to get latch status: %d\n", status);
  17641. + return;
  17642. + }
  17643. +
  17644. + mutex_lock(&ddev->write_lock);
  17645. +
  17646. + /*
  17647. + * If the respective dirty-bit has been cleared, an event has been
  17648. + * received, updating this state. The queried state may thus be out of
  17649. + * date. At this point, we can safely assume that the state provided
  17650. + * by the event is either up to date, or we're about to receive
  17651. + * another event updating it.
  17652. + */
  17653. +
  17654. + if (test_and_clear_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags))
  17655. + __sdtx_device_state_update_base(ddev, base);
  17656. +
  17657. + if (test_and_clear_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags))
  17658. + __sdtx_device_state_update_mode(ddev, mode);
  17659. +
  17660. + if (test_and_clear_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags))
  17661. + __sdtx_device_state_update_latch(ddev, latch);
  17662. +
  17663. + mutex_unlock(&ddev->write_lock);
  17664. +}
  17665. +
  17666. +static void sdtx_update_device_state(struct sdtx_device *ddev, unsigned long delay)
  17667. +{
  17668. + schedule_delayed_work(&ddev->state_work, delay);
  17669. +}
  17670. +
  17671. +
  17672. +/* -- Common device initialization. ----------------------------------------- */
  17673. +
  17674. +static int sdtx_device_init(struct sdtx_device *ddev, struct device *dev,
  17675. + struct ssam_controller *ctrl)
  17676. +{
  17677. + int status, tablet_mode;
  17678. +
  17679. + /* Basic initialization. */
  17680. + kref_init(&ddev->kref);
  17681. + init_rwsem(&ddev->lock);
  17682. + ddev->dev = dev;
  17683. + ddev->ctrl = ctrl;
  17684. +
  17685. + ddev->mdev.minor = MISC_DYNAMIC_MINOR;
  17686. + ddev->mdev.name = "surface_dtx";
  17687. + ddev->mdev.nodename = "surface/dtx";
  17688. + ddev->mdev.fops = &surface_dtx_fops;
  17689. +
  17690. + ddev->notif.base.priority = 1;
  17691. + ddev->notif.base.fn = sdtx_notifier;
  17692. + ddev->notif.event.reg = SSAM_EVENT_REGISTRY_SAM;
  17693. + ddev->notif.event.id.target_category = SSAM_SSH_TC_BAS;
  17694. + ddev->notif.event.id.instance = 0;
  17695. + ddev->notif.event.mask = SSAM_EVENT_MASK_NONE;
  17696. + ddev->notif.event.flags = SSAM_EVENT_SEQUENCED;
  17697. +
  17698. + init_waitqueue_head(&ddev->waitq);
  17699. + mutex_init(&ddev->write_lock);
  17700. + init_rwsem(&ddev->client_lock);
  17701. + INIT_LIST_HEAD(&ddev->client_list);
  17702. +
  17703. + INIT_DELAYED_WORK(&ddev->mode_work, sdtx_device_mode_workfn);
  17704. + INIT_DELAYED_WORK(&ddev->state_work, sdtx_device_state_workfn);
  17705. +
  17706. + /*
  17707. + * Get current device state. We want to guarantee that events are only
  17708. + * sent when state actually changes. Thus we cannot use special
  17709. + * "uninitialized" values, as that would cause problems when manually
  17710. + * querying the state in surface_dtx_pm_complete(). I.e. we would not
  17711. + * be able to detect state changes there if no change event has been
  17712. + * received between driver initialization and first device suspension.
  17713. + *
  17714. + * Note that we also need to do this before registering the event
  17715. + * notifier, as that may access the state values.
  17716. + */
  17717. + status = ssam_retry(ssam_bas_get_base, ddev->ctrl, &ddev->state.base);
  17718. + if (status)
  17719. + return status;
  17720. +
  17721. + status = ssam_retry(ssam_bas_get_device_mode, ddev->ctrl, &ddev->state.device_mode);
  17722. + if (status)
  17723. + return status;
  17724. +
  17725. + status = ssam_retry(ssam_bas_get_latch_status, ddev->ctrl, &ddev->state.latch_status);
  17726. + if (status)
  17727. + return status;
  17728. +
  17729. + /* Set up tablet mode switch. */
  17730. + ddev->mode_switch = input_allocate_device();
  17731. + if (!ddev->mode_switch)
  17732. + return -ENOMEM;
  17733. +
  17734. + ddev->mode_switch->name = "Microsoft Surface DTX Device Mode Switch";
  17735. + ddev->mode_switch->phys = "ssam/01:11:01:00:00/input0";
  17736. + ddev->mode_switch->id.bustype = BUS_HOST;
  17737. + ddev->mode_switch->dev.parent = ddev->dev;
  17738. +
  17739. + tablet_mode = (ddev->state.device_mode != SDTX_DEVICE_MODE_LAPTOP);
  17740. + input_set_capability(ddev->mode_switch, EV_SW, SW_TABLET_MODE);
  17741. + input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet_mode);
  17742. +
  17743. + status = input_register_device(ddev->mode_switch);
  17744. + if (status) {
  17745. + input_free_device(ddev->mode_switch);
  17746. + return status;
  17747. + }
  17748. +
  17749. + /* Set up event notifier. */
  17750. + status = ssam_notifier_register(ddev->ctrl, &ddev->notif);
  17751. + if (status)
  17752. + goto err_notif;
  17753. +
  17754. + /* Register miscdevice. */
  17755. + status = misc_register(&ddev->mdev);
  17756. + if (status)
  17757. + goto err_mdev;
  17758. +
  17759. + /*
  17760. + * Update device state in case it has changed between getting the
  17761. + * initial mode and registering the event notifier.
  17762. + */
  17763. + sdtx_update_device_state(ddev, 0);
  17764. + return 0;
  17765. +
  17766. +err_notif:
  17767. + ssam_notifier_unregister(ddev->ctrl, &ddev->notif);
  17768. + cancel_delayed_work_sync(&ddev->mode_work);
  17769. +err_mdev:
  17770. + input_unregister_device(ddev->mode_switch);
  17771. + return status;
  17772. +}
  17773. +
  17774. +static struct sdtx_device *sdtx_device_create(struct device *dev, struct ssam_controller *ctrl)
  17775. +{
  17776. + struct sdtx_device *ddev;
  17777. + int status;
  17778. +
  17779. + ddev = kzalloc(sizeof(*ddev), GFP_KERNEL);
  17780. + if (!ddev)
  17781. + return ERR_PTR(-ENOMEM);
  17782. +
  17783. + status = sdtx_device_init(ddev, dev, ctrl);
  17784. + if (status) {
  17785. + sdtx_device_put(ddev);
  17786. + return ERR_PTR(status);
  17787. + }
  17788. +
  17789. + return ddev;
  17790. +}
  17791. +
  17792. +static void sdtx_device_destroy(struct sdtx_device *ddev)
  17793. +{
  17794. + struct sdtx_client *client;
  17795. +
  17796. + /*
  17797. + * Mark device as shut-down. Prevent new clients from being added and
  17798. + * new operations from being executed.
  17799. + */
  17800. + set_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags);
  17801. +
  17802. + /* Disable notifiers, prevent new events from arriving. */
  17803. + ssam_notifier_unregister(ddev->ctrl, &ddev->notif);
  17804. +
  17805. + /* Stop mode_work, prevent access to mode_switch. */
  17806. + cancel_delayed_work_sync(&ddev->mode_work);
  17807. +
  17808. + /* Stop state_work. */
  17809. + cancel_delayed_work_sync(&ddev->state_work);
  17810. +
  17811. + /* With mode_work canceled, we can unregister the mode_switch. */
  17812. + input_unregister_device(ddev->mode_switch);
  17813. +
  17814. + /* Wake up async clients. */
  17815. + down_write(&ddev->client_lock);
  17816. + list_for_each_entry(client, &ddev->client_list, node) {
  17817. + kill_fasync(&client->fasync, SIGIO, POLL_HUP);
  17818. + }
  17819. + up_write(&ddev->client_lock);
  17820. +
  17821. + /* Wake up blocking clients. */
  17822. + wake_up_interruptible(&ddev->waitq);
  17823. +
  17824. + /*
  17825. + * Wait for clients to finish their current operation. After this, the
  17826. + * controller and device references are guaranteed to be no longer in
  17827. + * use.
  17828. + */
  17829. + down_write(&ddev->lock);
  17830. + ddev->dev = NULL;
  17831. + ddev->ctrl = NULL;
  17832. + up_write(&ddev->lock);
  17833. +
  17834. + /* Finally remove the misc-device. */
  17835. + misc_deregister(&ddev->mdev);
  17836. +
  17837. + /*
  17838. + * We're now guaranteed that sdtx_device_open() won't be called any
  17839. + * more, so we can now drop out reference.
  17840. + */
  17841. + sdtx_device_put(ddev);
  17842. +}
  17843. +
  17844. +
  17845. +/* -- PM ops. --------------------------------------------------------------- */
  17846. +
  17847. +#ifdef CONFIG_PM_SLEEP
  17848. +
  17849. +static void surface_dtx_pm_complete(struct device *dev)
  17850. +{
  17851. + struct sdtx_device *ddev = dev_get_drvdata(dev);
  17852. +
  17853. + /*
  17854. + * Normally, the EC will store events while suspended (i.e. in
  17855. + * display-off state) and release them when resumed (i.e. transitioned
  17856. + * to display-on state). During hibernation, however, the EC will be
  17857. + * shut down and does not store events. Furthermore, events might be
  17858. + * dropped during prolonged suspension (it is currently unknown how
  17859. + * big this event buffer is and how it behaves on overruns).
  17860. + *
  17861. + * To prevent any problems, we update the device state here. We do
  17862. + * this delayed to ensure that any events sent by the EC directly
  17863. + * after resuming will be handled first. The delay below has been
  17864. + * chosen (experimentally), so that there should be ample time for
  17865. + * these events to be handled, before we check and, if necessary,
  17866. + * update the state.
  17867. + */
  17868. + sdtx_update_device_state(ddev, msecs_to_jiffies(1000));
  17869. +}
  17870. +
  17871. +static const struct dev_pm_ops surface_dtx_pm_ops = {
  17872. + .complete = surface_dtx_pm_complete,
  17873. +};
  17874. +
  17875. +#else /* CONFIG_PM_SLEEP */
  17876. +
  17877. +static const struct dev_pm_ops surface_dtx_pm_ops = {};
  17878. +
  17879. +#endif /* CONFIG_PM_SLEEP */
  17880. +
  17881. +
  17882. +/* -- Platform driver. ------------------------------------------------------ */
  17883. +
  17884. +static int surface_dtx_platform_probe(struct platform_device *pdev)
  17885. +{
  17886. + struct ssam_controller *ctrl;
  17887. + struct sdtx_device *ddev;
  17888. +
  17889. + /* Link to EC. */
  17890. + ctrl = ssam_client_bind(&pdev->dev);
  17891. + if (IS_ERR(ctrl))
  17892. + return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl);
  17893. +
  17894. + ddev = sdtx_device_create(&pdev->dev, ctrl);
  17895. + if (IS_ERR(ddev))
  17896. + return PTR_ERR(ddev);
  17897. +
  17898. + platform_set_drvdata(pdev, ddev);
  17899. + return 0;
  17900. +}
  17901. +
  17902. +static int surface_dtx_platform_remove(struct platform_device *pdev)
  17903. +{
  17904. + sdtx_device_destroy(platform_get_drvdata(pdev));
  17905. + return 0;
  17906. +}
  17907. +
  17908. +static const struct acpi_device_id surface_dtx_acpi_match[] = {
  17909. + { "MSHW0133", 0 },
  17910. + { },
  17911. +};
  17912. +MODULE_DEVICE_TABLE(acpi, surface_dtx_acpi_match);
  17913. +
  17914. +static struct platform_driver surface_dtx_platform_driver = {
  17915. + .probe = surface_dtx_platform_probe,
  17916. + .remove = surface_dtx_platform_remove,
  17917. + .driver = {
  17918. + .name = "surface_dtx_pltf",
  17919. + .acpi_match_table = surface_dtx_acpi_match,
  17920. + .pm = &surface_dtx_pm_ops,
  17921. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  17922. + },
  17923. +};
  17924. +module_platform_driver(surface_dtx_platform_driver);
  17925. +
  17926. +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  17927. +MODULE_DESCRIPTION("Detachment-system driver for Surface System Aggregator Module");
  17928. +MODULE_LICENSE("GPL");
  17929. diff --git a/include/uapi/linux/surface_aggregator/dtx.h b/include/uapi/linux/surface_aggregator/dtx.h
  17930. new file mode 100644
  17931. index 000000000000..0833aab0d819
  17932. --- /dev/null
  17933. +++ b/include/uapi/linux/surface_aggregator/dtx.h
  17934. @@ -0,0 +1,146 @@
  17935. +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
  17936. +/*
  17937. + * Surface DTX (clipboard detachment system driver) user-space interface.
  17938. + *
  17939. + * Definitions, structs, and IOCTLs for the /dev/surface/dtx misc device. This
  17940. + * device allows user-space to control the clipboard detachment process on
  17941. + * Surface Book series devices.
  17942. + *
  17943. + * Copyright (C) 2020-2021 Maximilian Luz <luzmaximilian@gmail.com>
  17944. + */
  17945. +
  17946. +#ifndef _UAPI_LINUX_SURFACE_AGGREGATOR_DTX_H
  17947. +#define _UAPI_LINUX_SURFACE_AGGREGATOR_DTX_H
  17948. +
  17949. +#include <linux/ioctl.h>
  17950. +#include <linux/types.h>
  17951. +
  17952. +/* Status/error categories */
  17953. +#define SDTX_CATEGORY_STATUS 0x0000
  17954. +#define SDTX_CATEGORY_RUNTIME_ERROR 0x1000
  17955. +#define SDTX_CATEGORY_HARDWARE_ERROR 0x2000
  17956. +#define SDTX_CATEGORY_UNKNOWN 0xf000
  17957. +
  17958. +#define SDTX_CATEGORY_MASK 0xf000
  17959. +#define SDTX_CATEGORY(value) ((value) & SDTX_CATEGORY_MASK)
  17960. +
  17961. +#define SDTX_STATUS(code) ((code) | SDTX_CATEGORY_STATUS)
  17962. +#define SDTX_ERR_RT(code) ((code) | SDTX_CATEGORY_RUNTIME_ERROR)
  17963. +#define SDTX_ERR_HW(code) ((code) | SDTX_CATEGORY_HARDWARE_ERROR)
  17964. +#define SDTX_UNKNOWN(code) ((code) | SDTX_CATEGORY_UNKNOWN)
  17965. +
  17966. +#define SDTX_SUCCESS(value) (SDTX_CATEGORY(value) == SDTX_CATEGORY_STATUS)
  17967. +
  17968. +/* Latch status values */
  17969. +#define SDTX_LATCH_CLOSED SDTX_STATUS(0x00)
  17970. +#define SDTX_LATCH_OPENED SDTX_STATUS(0x01)
  17971. +
  17972. +/* Base state values */
  17973. +#define SDTX_BASE_DETACHED SDTX_STATUS(0x00)
  17974. +#define SDTX_BASE_ATTACHED SDTX_STATUS(0x01)
  17975. +
  17976. +/* Runtime errors (non-critical) */
  17977. +#define SDTX_DETACH_NOT_FEASIBLE SDTX_ERR_RT(0x01)
  17978. +#define SDTX_DETACH_TIMEDOUT SDTX_ERR_RT(0x02)
  17979. +
  17980. +/* Hardware errors (critical) */
  17981. +#define SDTX_ERR_FAILED_TO_OPEN SDTX_ERR_HW(0x01)
  17982. +#define SDTX_ERR_FAILED_TO_REMAIN_OPEN SDTX_ERR_HW(0x02)
  17983. +#define SDTX_ERR_FAILED_TO_CLOSE SDTX_ERR_HW(0x03)
  17984. +
  17985. +/* Base types */
  17986. +#define SDTX_DEVICE_TYPE_HID 0x0100
  17987. +#define SDTX_DEVICE_TYPE_SSH 0x0200
  17988. +
  17989. +#define SDTX_DEVICE_TYPE_MASK 0x0f00
  17990. +#define SDTX_DEVICE_TYPE(value) ((value) & SDTX_DEVICE_TYPE_MASK)
  17991. +
  17992. +#define SDTX_BASE_TYPE_HID(id) ((id) | SDTX_DEVICE_TYPE_HID)
  17993. +#define SDTX_BASE_TYPE_SSH(id) ((id) | SDTX_DEVICE_TYPE_SSH)
  17994. +
  17995. +/**
  17996. + * enum sdtx_device_mode - Mode describing how (and if) the clipboard is
  17997. + * attached to the base of the device.
  17998. + * @SDTX_DEVICE_MODE_TABLET: The clipboard is detached from the base and the
  17999. + * device operates as tablet.
  18000. + * @SDTX_DEVICE_MODE_LAPTOP: The clipboard is attached normally to the base
  18001. + * and the device operates as laptop.
  18002. + * @SDTX_DEVICE_MODE_STUDIO: The clipboard is attached to the base in reverse.
  18003. + * The device operates as tablet with keyboard and
  18004. + * touchpad deactivated, however, the base battery
  18005. + * and, if present in the specific device model, dGPU
  18006. + * are available to the system.
  18007. + */
  18008. +enum sdtx_device_mode {
  18009. + SDTX_DEVICE_MODE_TABLET = 0x00,
  18010. + SDTX_DEVICE_MODE_LAPTOP = 0x01,
  18011. + SDTX_DEVICE_MODE_STUDIO = 0x02,
  18012. +};
  18013. +
  18014. +/**
  18015. + * struct sdtx_event - Event provided by reading from the DTX device file.
  18016. + * @length: Length of the event payload, in bytes.
  18017. + * @code: Event code, detailing what type of event this is.
  18018. + * @data: Payload of the event, containing @length bytes.
  18019. + *
  18020. + * See &enum sdtx_event_code for currently valid event codes.
  18021. + */
  18022. +struct sdtx_event {
  18023. + __u16 length;
  18024. + __u16 code;
  18025. + __u8 data[];
  18026. +} __attribute__((__packed__));
  18027. +
  18028. +/**
  18029. + * enum sdtx_event_code - Code describing the type of an event.
  18030. + * @SDTX_EVENT_REQUEST: Detachment request event type.
  18031. + * @SDTX_EVENT_CANCEL: Cancel detachment process event type.
  18032. + * @SDTX_EVENT_BASE_CONNECTION: Base/clipboard connection change event type.
  18033. + * @SDTX_EVENT_LATCH_STATUS: Latch status change event type.
  18034. + * @SDTX_EVENT_DEVICE_MODE: Device mode change event type.
  18035. + *
  18036. + * Used in &struct sdtx_event to describe the type of the event. Further event
  18037. + * codes are reserved for future use. Any event parser should be able to
  18038. + * gracefully handle unknown events, i.e. by simply skipping them.
  18039. + *
  18040. + * Consult the DTX user-space interface documentation for details regarding
  18041. + * the individual event types.
  18042. + */
  18043. +enum sdtx_event_code {
  18044. + SDTX_EVENT_REQUEST = 1,
  18045. + SDTX_EVENT_CANCEL = 2,
  18046. + SDTX_EVENT_BASE_CONNECTION = 3,
  18047. + SDTX_EVENT_LATCH_STATUS = 4,
  18048. + SDTX_EVENT_DEVICE_MODE = 5,
  18049. +};
  18050. +
  18051. +/**
  18052. + * struct sdtx_base_info - Describes if and what type of base is connected.
  18053. + * @state: The state of the connection. Valid values are %SDTX_BASE_DETACHED,
  18054. + * %SDTX_BASE_ATTACHED, and %SDTX_DETACH_NOT_FEASIBLE (in case a base
  18055. + * is attached but low clipboard battery prevents detachment). Other
  18056. + * values are currently reserved.
  18057. + * @base_id: The type of base connected. Zero if no base is connected.
  18058. + */
  18059. +struct sdtx_base_info {
  18060. + __u16 state;
  18061. + __u16 base_id;
  18062. +} __attribute__((__packed__));
  18063. +
  18064. +/* IOCTLs */
  18065. +#define SDTX_IOCTL_EVENTS_ENABLE _IO(0xa5, 0x21)
  18066. +#define SDTX_IOCTL_EVENTS_DISABLE _IO(0xa5, 0x22)
  18067. +
  18068. +#define SDTX_IOCTL_LATCH_LOCK _IO(0xa5, 0x23)
  18069. +#define SDTX_IOCTL_LATCH_UNLOCK _IO(0xa5, 0x24)
  18070. +
  18071. +#define SDTX_IOCTL_LATCH_REQUEST _IO(0xa5, 0x25)
  18072. +#define SDTX_IOCTL_LATCH_CONFIRM _IO(0xa5, 0x26)
  18073. +#define SDTX_IOCTL_LATCH_HEARTBEAT _IO(0xa5, 0x27)
  18074. +#define SDTX_IOCTL_LATCH_CANCEL _IO(0xa5, 0x28)
  18075. +
  18076. +#define SDTX_IOCTL_GET_BASE_INFO _IOR(0xa5, 0x29, struct sdtx_base_info)
  18077. +#define SDTX_IOCTL_GET_DEVICE_MODE _IOR(0xa5, 0x2a, __u16)
  18078. +#define SDTX_IOCTL_GET_LATCH_STATUS _IOR(0xa5, 0x2b, __u16)
  18079. +
  18080. +#endif /* _UAPI_LINUX_SURFACE_AGGREGATOR_DTX_H */
  18081. --
  18082. 2.31.0
  18083. From fe26e240690665522af694f5a5a7a2985d0f236a Mon Sep 17 00:00:00 2001
  18084. From: Maximilian Luz <luzmaximilian@gmail.com>
  18085. Date: Tue, 9 Feb 2021 02:50:11 +0100
  18086. Subject: [PATCH] platform/surface: dtx: Add support for native SSAM devices
  18087. Add support for native SSAM devices to the DTX driver. This allows
  18088. support for the Surface Book 3, on which the DTX device is not present
  18089. in ACPI.
  18090. Patchset: surface-sam
  18091. ---
  18092. drivers/platform/surface/Kconfig | 4 ++
  18093. drivers/platform/surface/surface_dtx.c | 90 +++++++++++++++++++++++++-
  18094. 2 files changed, 93 insertions(+), 1 deletion(-)
  18095. diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig
  18096. index 745f9d2eb6a7..dea313989b4c 100644
  18097. --- a/drivers/platform/surface/Kconfig
  18098. +++ b/drivers/platform/surface/Kconfig
  18099. @@ -127,6 +127,10 @@ config SURFACE_DTX
  18100. behavior of this process, which includes the option to abort it in
  18101. case the base is still in use or speed it up in case it is not.
  18102. + Note that this module can be built without support for the Surface
  18103. + Aggregator Bus (i.e. CONFIG_SURFACE_AGGREGATOR_BUS=n). In that case,
  18104. + some devices, specifically the Surface Book 3, will not be supported.
  18105. +
  18106. config SURFACE_GPE
  18107. tristate "Surface GPE/Lid Support Driver"
  18108. depends on DMI
  18109. diff --git a/drivers/platform/surface/surface_dtx.c b/drivers/platform/surface/surface_dtx.c
  18110. index a95adc1094aa..4bb5d286bf95 100644
  18111. --- a/drivers/platform/surface/surface_dtx.c
  18112. +++ b/drivers/platform/surface/surface_dtx.c
  18113. @@ -27,6 +27,7 @@
  18114. #include <linux/workqueue.h>
  18115. #include <linux/surface_aggregator/controller.h>
  18116. +#include <linux/surface_aggregator/device.h>
  18117. #include <linux/surface_aggregator/dtx.h>
  18118. @@ -1194,7 +1195,94 @@ static struct platform_driver surface_dtx_platform_driver = {
  18119. .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  18120. },
  18121. };
  18122. -module_platform_driver(surface_dtx_platform_driver);
  18123. +
  18124. +
  18125. +/* -- SSAM device driver. --------------------------------------------------- */
  18126. +
  18127. +#ifdef CONFIG_SURFACE_AGGREGATOR_BUS
  18128. +
  18129. +static int surface_dtx_ssam_probe(struct ssam_device *sdev)
  18130. +{
  18131. + struct sdtx_device *ddev;
  18132. +
  18133. + ddev = sdtx_device_create(&sdev->dev, sdev->ctrl);
  18134. + if (IS_ERR(ddev))
  18135. + return PTR_ERR(ddev);
  18136. +
  18137. + ssam_device_set_drvdata(sdev, ddev);
  18138. + return 0;
  18139. +}
  18140. +
  18141. +static void surface_dtx_ssam_remove(struct ssam_device *sdev)
  18142. +{
  18143. + sdtx_device_destroy(ssam_device_get_drvdata(sdev));
  18144. +}
  18145. +
  18146. +static const struct ssam_device_id surface_dtx_ssam_match[] = {
  18147. + { SSAM_SDEV(BAS, 0x01, 0x00, 0x00) },
  18148. + { },
  18149. +};
  18150. +MODULE_DEVICE_TABLE(ssam, surface_dtx_ssam_match);
  18151. +
  18152. +static struct ssam_device_driver surface_dtx_ssam_driver = {
  18153. + .probe = surface_dtx_ssam_probe,
  18154. + .remove = surface_dtx_ssam_remove,
  18155. + .match_table = surface_dtx_ssam_match,
  18156. + .driver = {
  18157. + .name = "surface_dtx",
  18158. + .pm = &surface_dtx_pm_ops,
  18159. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  18160. + },
  18161. +};
  18162. +
  18163. +static int ssam_dtx_driver_register(void)
  18164. +{
  18165. + return ssam_device_driver_register(&surface_dtx_ssam_driver);
  18166. +}
  18167. +
  18168. +static void ssam_dtx_driver_unregister(void)
  18169. +{
  18170. + ssam_device_driver_unregister(&surface_dtx_ssam_driver);
  18171. +}
  18172. +
  18173. +#else /* CONFIG_SURFACE_AGGREGATOR_BUS */
  18174. +
  18175. +static int ssam_dtx_driver_register(void)
  18176. +{
  18177. + return 0;
  18178. +}
  18179. +
  18180. +static void ssam_dtx_driver_unregister(void)
  18181. +{
  18182. +}
  18183. +
  18184. +#endif /* CONFIG_SURFACE_AGGREGATOR_BUS */
  18185. +
  18186. +
  18187. +/* -- Module setup. --------------------------------------------------------- */
  18188. +
  18189. +static int __init surface_dtx_init(void)
  18190. +{
  18191. + int status;
  18192. +
  18193. + status = ssam_dtx_driver_register();
  18194. + if (status)
  18195. + return status;
  18196. +
  18197. + status = platform_driver_register(&surface_dtx_platform_driver);
  18198. + if (status)
  18199. + ssam_dtx_driver_unregister();
  18200. +
  18201. + return status;
  18202. +}
  18203. +module_init(surface_dtx_init);
  18204. +
  18205. +static void __exit surface_dtx_exit(void)
  18206. +{
  18207. + platform_driver_unregister(&surface_dtx_platform_driver);
  18208. + ssam_dtx_driver_unregister();
  18209. +}
  18210. +module_exit(surface_dtx_exit);
  18211. MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  18212. MODULE_DESCRIPTION("Detachment-system driver for Surface System Aggregator Module");
  18213. --
  18214. 2.31.0
  18215. From 5371ba2eedca09094db9dcf6b2b8c60159663543 Mon Sep 17 00:00:00 2001
  18216. From: Maximilian Luz <luzmaximilian@gmail.com>
  18217. Date: Tue, 9 Feb 2021 02:55:31 +0100
  18218. Subject: [PATCH] docs: driver-api: Add Surface DTX driver documentation
  18219. Add documentation for the user-space interface of the Surface DTX
  18220. (detachment system) driver, used on Microsoft Surface Book series
  18221. devices.
  18222. Patchset: surface-sam
  18223. ---
  18224. .../surface_aggregator/clients/dtx.rst | 718 ++++++++++++++++++
  18225. .../surface_aggregator/clients/index.rst | 1 +
  18226. MAINTAINERS | 1 +
  18227. 3 files changed, 720 insertions(+)
  18228. create mode 100644 Documentation/driver-api/surface_aggregator/clients/dtx.rst
  18229. diff --git a/Documentation/driver-api/surface_aggregator/clients/dtx.rst b/Documentation/driver-api/surface_aggregator/clients/dtx.rst
  18230. new file mode 100644
  18231. index 000000000000..e7e7c20007f0
  18232. --- /dev/null
  18233. +++ b/Documentation/driver-api/surface_aggregator/clients/dtx.rst
  18234. @@ -0,0 +1,718 @@
  18235. +.. SPDX-License-Identifier: GPL-2.0+
  18236. +
  18237. +.. |__u16| replace:: :c:type:`__u16 <__u16>`
  18238. +.. |sdtx_event| replace:: :c:type:`struct sdtx_event <sdtx_event>`
  18239. +.. |sdtx_event_code| replace:: :c:type:`enum sdtx_event_code <sdtx_event_code>`
  18240. +.. |sdtx_base_info| replace:: :c:type:`struct sdtx_base_info <sdtx_base_info>`
  18241. +.. |sdtx_device_mode| replace:: :c:type:`struct sdtx_device_mode <sdtx_device_mode>`
  18242. +
  18243. +======================================================
  18244. +User-Space DTX (Clipboard Detachment System) Interface
  18245. +======================================================
  18246. +
  18247. +The ``surface_dtx`` driver is responsible for proper clipboard detachment
  18248. +and re-attachment handling. To this end, it provides the ``/dev/surface/dtx``
  18249. +device file, through which it can interface with a user-space daemon. This
  18250. +daemon is then ultimately responsible for determining and taking necessary
  18251. +actions, such as unmounting devices attached to the base,
  18252. +unloading/reloading the graphics-driver, user-notifications, etc.
  18253. +
  18254. +There are two basic communication principles used in this driver: Commands
  18255. +(in other parts of the documentation also referred to as requests) and
  18256. +events. Commands are sent to the EC and may have a different implications in
  18257. +different contexts. Events are sent by the EC upon some internal state
  18258. +change. Commands are always driver-initiated, whereas events are always
  18259. +initiated by the EC.
  18260. +
  18261. +.. contents::
  18262. +
  18263. +Nomenclature
  18264. +============
  18265. +
  18266. +* **Clipboard:**
  18267. + The detachable upper part of the Surface Book, housing the screen and CPU.
  18268. +
  18269. +* **Base:**
  18270. + The lower part of the Surface Book from which the clipboard can be
  18271. + detached, optionally (model dependent) housing the discrete GPU (dGPU).
  18272. +
  18273. +* **Latch:**
  18274. + The mechanism keeping the clipboard attached to the base in normal
  18275. + operation and allowing it to be detached when requested.
  18276. +
  18277. +* **Silently ignored commands:**
  18278. + The command is accepted by the EC as a valid command and acknowledged
  18279. + (following the standard communication protocol), but the EC does not act
  18280. + upon it, i.e. ignores it.e upper part of the
  18281. +
  18282. +
  18283. +Detachment Process
  18284. +==================
  18285. +
  18286. +Warning: This part of the documentation is based on reverse engineering and
  18287. +testing and thus may contain errors or be incomplete.
  18288. +
  18289. +Latch States
  18290. +------------
  18291. +
  18292. +The latch mechanism has two major states: *open* and *closed*. In the
  18293. +*closed* state (default), the clipboard is secured to the base, whereas in
  18294. +the *open* state, the clipboard can be removed by a user.
  18295. +
  18296. +The latch can additionally be locked and, correspondingly, unlocked, which
  18297. +can influence the detachment procedure. Specifically, this locking mechanism
  18298. +is intended to prevent the dGPU, positioned in the base of the device, from
  18299. +being hot-unplugged while in use. More details can be found in the
  18300. +documentation for the detachment procedure below. By default, the latch is
  18301. +unlocked.
  18302. +
  18303. +Detachment Procedure
  18304. +--------------------
  18305. +
  18306. +Note that the detachment process is governed fully by the EC. The
  18307. +``surface_dtx`` driver only relays events from the EC to user-space and
  18308. +commands from user-space to the EC, i.e. it does not influence this process.
  18309. +
  18310. +The detachment process is started with the user pressing the *detach* button
  18311. +on the base of the device or executing the ``SDTX_IOCTL_LATCH_REQUEST`` IOCTL.
  18312. +Following that:
  18313. +
  18314. +1. The EC turns on the indicator led on the detach-button, sends a
  18315. + *detach-request* event (``SDTX_EVENT_REQUEST``), and awaits further
  18316. + instructions/commands. In case the latch is unlocked, the led will flash
  18317. + green. If the latch has been locked, the led will be solid red
  18318. +
  18319. +2. The event is, via the ``surface_dtx`` driver, relayed to user-space, where
  18320. + an appropriate user-space daemon can handle it and send instructions back
  18321. + to the EC via IOCTLs provided by this driver.
  18322. +
  18323. +3. The EC waits for instructions from user-space and acts according to them.
  18324. + If the EC does not receive any instructions in a given period, it will
  18325. + time out and continue as follows:
  18326. +
  18327. + - If the latch is unlocked, the EC will open the latch and the clipboard
  18328. + can be detached from the base. This is the exact behavior as without
  18329. + this driver or any user-space daemon. See the ``SDTX_IOCTL_LATCH_CONFIRM``
  18330. + description below for more details on the follow-up behavior of the EC.
  18331. +
  18332. + - If the latch is locked, the EC will *not* open the latch, meaning the
  18333. + clipboard cannot be detached from the base. Furthermore, the EC sends
  18334. + an cancel event (``SDTX_EVENT_CANCEL``) detailing this with the cancel
  18335. + reason ``SDTX_DETACH_TIMEDOUT`` (see :ref:`events` for details).
  18336. +
  18337. +Valid responses by a user-space daemon to a detachment request event are:
  18338. +
  18339. +- Execute ``SDTX_IOCTL_LATCH_REQUEST``. This will immediately abort the
  18340. + detachment process. Furthermore, the EC will send a detach-request event,
  18341. + similar to the user pressing the detach-button to cancel said process (see
  18342. + below).
  18343. +
  18344. +- Execute ``SDTX_IOCTL_LATCH_CONFIRM``. This will cause the EC to open the
  18345. + latch, after which the user can separate clipboard and base.
  18346. +
  18347. + As this changes the latch state, a *latch-status* event
  18348. + (``SDTX_EVENT_LATCH_STATUS``) will be sent once the latch has been opened
  18349. + successfully. If the EC fails to open the latch, e.g. due to hardware
  18350. + error or low battery, a latch-cancel event (``SDTX_EVENT_CANCEL``) will be
  18351. + sent with the cancel reason indicating the specific failure.
  18352. +
  18353. + If the latch is currently locked, the latch will automatically be
  18354. + unlocked before it is opened.
  18355. +
  18356. +- Execute ``SDTX_IOCTL_LATCH_HEARTBEAT``. This will reset the internal timeout.
  18357. + No other actions will be performed, i.e. the detachment process will neither
  18358. + be completed nor canceled, and the EC will still be waiting for further
  18359. + responses.
  18360. +
  18361. +- Execute ``SDTX_IOCTL_LATCH_CANCEL``. This will abort the detachment process,
  18362. + similar to ``SDTX_IOCTL_LATCH_REQUEST``, described above, or the button
  18363. + press, described below. A *generic request* event (``SDTX_EVENT_REQUEST``)
  18364. + is send in response to this. In contrast to those, however, this command
  18365. + does not trigger a new detachment process if none is currently in
  18366. + progress.
  18367. +
  18368. +- Do nothing. The detachment process eventually times out as described in
  18369. + point 3.
  18370. +
  18371. +See :ref:`ioctls` for more details on these responses.
  18372. +
  18373. +It is important to note that, if the user presses the detach button at any
  18374. +point when a detachment operation is in progress (i.e. after the EC has sent
  18375. +the initial *detach-request* event (``SDTX_EVENT_REQUEST``) and before it
  18376. +received the corresponding response concluding the process), the detachment
  18377. +process is canceled on the EC-level and an identical event is being sent.
  18378. +Thus a *detach-request* event, by itself, does not signal the start of the
  18379. +detachment process.
  18380. +
  18381. +The detachment process may further be canceled by the EC due to hardware
  18382. +failures or a low clipboard battery. This is done via a cancel event
  18383. +(``SDTX_EVENT_CANCEL``) with the corresponding cancel reason.
  18384. +
  18385. +
  18386. +User-Space Interface Documentation
  18387. +==================================
  18388. +
  18389. +Error Codes and Status Values
  18390. +-----------------------------
  18391. +
  18392. +Error and status codes are divided into different categories, which can be
  18393. +used to determine if the status code is an error, and, if it is, the
  18394. +severity and type of that error. The current categories are:
  18395. +
  18396. +.. flat-table:: Overview of Status/Error Categories.
  18397. + :widths: 2 1 3
  18398. + :header-rows: 1
  18399. +
  18400. + * - Name
  18401. + - Value
  18402. + - Short Description
  18403. +
  18404. + * - ``STATUS``
  18405. + - ``0x0000``
  18406. + - Non-error status codes.
  18407. +
  18408. + * - ``RUNTIME_ERROR``
  18409. + - ``0x1000``
  18410. + - Non-critical runtime errors.
  18411. +
  18412. + * - ``HARDWARE_ERROR``
  18413. + - ``0x2000``
  18414. + - Critical hardware failures.
  18415. +
  18416. + * - ``UNKNOWN``
  18417. + - ``0xF000``
  18418. + - Unknown error codes.
  18419. +
  18420. +Other categories are reserved for future use. The ``SDTX_CATEGORY()`` macro
  18421. +can be used to determine the category of any status value. The
  18422. +``SDTX_SUCCESS()`` macro can be used to check if the status value is a
  18423. +success value (``SDTX_CATEGORY_STATUS``) or if it indicates a failure.
  18424. +
  18425. +Unknown status or error codes sent by the EC are assigned to the ``UNKNOWN``
  18426. +category by the driver and may be implemented via their own code in the
  18427. +future.
  18428. +
  18429. +Currently used error codes are:
  18430. +
  18431. +.. flat-table:: Overview of Error Codes.
  18432. + :widths: 2 1 1 3
  18433. + :header-rows: 1
  18434. +
  18435. + * - Name
  18436. + - Category
  18437. + - Value
  18438. + - Short Description
  18439. +
  18440. + * - ``SDTX_DETACH_NOT_FEASIBLE``
  18441. + - ``RUNTIME``
  18442. + - ``0x1001``
  18443. + - Detachment not feasible due to low clipboard battery.
  18444. +
  18445. + * - ``SDTX_DETACH_TIMEDOUT``
  18446. + - ``RUNTIME``
  18447. + - ``0x1002``
  18448. + - Detachment process timed out while the latch was locked.
  18449. +
  18450. + * - ``SDTX_ERR_FAILED_TO_OPEN``
  18451. + - ``HARDWARE``
  18452. + - ``0x2001``
  18453. + - Failed to open latch.
  18454. +
  18455. + * - ``SDTX_ERR_FAILED_TO_REMAIN_OPEN``
  18456. + - ``HARDWARE``
  18457. + - ``0x2002``
  18458. + - Failed to keep latch open.
  18459. +
  18460. + * - ``SDTX_ERR_FAILED_TO_CLOSE``
  18461. + - ``HARDWARE``
  18462. + - ``0x2003``
  18463. + - Failed to close latch.
  18464. +
  18465. +Other error codes are reserved for future use. Non-error status codes may
  18466. +overlap and are generally only unique within their use-case:
  18467. +
  18468. +.. flat-table:: Latch Status Codes.
  18469. + :widths: 2 1 1 3
  18470. + :header-rows: 1
  18471. +
  18472. + * - Name
  18473. + - Category
  18474. + - Value
  18475. + - Short Description
  18476. +
  18477. + * - ``SDTX_LATCH_CLOSED``
  18478. + - ``STATUS``
  18479. + - ``0x0000``
  18480. + - Latch is closed/has been closed.
  18481. +
  18482. + * - ``SDTX_LATCH_OPENED``
  18483. + - ``STATUS``
  18484. + - ``0x0001``
  18485. + - Latch is open/has been opened.
  18486. +
  18487. +.. flat-table:: Base State Codes.
  18488. + :widths: 2 1 1 3
  18489. + :header-rows: 1
  18490. +
  18491. + * - Name
  18492. + - Category
  18493. + - Value
  18494. + - Short Description
  18495. +
  18496. + * - ``SDTX_BASE_DETACHED``
  18497. + - ``STATUS``
  18498. + - ``0x0000``
  18499. + - Base has been detached/is not present.
  18500. +
  18501. + * - ``SDTX_BASE_ATTACHED``
  18502. + - ``STATUS``
  18503. + - ``0x0001``
  18504. + - Base has been attached/is present.
  18505. +
  18506. +Again, other codes are reserved for future use.
  18507. +
  18508. +.. _events:
  18509. +
  18510. +Events
  18511. +------
  18512. +
  18513. +Events can be received by reading from the device file. They are disabled by
  18514. +default and have to be enabled by executing ``SDTX_IOCTL_EVENTS_ENABLE``
  18515. +first. All events follow the layout prescribed by |sdtx_event|. Specific
  18516. +event types can be identified by their event code, described in
  18517. +|sdtx_event_code|. Note that other event codes are reserved for future use,
  18518. +thus an event parser must be able to handle any unknown/unsupported event
  18519. +types gracefully, by relying on the payload length given in the event header.
  18520. +
  18521. +Currently provided event types are:
  18522. +
  18523. +.. flat-table:: Overview of DTX events.
  18524. + :widths: 2 1 1 3
  18525. + :header-rows: 1
  18526. +
  18527. + * - Name
  18528. + - Code
  18529. + - Payload
  18530. + - Short Description
  18531. +
  18532. + * - ``SDTX_EVENT_REQUEST``
  18533. + - ``1``
  18534. + - ``0`` bytes
  18535. + - Detachment process initiated/aborted.
  18536. +
  18537. + * - ``SDTX_EVENT_CANCEL``
  18538. + - ``2``
  18539. + - ``2`` bytes
  18540. + - EC canceled detachment process.
  18541. +
  18542. + * - ``SDTX_EVENT_BASE_CONNECTION``
  18543. + - ``3``
  18544. + - ``4`` bytes
  18545. + - Base connection state changed.
  18546. +
  18547. + * - ``SDTX_EVENT_LATCH_STATUS``
  18548. + - ``4``
  18549. + - ``2`` bytes
  18550. + - Latch status changed.
  18551. +
  18552. + * - ``SDTX_EVENT_DEVICE_MODE``
  18553. + - ``5``
  18554. + - ``2`` bytes
  18555. + - Device mode changed.
  18556. +
  18557. +Individual events in more detail:
  18558. +
  18559. +``SDTX_EVENT_REQUEST``
  18560. +^^^^^^^^^^^^^^^^^^^^^^
  18561. +
  18562. +Sent when a detachment process is started or, if in progress, aborted by the
  18563. +user, either via a detach button press or a detach request
  18564. +(``SDTX_IOCTL_LATCH_REQUEST``) being sent from user-space.
  18565. +
  18566. +Does not have any payload.
  18567. +
  18568. +``SDTX_EVENT_CANCEL``
  18569. +^^^^^^^^^^^^^^^^^^^^^
  18570. +
  18571. +Sent when a detachment process is canceled by the EC due to unfulfilled
  18572. +preconditions (e.g. clipboard battery too low to detach) or hardware
  18573. +failure. The reason for cancellation is given in the event payload detailed
  18574. +below and can be one of
  18575. +
  18576. +* ``SDTX_DETACH_TIMEDOUT``: Detachment timed out while the latch was locked.
  18577. + The latch has neither been opened nor unlocked.
  18578. +
  18579. +* ``SDTX_DETACH_NOT_FEASIBLE``: Detachment not feasible due to low clipboard
  18580. + battery.
  18581. +
  18582. +* ``SDTX_ERR_FAILED_TO_OPEN``: Could not open the latch (hardware failure).
  18583. +
  18584. +* ``SDTX_ERR_FAILED_TO_REMAIN_OPEN``: Could not keep the latch open (hardware
  18585. + failure).
  18586. +
  18587. +* ``SDTX_ERR_FAILED_TO_CLOSE``: Could not close the latch (hardware failure).
  18588. +
  18589. +Other error codes in this context are reserved for future use.
  18590. +
  18591. +These codes can be classified via the ``SDTX_CATEGORY()`` macro to discern
  18592. +between critical hardware errors (``SDTX_CATEGORY_HARDWARE_ERROR``) or
  18593. +runtime errors (``SDTX_CATEGORY_RUNTIME_ERROR``), the latter of which may
  18594. +happen during normal operation if certain preconditions for detachment are
  18595. +not given.
  18596. +
  18597. +.. flat-table:: Detachment Cancel Event Payload
  18598. + :widths: 1 1 4
  18599. + :header-rows: 1
  18600. +
  18601. + * - Field
  18602. + - Type
  18603. + - Description
  18604. +
  18605. + * - ``reason``
  18606. + - |__u16|
  18607. + - Reason for cancellation.
  18608. +
  18609. +``SDTX_EVENT_BASE_CONNECTION``
  18610. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  18611. +
  18612. +Sent when the base connection state has changed, i.e. when the base has been
  18613. +attached, detached, or detachment has become infeasible due to low clipboard
  18614. +battery. The new state and, if a base is connected, ID of the base is
  18615. +provided as payload of type |sdtx_base_info| with its layout presented
  18616. +below:
  18617. +
  18618. +.. flat-table:: Base-Connection-Change Event Payload
  18619. + :widths: 1 1 4
  18620. + :header-rows: 1
  18621. +
  18622. + * - Field
  18623. + - Type
  18624. + - Description
  18625. +
  18626. + * - ``state``
  18627. + - |__u16|
  18628. + - Base connection state.
  18629. +
  18630. + * - ``base_id``
  18631. + - |__u16|
  18632. + - Type of base connected (zero if none).
  18633. +
  18634. +Possible values for ``state`` are:
  18635. +
  18636. +* ``SDTX_BASE_DETACHED``,
  18637. +* ``SDTX_BASE_ATTACHED``, and
  18638. +* ``SDTX_DETACH_NOT_FEASIBLE``.
  18639. +
  18640. +Other values are reserved for future use.
  18641. +
  18642. +``SDTX_EVENT_LATCH_STATUS``
  18643. +^^^^^^^^^^^^^^^^^^^^^^^^^^^
  18644. +
  18645. +Sent when the latch status has changed, i.e. when the latch has been opened,
  18646. +closed, or an error occurred. The current status is provided as payload:
  18647. +
  18648. +.. flat-table:: Latch-Status-Change Event Payload
  18649. + :widths: 1 1 4
  18650. + :header-rows: 1
  18651. +
  18652. + * - Field
  18653. + - Type
  18654. + - Description
  18655. +
  18656. + * - ``status``
  18657. + - |__u16|
  18658. + - Latch status.
  18659. +
  18660. +Possible values for ``status`` are:
  18661. +
  18662. +* ``SDTX_LATCH_CLOSED``,
  18663. +* ``SDTX_LATCH_OPENED``,
  18664. +* ``SDTX_ERR_FAILED_TO_OPEN``,
  18665. +* ``SDTX_ERR_FAILED_TO_REMAIN_OPEN``, and
  18666. +* ``SDTX_ERR_FAILED_TO_CLOSE``.
  18667. +
  18668. +Other values are reserved for future use.
  18669. +
  18670. +``SDTX_EVENT_DEVICE_MODE``
  18671. +^^^^^^^^^^^^^^^^^^^^^^^^^^
  18672. +
  18673. +Sent when the device mode has changed. The new device mode is provided as
  18674. +payload:
  18675. +
  18676. +.. flat-table:: Device-Mode-Change Event Payload
  18677. + :widths: 1 1 4
  18678. + :header-rows: 1
  18679. +
  18680. + * - Field
  18681. + - Type
  18682. + - Description
  18683. +
  18684. + * - ``mode``
  18685. + - |__u16|
  18686. + - Device operation mode.
  18687. +
  18688. +Possible values for ``mode`` are:
  18689. +
  18690. +* ``SDTX_DEVICE_MODE_TABLET``,
  18691. +* ``SDTX_DEVICE_MODE_LAPTOP``, and
  18692. +* ``SDTX_DEVICE_MODE_STUDIO``.
  18693. +
  18694. +Other values are reserved for future use.
  18695. +
  18696. +.. _ioctls:
  18697. +
  18698. +IOCTLs
  18699. +------
  18700. +
  18701. +The following IOCTLs are provided:
  18702. +
  18703. +.. flat-table:: Overview of DTX IOCTLs
  18704. + :widths: 1 1 1 1 4
  18705. + :header-rows: 1
  18706. +
  18707. + * - Type
  18708. + - Number
  18709. + - Direction
  18710. + - Name
  18711. + - Description
  18712. +
  18713. + * - ``0xA5``
  18714. + - ``0x21``
  18715. + - ``-``
  18716. + - ``EVENTS_ENABLE``
  18717. + - Enable events for the current file descriptor.
  18718. +
  18719. + * - ``0xA5``
  18720. + - ``0x22``
  18721. + - ``-``
  18722. + - ``EVENTS_DISABLE``
  18723. + - Disable events for the current file descriptor.
  18724. +
  18725. + * - ``0xA5``
  18726. + - ``0x23``
  18727. + - ``-``
  18728. + - ``LATCH_LOCK``
  18729. + - Lock the latch.
  18730. +
  18731. + * - ``0xA5``
  18732. + - ``0x24``
  18733. + - ``-``
  18734. + - ``LATCH_UNLOCK``
  18735. + - Unlock the latch.
  18736. +
  18737. + * - ``0xA5``
  18738. + - ``0x25``
  18739. + - ``-``
  18740. + - ``LATCH_REQUEST``
  18741. + - Request clipboard detachment.
  18742. +
  18743. + * - ``0xA5``
  18744. + - ``0x26``
  18745. + - ``-``
  18746. + - ``LATCH_CONFIRM``
  18747. + - Confirm clipboard detachment request.
  18748. +
  18749. + * - ``0xA5``
  18750. + - ``0x27``
  18751. + - ``-``
  18752. + - ``LATCH_HEARTBEAT``
  18753. + - Send heartbeat signal to EC.
  18754. +
  18755. + * - ``0xA5``
  18756. + - ``0x28``
  18757. + - ``-``
  18758. + - ``LATCH_CANCEL``
  18759. + - Cancel detachment process.
  18760. +
  18761. + * - ``0xA5``
  18762. + - ``0x29``
  18763. + - ``R``
  18764. + - ``GET_BASE_INFO``
  18765. + - Get current base/connection information.
  18766. +
  18767. + * - ``0xA5``
  18768. + - ``0x2A``
  18769. + - ``R``
  18770. + - ``GET_DEVICE_MODE``
  18771. + - Get current device operation mode.
  18772. +
  18773. + * - ``0xA5``
  18774. + - ``0x2B``
  18775. + - ``R``
  18776. + - ``GET_LATCH_STATUS``
  18777. + - Get current device latch status.
  18778. +
  18779. +``SDTX_IOCTL_EVENTS_ENABLE``
  18780. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  18781. +
  18782. +Defined as ``_IO(0xA5, 0x22)``.
  18783. +
  18784. +Enable events for the current file descriptor. Events can be obtained by
  18785. +reading from the device, if enabled. Events are disabled by default.
  18786. +
  18787. +``SDTX_IOCTL_EVENTS_DISABLE``
  18788. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  18789. +
  18790. +Defined as ``_IO(0xA5, 0x22)``.
  18791. +
  18792. +Disable events for the current file descriptor. Events can be obtained by
  18793. +reading from the device, if enabled. Events are disabled by default.
  18794. +
  18795. +``SDTX_IOCTL_LATCH_LOCK``
  18796. +^^^^^^^^^^^^^^^^^^^^^^^^^
  18797. +
  18798. +Defined as ``_IO(0xA5, 0x23)``.
  18799. +
  18800. +Locks the latch, causing the detachment procedure to abort without opening
  18801. +the latch on timeout. The latch is unlocked by default. This command will be
  18802. +silently ignored if the latch is already locked.
  18803. +
  18804. +``SDTX_IOCTL_LATCH_UNLOCK``
  18805. +^^^^^^^^^^^^^^^^^^^^^^^^^^^
  18806. +
  18807. +Defined as ``_IO(0xA5, 0x24)``.
  18808. +
  18809. +Unlocks the latch, causing the detachment procedure to open the latch on
  18810. +timeout. The latch is unlocked by default. This command will not open the
  18811. +latch when sent during an ongoing detachment process. It will be silently
  18812. +ignored if the latch is already unlocked.
  18813. +
  18814. +``SDTX_IOCTL_LATCH_REQUEST``
  18815. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  18816. +
  18817. +Defined as ``_IO(0xA5, 0x25)``.
  18818. +
  18819. +Generic latch request. Behavior depends on the context: If no
  18820. +detachment-process is active, detachment is requested. Otherwise the
  18821. +currently active detachment-process will be aborted.
  18822. +
  18823. +If a detachment process is canceled by this operation, a generic detachment
  18824. +request event (``SDTX_EVENT_REQUEST``) will be sent.
  18825. +
  18826. +This essentially behaves the same as a detachment button press.
  18827. +
  18828. +``SDTX_IOCTL_LATCH_CONFIRM``
  18829. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  18830. +
  18831. +Defined as ``_IO(0xA5, 0x26)``.
  18832. +
  18833. +Acknowledges and confirms a latch request. If sent during an ongoing
  18834. +detachment process, this command causes the latch to be opened immediately.
  18835. +The latch will also be opened if it has been locked. In this case, the latch
  18836. +lock is reset to the unlocked state.
  18837. +
  18838. +This command will be silently ignored if there is currently no detachment
  18839. +procedure in progress.
  18840. +
  18841. +``SDTX_IOCTL_LATCH_HEARTBEAT``
  18842. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  18843. +
  18844. +Defined as ``_IO(0xA5, 0x27)``.
  18845. +
  18846. +Sends a heartbeat, essentially resetting the detachment timeout. This
  18847. +command can be used to keep the detachment process alive while work required
  18848. +for the detachment to succeed is still in progress.
  18849. +
  18850. +This command will be silently ignored if there is currently no detachment
  18851. +procedure in progress.
  18852. +
  18853. +``SDTX_IOCTL_LATCH_CANCEL``
  18854. +^^^^^^^^^^^^^^^^^^^^^^^^^^^
  18855. +
  18856. +Defined as ``_IO(0xA5, 0x28)``.
  18857. +
  18858. +Cancels detachment in progress (if any). If a detachment process is canceled
  18859. +by this operation, a generic detachment request event
  18860. +(``SDTX_EVENT_REQUEST``) will be sent.
  18861. +
  18862. +This command will be silently ignored if there is currently no detachment
  18863. +procedure in progress.
  18864. +
  18865. +``SDTX_IOCTL_GET_BASE_INFO``
  18866. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  18867. +
  18868. +Defined as ``_IOR(0xA5, 0x29, struct sdtx_base_info)``.
  18869. +
  18870. +Get the current base connection state (i.e. attached/detached) and the type
  18871. +of the base connected to the clipboard. This is command essentially provides
  18872. +a way to query the information provided by the base connection change event
  18873. +(``SDTX_EVENT_BASE_CONNECTION``).
  18874. +
  18875. +Possible values for ``struct sdtx_base_info.state`` are:
  18876. +
  18877. +* ``SDTX_BASE_DETACHED``,
  18878. +* ``SDTX_BASE_ATTACHED``, and
  18879. +* ``SDTX_DETACH_NOT_FEASIBLE``.
  18880. +
  18881. +Other values are reserved for future use.
  18882. +
  18883. +``SDTX_IOCTL_GET_DEVICE_MODE``
  18884. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  18885. +
  18886. +Defined as ``_IOR(0xA5, 0x2A, __u16)``.
  18887. +
  18888. +Returns the device operation mode, indicating if and how the base is
  18889. +attached to the clipboard. This is command essentially provides a way to
  18890. +query the information provided by the device mode change event
  18891. +(``SDTX_EVENT_DEVICE_MODE``).
  18892. +
  18893. +Returned values are:
  18894. +
  18895. +* ``SDTX_DEVICE_MODE_LAPTOP``
  18896. +* ``SDTX_DEVICE_MODE_TABLET``
  18897. +* ``SDTX_DEVICE_MODE_STUDIO``
  18898. +
  18899. +See |sdtx_device_mode| for details. Other values are reserved for future
  18900. +use.
  18901. +
  18902. +
  18903. +``SDTX_IOCTL_GET_LATCH_STATUS``
  18904. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  18905. +
  18906. +Defined as ``_IOR(0xA5, 0x2B, __u16)``.
  18907. +
  18908. +Get the current latch status or (presumably) the last error encountered when
  18909. +trying to open/close the latch. This is command essentially provides a way
  18910. +to query the information provided by the latch status change event
  18911. +(``SDTX_EVENT_LATCH_STATUS``).
  18912. +
  18913. +Returned values are:
  18914. +
  18915. +* ``SDTX_LATCH_CLOSED``,
  18916. +* ``SDTX_LATCH_OPENED``,
  18917. +* ``SDTX_ERR_FAILED_TO_OPEN``,
  18918. +* ``SDTX_ERR_FAILED_TO_REMAIN_OPEN``, and
  18919. +* ``SDTX_ERR_FAILED_TO_CLOSE``.
  18920. +
  18921. +Other values are reserved for future use.
  18922. +
  18923. +A Note on Base IDs
  18924. +------------------
  18925. +
  18926. +Base types/IDs provided via ``SDTX_EVENT_BASE_CONNECTION`` or
  18927. +``SDTX_IOCTL_GET_BASE_INFO`` are directly forwarded from the EC in the lower
  18928. +byte of the combined |__u16| value, with the driver storing the EC type from
  18929. +which this ID comes in the high byte (without this, base IDs over different
  18930. +types of ECs may be overlapping).
  18931. +
  18932. +The ``SDTX_DEVICE_TYPE()`` macro can be used to determine the EC device
  18933. +type. This can be one of
  18934. +
  18935. +* ``SDTX_DEVICE_TYPE_HID``, for Surface Aggregator Module over HID, and
  18936. +
  18937. +* ``SDTX_DEVICE_TYPE_SSH``, for Surface Aggregator Module over Surface Serial
  18938. + Hub.
  18939. +
  18940. +Note that currently only the ``SSH`` type EC is supported, however ``HID``
  18941. +type is reserved for future use.
  18942. +
  18943. +Structures and Enums
  18944. +--------------------
  18945. +
  18946. +.. kernel-doc:: include/uapi/linux/surface_aggregator/dtx.h
  18947. +
  18948. +API Users
  18949. +=========
  18950. +
  18951. +A user-space daemon utilizing this API can be found at
  18952. +https://github.com/linux-surface/surface-dtx-daemon.
  18953. diff --git a/Documentation/driver-api/surface_aggregator/clients/index.rst b/Documentation/driver-api/surface_aggregator/clients/index.rst
  18954. index 3ccabce23271..98ea9946b8a2 100644
  18955. --- a/Documentation/driver-api/surface_aggregator/clients/index.rst
  18956. +++ b/Documentation/driver-api/surface_aggregator/clients/index.rst
  18957. @@ -11,6 +11,7 @@ This is the documentation for client drivers themselves. Refer to
  18958. :maxdepth: 1
  18959. cdev
  18960. + dtx
  18961. san
  18962. .. only:: subproject and html
  18963. diff --git a/MAINTAINERS b/MAINTAINERS
  18964. index 1a60e353df38..a6a4f5afdfa8 100644
  18965. --- a/MAINTAINERS
  18966. +++ b/MAINTAINERS
  18967. @@ -11789,6 +11789,7 @@ MICROSOFT SURFACE DTX DRIVER
  18968. M: Maximilian Luz <luzmaximilian@gmail.com>
  18969. L: platform-driver-x86@vger.kernel.org
  18970. S: Maintained
  18971. +F: Documentation/driver-api/surface_aggregator/clients/dtx.rst
  18972. F: drivers/platform/surface/surface_dtx.c
  18973. F: include/uapi/linux/surface_aggregator/dtx.h
  18974. --
  18975. 2.31.0
  18976. From a6c935de36064d4dd03c11201ac1cf1013d26416 Mon Sep 17 00:00:00 2001
  18977. From: Maximilian Luz <luzmaximilian@gmail.com>
  18978. Date: Thu, 11 Feb 2021 20:02:57 +0100
  18979. Subject: [PATCH] input: Add bus ID for Surface Aggregator Module
  18980. Add a bus identifier for the Surface System Aggregator Module, which
  18981. connects various integrated HID devices on Microsoft Surface models via
  18982. a dedicated HID transport protocol.
  18983. Patchset: surface-sam
  18984. ---
  18985. include/uapi/linux/input.h | 1 +
  18986. 1 file changed, 1 insertion(+)
  18987. diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
  18988. index 9a61c28ed3ae..3e81ea3d7df2 100644
  18989. --- a/include/uapi/linux/input.h
  18990. +++ b/include/uapi/linux/input.h
  18991. @@ -271,6 +271,7 @@ struct input_mask {
  18992. #define BUS_RMI 0x1D
  18993. #define BUS_CEC 0x1E
  18994. #define BUS_INTEL_ISHTP 0x1F
  18995. +#define BUS_SURFACE_AGGREGATOR 0x20
  18996. /*
  18997. * MT_TOOL types
  18998. --
  18999. 2.31.0
  19000. From 67807eaaf15f2f6b96052861c98c8ba1d77a181d Mon Sep 17 00:00:00 2001
  19001. From: Maximilian Luz <luzmaximilian@gmail.com>
  19002. Date: Thu, 11 Feb 2021 20:08:50 +0100
  19003. Subject: [PATCH] HID: Add support for Surface Aggregator Module HID transport
  19004. Add a HID transport driver to support integrated HID devices on newer
  19005. Microsoft Surface models (specifically 7th-generation, i.e. Surface
  19006. Laptop 3, Surface Book 3, and later).
  19007. On those models, the internal keyboard and touchpad (as well as some
  19008. other HID devices with currently unknown function) are connected via the
  19009. generic HID subsystem (TC=0x15) of the Surface System Aggregator Module
  19010. (SSAM). This subsystem provides a generic HID transport layer, support
  19011. for which is implemented by this driver.
  19012. Patchset: surface-sam
  19013. ---
  19014. MAINTAINERS | 7 +
  19015. drivers/hid/Kconfig | 2 +
  19016. drivers/hid/Makefile | 2 +
  19017. drivers/hid/surface-hid/Kconfig | 28 +++
  19018. drivers/hid/surface-hid/Makefile | 6 +
  19019. drivers/hid/surface-hid/surface_hid.c | 256 +++++++++++++++++++
  19020. drivers/hid/surface-hid/surface_hid_core.c | 272 +++++++++++++++++++++
  19021. drivers/hid/surface-hid/surface_hid_core.h | 77 ++++++
  19022. 8 files changed, 650 insertions(+)
  19023. create mode 100644 drivers/hid/surface-hid/Kconfig
  19024. create mode 100644 drivers/hid/surface-hid/Makefile
  19025. create mode 100644 drivers/hid/surface-hid/surface_hid.c
  19026. create mode 100644 drivers/hid/surface-hid/surface_hid_core.c
  19027. create mode 100644 drivers/hid/surface-hid/surface_hid_core.h
  19028. diff --git a/MAINTAINERS b/MAINTAINERS
  19029. index a6a4f5afdfa8..2eac975aee50 100644
  19030. --- a/MAINTAINERS
  19031. +++ b/MAINTAINERS
  19032. @@ -11808,6 +11808,13 @@ S: Maintained
  19033. T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git
  19034. F: drivers/platform/surface/
  19035. +MICROSOFT SURFACE HID TRANSPORT DRIVER
  19036. +M: Maximilian Luz <luzmaximilian@gmail.com>
  19037. +L: linux-input@vger.kernel.org
  19038. +L: platform-driver-x86@vger.kernel.org
  19039. +S: Maintained
  19040. +F: drivers/hid/surface-hid/
  19041. +
  19042. MICROSOFT SURFACE PRO 3 BUTTON DRIVER
  19043. M: Chen Yu <yu.c.chen@intel.com>
  19044. L: platform-driver-x86@vger.kernel.org
  19045. diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
  19046. index 09fa75a2b289..e82474897919 100644
  19047. --- a/drivers/hid/Kconfig
  19048. +++ b/drivers/hid/Kconfig
  19049. @@ -1187,4 +1187,6 @@ source "drivers/hid/intel-ish-hid/Kconfig"
  19050. source "drivers/hid/amd-sfh-hid/Kconfig"
  19051. +source "drivers/hid/surface-hid/Kconfig"
  19052. +
  19053. endmenu
  19054. diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
  19055. index 014d21fe7dac..98d6b9f666ec 100644
  19056. --- a/drivers/hid/Makefile
  19057. +++ b/drivers/hid/Makefile
  19058. @@ -144,3 +144,5 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/
  19059. obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/
  19060. obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/
  19061. +
  19062. +obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/
  19063. diff --git a/drivers/hid/surface-hid/Kconfig b/drivers/hid/surface-hid/Kconfig
  19064. new file mode 100644
  19065. index 000000000000..642c7f0e64fe
  19066. --- /dev/null
  19067. +++ b/drivers/hid/surface-hid/Kconfig
  19068. @@ -0,0 +1,28 @@
  19069. +# SPDX-License-Identifier: GPL-2.0+
  19070. +menu "Surface System Aggregator Module HID support"
  19071. + depends on SURFACE_AGGREGATOR
  19072. + depends on INPUT
  19073. +
  19074. +config SURFACE_HID
  19075. + tristate "HID transport driver for Surface System Aggregator Module"
  19076. + depends on SURFACE_AGGREGATOR_REGISTRY
  19077. + select SURFACE_HID_CORE
  19078. + help
  19079. + Driver to support integrated HID devices on newer Microsoft Surface
  19080. + models.
  19081. +
  19082. + This driver provides support for the HID transport protocol provided
  19083. + by the Surface Aggregator Module (i.e. the embedded controller) on
  19084. + 7th-generation Microsoft Surface devices, i.e. Surface Book 3 and
  19085. + Surface Laptop 3. On those models, it is mainly used to connect the
  19086. + integrated touchpad and keyboard.
  19087. +
  19088. + Say M or Y here, if you want support for integrated HID devices, i.e.
  19089. + integrated touchpad and keyboard, on 7th generation Microsoft Surface
  19090. + models.
  19091. +
  19092. +endmenu
  19093. +
  19094. +config SURFACE_HID_CORE
  19095. + tristate
  19096. + select HID
  19097. diff --git a/drivers/hid/surface-hid/Makefile b/drivers/hid/surface-hid/Makefile
  19098. new file mode 100644
  19099. index 000000000000..62fc04632d3d
  19100. --- /dev/null
  19101. +++ b/drivers/hid/surface-hid/Makefile
  19102. @@ -0,0 +1,6 @@
  19103. +# SPDX-License-Identifier: GPL-2.0+
  19104. +#
  19105. +# Makefile - Surface System Aggregator Module (SSAM) HID transport driver.
  19106. +#
  19107. +obj-$(CONFIG_SURFACE_HID_CORE) += surface_hid_core.o
  19108. +obj-$(CONFIG_SURFACE_HID) += surface_hid.o
  19109. diff --git a/drivers/hid/surface-hid/surface_hid.c b/drivers/hid/surface-hid/surface_hid.c
  19110. new file mode 100644
  19111. index 000000000000..e4477c328536
  19112. --- /dev/null
  19113. +++ b/drivers/hid/surface-hid/surface_hid.c
  19114. @@ -0,0 +1,256 @@
  19115. +// SPDX-License-Identifier: GPL-2.0+
  19116. +/*
  19117. + * Surface System Aggregator Module (SSAM) HID transport driver for the
  19118. + * generic HID interface (HID/TC=0x15 subsystem). Provides support for
  19119. + * integrated HID devices on Surface Laptop 3, Book 3, and later.
  19120. + *
  19121. + * Copyright (C) 2019-2021 Blaž Hrastnik <blaz@mxxn.io>,
  19122. + * Maximilian Luz <luzmaximilian@gmail.com>
  19123. + */
  19124. +
  19125. +#include <asm/unaligned.h>
  19126. +#include <linux/hid.h>
  19127. +#include <linux/kernel.h>
  19128. +#include <linux/module.h>
  19129. +#include <linux/types.h>
  19130. +
  19131. +#include <linux/surface_aggregator/controller.h>
  19132. +#include <linux/surface_aggregator/device.h>
  19133. +
  19134. +#include "surface_hid_core.h"
  19135. +
  19136. +
  19137. +/* -- SAM interface. -------------------------------------------------------- */
  19138. +
  19139. +struct surface_hid_buffer_slice {
  19140. + __u8 entry;
  19141. + __le32 offset;
  19142. + __le32 length;
  19143. + __u8 end;
  19144. + __u8 data[];
  19145. +} __packed;
  19146. +
  19147. +static_assert(sizeof(struct surface_hid_buffer_slice) == 10);
  19148. +
  19149. +enum surface_hid_cid {
  19150. + SURFACE_HID_CID_OUTPUT_REPORT = 0x01,
  19151. + SURFACE_HID_CID_GET_FEATURE_REPORT = 0x02,
  19152. + SURFACE_HID_CID_SET_FEATURE_REPORT = 0x03,
  19153. + SURFACE_HID_CID_GET_DESCRIPTOR = 0x04,
  19154. +};
  19155. +
  19156. +static int ssam_hid_get_descriptor(struct surface_hid_device *shid, u8 entry, u8 *buf, size_t len)
  19157. +{
  19158. + u8 buffer[sizeof(struct surface_hid_buffer_slice) + 0x76];
  19159. + struct surface_hid_buffer_slice *slice;
  19160. + struct ssam_request rqst;
  19161. + struct ssam_response rsp;
  19162. + u32 buffer_len, offset, length;
  19163. + int status;
  19164. +
  19165. + /*
  19166. + * Note: The 0x76 above has been chosen because that's what's used by
  19167. + * the Windows driver. Together with the header, this leads to a 128
  19168. + * byte payload in total.
  19169. + */
  19170. +
  19171. + buffer_len = ARRAY_SIZE(buffer) - sizeof(struct surface_hid_buffer_slice);
  19172. +
  19173. + rqst.target_category = shid->uid.category;
  19174. + rqst.target_id = shid->uid.target;
  19175. + rqst.command_id = SURFACE_HID_CID_GET_DESCRIPTOR;
  19176. + rqst.instance_id = shid->uid.instance;
  19177. + rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
  19178. + rqst.length = sizeof(struct surface_hid_buffer_slice);
  19179. + rqst.payload = buffer;
  19180. +
  19181. + rsp.capacity = ARRAY_SIZE(buffer);
  19182. + rsp.pointer = buffer;
  19183. +
  19184. + slice = (struct surface_hid_buffer_slice *)buffer;
  19185. + slice->entry = entry;
  19186. + slice->end = 0;
  19187. +
  19188. + offset = 0;
  19189. + length = buffer_len;
  19190. +
  19191. + while (!slice->end && offset < len) {
  19192. + put_unaligned_le32(offset, &slice->offset);
  19193. + put_unaligned_le32(length, &slice->length);
  19194. +
  19195. + rsp.length = 0;
  19196. +
  19197. + status = ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp,
  19198. + sizeof(*slice));
  19199. + if (status)
  19200. + return status;
  19201. +
  19202. + offset = get_unaligned_le32(&slice->offset);
  19203. + length = get_unaligned_le32(&slice->length);
  19204. +
  19205. + /* Don't mess stuff up in case we receive garbage. */
  19206. + if (length > buffer_len || offset > len)
  19207. + return -EPROTO;
  19208. +
  19209. + if (offset + length > len)
  19210. + length = len - offset;
  19211. +
  19212. + memcpy(buf + offset, &slice->data[0], length);
  19213. +
  19214. + offset += length;
  19215. + length = buffer_len;
  19216. + }
  19217. +
  19218. + if (offset != len) {
  19219. + dev_err(shid->dev, "unexpected descriptor length: got %u, expected %zu\n",
  19220. + offset, len);
  19221. + return -EPROTO;
  19222. + }
  19223. +
  19224. + return 0;
  19225. +}
  19226. +
  19227. +static int ssam_hid_set_raw_report(struct surface_hid_device *shid, u8 rprt_id, bool feature,
  19228. + u8 *buf, size_t len)
  19229. +{
  19230. + struct ssam_request rqst;
  19231. + u8 cid;
  19232. +
  19233. + if (feature)
  19234. + cid = SURFACE_HID_CID_SET_FEATURE_REPORT;
  19235. + else
  19236. + cid = SURFACE_HID_CID_OUTPUT_REPORT;
  19237. +
  19238. + rqst.target_category = shid->uid.category;
  19239. + rqst.target_id = shid->uid.target;
  19240. + rqst.instance_id = shid->uid.instance;
  19241. + rqst.command_id = cid;
  19242. + rqst.flags = 0;
  19243. + rqst.length = len;
  19244. + rqst.payload = buf;
  19245. +
  19246. + buf[0] = rprt_id;
  19247. +
  19248. + return ssam_retry(ssam_request_sync, shid->ctrl, &rqst, NULL);
  19249. +}
  19250. +
  19251. +static int ssam_hid_get_raw_report(struct surface_hid_device *shid, u8 rprt_id, u8 *buf, size_t len)
  19252. +{
  19253. + struct ssam_request rqst;
  19254. + struct ssam_response rsp;
  19255. +
  19256. + rqst.target_category = shid->uid.category;
  19257. + rqst.target_id = shid->uid.target;
  19258. + rqst.instance_id = shid->uid.instance;
  19259. + rqst.command_id = SURFACE_HID_CID_GET_FEATURE_REPORT;
  19260. + rqst.flags = 0;
  19261. + rqst.length = sizeof(rprt_id);
  19262. + rqst.payload = &rprt_id;
  19263. +
  19264. + rsp.capacity = len;
  19265. + rsp.length = 0;
  19266. + rsp.pointer = buf;
  19267. +
  19268. + return ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(rprt_id));
  19269. +}
  19270. +
  19271. +static u32 ssam_hid_event_fn(struct ssam_event_notifier *nf, const struct ssam_event *event)
  19272. +{
  19273. + struct surface_hid_device *shid = container_of(nf, struct surface_hid_device, notif);
  19274. + int status;
  19275. +
  19276. + if (event->command_id != 0x00)
  19277. + return 0;
  19278. +
  19279. + status = hid_input_report(shid->hid, HID_INPUT_REPORT, (u8 *)&event->data[0],
  19280. + event->length, 0);
  19281. +
  19282. + return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED;
  19283. +}
  19284. +
  19285. +
  19286. +/* -- Transport driver. ----------------------------------------------------- */
  19287. +
  19288. +static int shid_output_report(struct surface_hid_device *shid, u8 rprt_id, u8 *buf, size_t len)
  19289. +{
  19290. + int status;
  19291. +
  19292. + status = ssam_hid_set_raw_report(shid, rprt_id, false, buf, len);
  19293. + return status >= 0 ? len : status;
  19294. +}
  19295. +
  19296. +static int shid_get_feature_report(struct surface_hid_device *shid, u8 rprt_id, u8 *buf, size_t len)
  19297. +{
  19298. + int status;
  19299. +
  19300. + status = ssam_hid_get_raw_report(shid, rprt_id, buf, len);
  19301. + return status >= 0 ? len : status;
  19302. +}
  19303. +
  19304. +static int shid_set_feature_report(struct surface_hid_device *shid, u8 rprt_id, u8 *buf, size_t len)
  19305. +{
  19306. + int status;
  19307. +
  19308. + status = ssam_hid_set_raw_report(shid, rprt_id, true, buf, len);
  19309. + return status >= 0 ? len : status;
  19310. +}
  19311. +
  19312. +
  19313. +/* -- Driver setup. --------------------------------------------------------- */
  19314. +
  19315. +static int surface_hid_probe(struct ssam_device *sdev)
  19316. +{
  19317. + struct surface_hid_device *shid;
  19318. +
  19319. + shid = devm_kzalloc(&sdev->dev, sizeof(*shid), GFP_KERNEL);
  19320. + if (!shid)
  19321. + return -ENOMEM;
  19322. +
  19323. + shid->dev = &sdev->dev;
  19324. + shid->ctrl = sdev->ctrl;
  19325. + shid->uid = sdev->uid;
  19326. +
  19327. + shid->notif.base.priority = 1;
  19328. + shid->notif.base.fn = ssam_hid_event_fn;
  19329. + shid->notif.event.reg = SSAM_EVENT_REGISTRY_REG;
  19330. + shid->notif.event.id.target_category = sdev->uid.category;
  19331. + shid->notif.event.id.instance = sdev->uid.instance;
  19332. + shid->notif.event.mask = SSAM_EVENT_MASK_STRICT;
  19333. + shid->notif.event.flags = 0;
  19334. +
  19335. + shid->ops.get_descriptor = ssam_hid_get_descriptor;
  19336. + shid->ops.output_report = shid_output_report;
  19337. + shid->ops.get_feature_report = shid_get_feature_report;
  19338. + shid->ops.set_feature_report = shid_set_feature_report;
  19339. +
  19340. + ssam_device_set_drvdata(sdev, shid);
  19341. + return surface_hid_device_add(shid);
  19342. +}
  19343. +
  19344. +static void surface_hid_remove(struct ssam_device *sdev)
  19345. +{
  19346. + surface_hid_device_destroy(ssam_device_get_drvdata(sdev));
  19347. +}
  19348. +
  19349. +static const struct ssam_device_id surface_hid_match[] = {
  19350. + { SSAM_SDEV(HID, 0x02, SSAM_ANY_IID, 0x00) },
  19351. + { },
  19352. +};
  19353. +MODULE_DEVICE_TABLE(ssam, surface_hid_match);
  19354. +
  19355. +static struct ssam_device_driver surface_hid_driver = {
  19356. + .probe = surface_hid_probe,
  19357. + .remove = surface_hid_remove,
  19358. + .match_table = surface_hid_match,
  19359. + .driver = {
  19360. + .name = "surface_hid",
  19361. + .pm = &surface_hid_pm_ops,
  19362. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  19363. + },
  19364. +};
  19365. +module_ssam_device_driver(surface_hid_driver);
  19366. +
  19367. +MODULE_AUTHOR("Blaž Hrastnik <blaz@mxxn.io>");
  19368. +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  19369. +MODULE_DESCRIPTION("HID transport driver for Surface System Aggregator Module");
  19370. +MODULE_LICENSE("GPL");
  19371. diff --git a/drivers/hid/surface-hid/surface_hid_core.c b/drivers/hid/surface-hid/surface_hid_core.c
  19372. new file mode 100644
  19373. index 000000000000..2cadb8013529
  19374. --- /dev/null
  19375. +++ b/drivers/hid/surface-hid/surface_hid_core.c
  19376. @@ -0,0 +1,272 @@
  19377. +// SPDX-License-Identifier: GPL-2.0+
  19378. +/*
  19379. + * Common/core components for the Surface System Aggregator Module (SSAM) HID
  19380. + * transport driver. Provides support for integrated HID devices on Microsoft
  19381. + * Surface models.
  19382. + *
  19383. + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
  19384. + */
  19385. +
  19386. +#include <asm/unaligned.h>
  19387. +#include <linux/hid.h>
  19388. +#include <linux/kernel.h>
  19389. +#include <linux/module.h>
  19390. +#include <linux/types.h>
  19391. +#include <linux/usb/ch9.h>
  19392. +
  19393. +#include <linux/surface_aggregator/controller.h>
  19394. +
  19395. +#include "surface_hid_core.h"
  19396. +
  19397. +
  19398. +/* -- Device descriptor access. --------------------------------------------- */
  19399. +
  19400. +static int surface_hid_load_hid_descriptor(struct surface_hid_device *shid)
  19401. +{
  19402. + int status;
  19403. +
  19404. + status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_HID,
  19405. + (u8 *)&shid->hid_desc, sizeof(shid->hid_desc));
  19406. + if (status)
  19407. + return status;
  19408. +
  19409. + if (shid->hid_desc.desc_len != sizeof(shid->hid_desc)) {
  19410. + dev_err(shid->dev, "unexpected HID descriptor length: got %u, expected %zu\n",
  19411. + shid->hid_desc.desc_len, sizeof(shid->hid_desc));
  19412. + return -EPROTO;
  19413. + }
  19414. +
  19415. + if (shid->hid_desc.desc_type != HID_DT_HID) {
  19416. + dev_err(shid->dev, "unexpected HID descriptor type: got %#04x, expected %#04x\n",
  19417. + shid->hid_desc.desc_type, HID_DT_HID);
  19418. + return -EPROTO;
  19419. + }
  19420. +
  19421. + if (shid->hid_desc.num_descriptors != 1) {
  19422. + dev_err(shid->dev, "unexpected number of descriptors: got %u, expected 1\n",
  19423. + shid->hid_desc.num_descriptors);
  19424. + return -EPROTO;
  19425. + }
  19426. +
  19427. + if (shid->hid_desc.report_desc_type != HID_DT_REPORT) {
  19428. + dev_err(shid->dev, "unexpected report descriptor type: got %#04x, expected %#04x\n",
  19429. + shid->hid_desc.report_desc_type, HID_DT_REPORT);
  19430. + return -EPROTO;
  19431. + }
  19432. +
  19433. + return 0;
  19434. +}
  19435. +
  19436. +static int surface_hid_load_device_attributes(struct surface_hid_device *shid)
  19437. +{
  19438. + int status;
  19439. +
  19440. + status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_ATTRS,
  19441. + (u8 *)&shid->attrs, sizeof(shid->attrs));
  19442. + if (status)
  19443. + return status;
  19444. +
  19445. + if (get_unaligned_le32(&shid->attrs.length) != sizeof(shid->attrs)) {
  19446. + dev_err(shid->dev, "unexpected attribute length: got %u, expected %zu\n",
  19447. + get_unaligned_le32(&shid->attrs.length), sizeof(shid->attrs));
  19448. + return -EPROTO;
  19449. + }
  19450. +
  19451. + return 0;
  19452. +}
  19453. +
  19454. +
  19455. +/* -- Transport driver (common). -------------------------------------------- */
  19456. +
  19457. +static int surface_hid_start(struct hid_device *hid)
  19458. +{
  19459. + struct surface_hid_device *shid = hid->driver_data;
  19460. +
  19461. + return ssam_notifier_register(shid->ctrl, &shid->notif);
  19462. +}
  19463. +
  19464. +static void surface_hid_stop(struct hid_device *hid)
  19465. +{
  19466. + struct surface_hid_device *shid = hid->driver_data;
  19467. +
  19468. + /* Note: This call will log errors for us, so ignore them here. */
  19469. + ssam_notifier_unregister(shid->ctrl, &shid->notif);
  19470. +}
  19471. +
  19472. +static int surface_hid_open(struct hid_device *hid)
  19473. +{
  19474. + return 0;
  19475. +}
  19476. +
  19477. +static void surface_hid_close(struct hid_device *hid)
  19478. +{
  19479. +}
  19480. +
  19481. +static int surface_hid_parse(struct hid_device *hid)
  19482. +{
  19483. + struct surface_hid_device *shid = hid->driver_data;
  19484. + size_t len = get_unaligned_le16(&shid->hid_desc.report_desc_len);
  19485. + u8 *buf;
  19486. + int status;
  19487. +
  19488. + buf = kzalloc(len, GFP_KERNEL);
  19489. + if (!buf)
  19490. + return -ENOMEM;
  19491. +
  19492. + status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_REPORT, buf, len);
  19493. + if (!status)
  19494. + status = hid_parse_report(hid, buf, len);
  19495. +
  19496. + kfree(buf);
  19497. + return status;
  19498. +}
  19499. +
  19500. +static int surface_hid_raw_request(struct hid_device *hid, unsigned char reportnum, u8 *buf,
  19501. + size_t len, unsigned char rtype, int reqtype)
  19502. +{
  19503. + struct surface_hid_device *shid = hid->driver_data;
  19504. +
  19505. + if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT)
  19506. + return shid->ops.output_report(shid, reportnum, buf, len);
  19507. +
  19508. + else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT)
  19509. + return shid->ops.get_feature_report(shid, reportnum, buf, len);
  19510. +
  19511. + else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT)
  19512. + return shid->ops.set_feature_report(shid, reportnum, buf, len);
  19513. +
  19514. + return -EIO;
  19515. +}
  19516. +
  19517. +static struct hid_ll_driver surface_hid_ll_driver = {
  19518. + .start = surface_hid_start,
  19519. + .stop = surface_hid_stop,
  19520. + .open = surface_hid_open,
  19521. + .close = surface_hid_close,
  19522. + .parse = surface_hid_parse,
  19523. + .raw_request = surface_hid_raw_request,
  19524. +};
  19525. +
  19526. +
  19527. +/* -- Common device setup. -------------------------------------------------- */
  19528. +
  19529. +int surface_hid_device_add(struct surface_hid_device *shid)
  19530. +{
  19531. + int status;
  19532. +
  19533. + status = surface_hid_load_hid_descriptor(shid);
  19534. + if (status)
  19535. + return status;
  19536. +
  19537. + status = surface_hid_load_device_attributes(shid);
  19538. + if (status)
  19539. + return status;
  19540. +
  19541. + shid->hid = hid_allocate_device();
  19542. + if (IS_ERR(shid->hid))
  19543. + return PTR_ERR(shid->hid);
  19544. +
  19545. + shid->hid->dev.parent = shid->dev;
  19546. + shid->hid->bus = BUS_SURFACE_AGGREGATOR;
  19547. + shid->hid->vendor = cpu_to_le16(shid->attrs.vendor);
  19548. + shid->hid->product = cpu_to_le16(shid->attrs.product);
  19549. + shid->hid->version = cpu_to_le16(shid->hid_desc.hid_version);
  19550. + shid->hid->country = shid->hid_desc.country_code;
  19551. +
  19552. + snprintf(shid->hid->name, sizeof(shid->hid->name), "Microsoft Surface %04X:%04X",
  19553. + shid->hid->vendor, shid->hid->product);
  19554. +
  19555. + strscpy(shid->hid->phys, dev_name(shid->dev), sizeof(shid->hid->phys));
  19556. +
  19557. + shid->hid->driver_data = shid;
  19558. + shid->hid->ll_driver = &surface_hid_ll_driver;
  19559. +
  19560. + status = hid_add_device(shid->hid);
  19561. + if (status)
  19562. + hid_destroy_device(shid->hid);
  19563. +
  19564. + return status;
  19565. +}
  19566. +EXPORT_SYMBOL_GPL(surface_hid_device_add);
  19567. +
  19568. +void surface_hid_device_destroy(struct surface_hid_device *shid)
  19569. +{
  19570. + hid_destroy_device(shid->hid);
  19571. +}
  19572. +EXPORT_SYMBOL_GPL(surface_hid_device_destroy);
  19573. +
  19574. +
  19575. +/* -- PM ops. --------------------------------------------------------------- */
  19576. +
  19577. +#ifdef CONFIG_PM_SLEEP
  19578. +
  19579. +static int surface_hid_suspend(struct device *dev)
  19580. +{
  19581. + struct surface_hid_device *d = dev_get_drvdata(dev);
  19582. +
  19583. + if (d->hid->driver && d->hid->driver->suspend)
  19584. + return d->hid->driver->suspend(d->hid, PMSG_SUSPEND);
  19585. +
  19586. + return 0;
  19587. +}
  19588. +
  19589. +static int surface_hid_resume(struct device *dev)
  19590. +{
  19591. + struct surface_hid_device *d = dev_get_drvdata(dev);
  19592. +
  19593. + if (d->hid->driver && d->hid->driver->resume)
  19594. + return d->hid->driver->resume(d->hid);
  19595. +
  19596. + return 0;
  19597. +}
  19598. +
  19599. +static int surface_hid_freeze(struct device *dev)
  19600. +{
  19601. + struct surface_hid_device *d = dev_get_drvdata(dev);
  19602. +
  19603. + if (d->hid->driver && d->hid->driver->suspend)
  19604. + return d->hid->driver->suspend(d->hid, PMSG_FREEZE);
  19605. +
  19606. + return 0;
  19607. +}
  19608. +
  19609. +static int surface_hid_poweroff(struct device *dev)
  19610. +{
  19611. + struct surface_hid_device *d = dev_get_drvdata(dev);
  19612. +
  19613. + if (d->hid->driver && d->hid->driver->suspend)
  19614. + return d->hid->driver->suspend(d->hid, PMSG_HIBERNATE);
  19615. +
  19616. + return 0;
  19617. +}
  19618. +
  19619. +static int surface_hid_restore(struct device *dev)
  19620. +{
  19621. + struct surface_hid_device *d = dev_get_drvdata(dev);
  19622. +
  19623. + if (d->hid->driver && d->hid->driver->reset_resume)
  19624. + return d->hid->driver->reset_resume(d->hid);
  19625. +
  19626. + return 0;
  19627. +}
  19628. +
  19629. +const struct dev_pm_ops surface_hid_pm_ops = {
  19630. + .freeze = surface_hid_freeze,
  19631. + .thaw = surface_hid_resume,
  19632. + .suspend = surface_hid_suspend,
  19633. + .resume = surface_hid_resume,
  19634. + .poweroff = surface_hid_poweroff,
  19635. + .restore = surface_hid_restore,
  19636. +};
  19637. +EXPORT_SYMBOL_GPL(surface_hid_pm_ops);
  19638. +
  19639. +#else /* CONFIG_PM_SLEEP */
  19640. +
  19641. +const struct dev_pm_ops surface_hid_pm_ops = { };
  19642. +EXPORT_SYMBOL_GPL(surface_hid_pm_ops);
  19643. +
  19644. +#endif /* CONFIG_PM_SLEEP */
  19645. +
  19646. +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  19647. +MODULE_DESCRIPTION("HID transport driver core for Surface System Aggregator Module");
  19648. +MODULE_LICENSE("GPL");
  19649. diff --git a/drivers/hid/surface-hid/surface_hid_core.h b/drivers/hid/surface-hid/surface_hid_core.h
  19650. new file mode 100644
  19651. index 000000000000..4b1a7b57e035
  19652. --- /dev/null
  19653. +++ b/drivers/hid/surface-hid/surface_hid_core.h
  19654. @@ -0,0 +1,77 @@
  19655. +/* SPDX-License-Identifier: GPL-2.0+ */
  19656. +/*
  19657. + * Common/core components for the Surface System Aggregator Module (SSAM) HID
  19658. + * transport driver. Provides support for integrated HID devices on Microsoft
  19659. + * Surface models.
  19660. + *
  19661. + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
  19662. + */
  19663. +
  19664. +#ifndef SURFACE_HID_CORE_H
  19665. +#define SURFACE_HID_CORE_H
  19666. +
  19667. +#include <linux/hid.h>
  19668. +#include <linux/pm.h>
  19669. +#include <linux/types.h>
  19670. +
  19671. +#include <linux/surface_aggregator/controller.h>
  19672. +#include <linux/surface_aggregator/device.h>
  19673. +
  19674. +enum surface_hid_descriptor_entry {
  19675. + SURFACE_HID_DESC_HID = 0,
  19676. + SURFACE_HID_DESC_REPORT = 1,
  19677. + SURFACE_HID_DESC_ATTRS = 2,
  19678. +};
  19679. +
  19680. +struct surface_hid_descriptor {
  19681. + __u8 desc_len; /* = 9 */
  19682. + __u8 desc_type; /* = HID_DT_HID */
  19683. + __le16 hid_version;
  19684. + __u8 country_code;
  19685. + __u8 num_descriptors; /* = 1 */
  19686. +
  19687. + __u8 report_desc_type; /* = HID_DT_REPORT */
  19688. + __le16 report_desc_len;
  19689. +} __packed;
  19690. +
  19691. +static_assert(sizeof(struct surface_hid_descriptor) == 9);
  19692. +
  19693. +struct surface_hid_attributes {
  19694. + __le32 length;
  19695. + __le16 vendor;
  19696. + __le16 product;
  19697. + __le16 version;
  19698. + __u8 _unknown[22];
  19699. +} __packed;
  19700. +
  19701. +static_assert(sizeof(struct surface_hid_attributes) == 32);
  19702. +
  19703. +struct surface_hid_device;
  19704. +
  19705. +struct surface_hid_device_ops {
  19706. + int (*get_descriptor)(struct surface_hid_device *shid, u8 entry, u8 *buf, size_t len);
  19707. + int (*output_report)(struct surface_hid_device *shid, u8 rprt_id, u8 *buf, size_t len);
  19708. + int (*get_feature_report)(struct surface_hid_device *shid, u8 rprt_id, u8 *buf, size_t len);
  19709. + int (*set_feature_report)(struct surface_hid_device *shid, u8 rprt_id, u8 *buf, size_t len);
  19710. +};
  19711. +
  19712. +struct surface_hid_device {
  19713. + struct device *dev;
  19714. + struct ssam_controller *ctrl;
  19715. + struct ssam_device_uid uid;
  19716. +
  19717. + struct surface_hid_descriptor hid_desc;
  19718. + struct surface_hid_attributes attrs;
  19719. +
  19720. + struct ssam_event_notifier notif;
  19721. + struct hid_device *hid;
  19722. +
  19723. + struct surface_hid_device_ops ops;
  19724. +};
  19725. +
  19726. +int surface_hid_device_add(struct surface_hid_device *shid);
  19727. +void surface_hid_device_destroy(struct surface_hid_device *shid);
  19728. +
  19729. +extern const struct dev_pm_ops surface_hid_pm_ops;
  19730. +
  19731. +#endif /* SURFACE_HID_CORE_H */
  19732. --
  19733. 2.31.0
  19734. From 793ac74222c86e9e445aab0eded525edd6b75282 Mon Sep 17 00:00:00 2001
  19735. From: Maximilian Luz <luzmaximilian@gmail.com>
  19736. Date: Thu, 11 Feb 2021 20:10:17 +0100
  19737. Subject: [PATCH] HID: surface-hid: Add support for legacy keyboard interface
  19738. Add support for the legacy keyboard (KBD/TC=0x08) HID transport layer of
  19739. the Surface System Aggregator Module (SSAM) to the Surface HID driver.
  19740. On Surface Laptops 1 and 2, this interface is used to connect the
  19741. integrated keyboard.
  19742. Note that this subsystem interface essentially provides a limited HID
  19743. transport layer. In contras to the generic HID interface (TC=0x15) used
  19744. on newer Surface models, this interface only allows (as far as we know)
  19745. for a single device to be connected and is otherwise severely limited in
  19746. terms of support for feature- and output-reports. Specifically, only
  19747. caps-lock-LED output-reports and a single read-only feature-report are
  19748. supported.
  19749. Patchset: surface-sam
  19750. ---
  19751. drivers/hid/surface-hid/Kconfig | 14 ++
  19752. drivers/hid/surface-hid/Makefile | 1 +
  19753. drivers/hid/surface-hid/surface_hid.c | 7 +-
  19754. drivers/hid/surface-hid/surface_kbd.c | 300 ++++++++++++++++++++++++++
  19755. 4 files changed, 317 insertions(+), 5 deletions(-)
  19756. create mode 100644 drivers/hid/surface-hid/surface_kbd.c
  19757. diff --git a/drivers/hid/surface-hid/Kconfig b/drivers/hid/surface-hid/Kconfig
  19758. index 642c7f0e64fe..7ce9b5d641eb 100644
  19759. --- a/drivers/hid/surface-hid/Kconfig
  19760. +++ b/drivers/hid/surface-hid/Kconfig
  19761. @@ -21,6 +21,20 @@ config SURFACE_HID
  19762. integrated touchpad and keyboard, on 7th generation Microsoft Surface
  19763. models.
  19764. +config SURFACE_KBD
  19765. + tristate "HID keyboard transport driver for Surface System Aggregator Module"
  19766. + select SURFACE_HID_CORE
  19767. + help
  19768. + Driver to support HID keyboards on Surface Laptop 1 and 2 devices.
  19769. +
  19770. + This driver provides support for the HID transport protocol provided
  19771. + by the Surface Aggregator Module (i.e. the embedded controller) on
  19772. + Microsoft Surface Laptops 1 and 2. It is used to connect the
  19773. + integrated keyboard on those devices.
  19774. +
  19775. + Say M or Y here, if you want support for the integrated keyboard on
  19776. + Microsoft Surface Laptops 1 and 2.
  19777. +
  19778. endmenu
  19779. config SURFACE_HID_CORE
  19780. diff --git a/drivers/hid/surface-hid/Makefile b/drivers/hid/surface-hid/Makefile
  19781. index 62fc04632d3d..4ae11cf09b25 100644
  19782. --- a/drivers/hid/surface-hid/Makefile
  19783. +++ b/drivers/hid/surface-hid/Makefile
  19784. @@ -4,3 +4,4 @@
  19785. #
  19786. obj-$(CONFIG_SURFACE_HID_CORE) += surface_hid_core.o
  19787. obj-$(CONFIG_SURFACE_HID) += surface_hid.o
  19788. +obj-$(CONFIG_SURFACE_KBD) += surface_kbd.o
  19789. diff --git a/drivers/hid/surface-hid/surface_hid.c b/drivers/hid/surface-hid/surface_hid.c
  19790. index e4477c328536..3477b31611ae 100644
  19791. --- a/drivers/hid/surface-hid/surface_hid.c
  19792. +++ b/drivers/hid/surface-hid/surface_hid.c
  19793. @@ -157,15 +157,12 @@ static int ssam_hid_get_raw_report(struct surface_hid_device *shid, u8 rprt_id,
  19794. static u32 ssam_hid_event_fn(struct ssam_event_notifier *nf, const struct ssam_event *event)
  19795. {
  19796. struct surface_hid_device *shid = container_of(nf, struct surface_hid_device, notif);
  19797. - int status;
  19798. if (event->command_id != 0x00)
  19799. return 0;
  19800. - status = hid_input_report(shid->hid, HID_INPUT_REPORT, (u8 *)&event->data[0],
  19801. - event->length, 0);
  19802. -
  19803. - return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED;
  19804. + hid_input_report(shid->hid, HID_INPUT_REPORT, (u8 *)&event->data[0], event->length, 0);
  19805. + return SSAM_NOTIF_HANDLED;
  19806. }
  19807. diff --git a/drivers/hid/surface-hid/surface_kbd.c b/drivers/hid/surface-hid/surface_kbd.c
  19808. new file mode 100644
  19809. index 000000000000..0635341bc517
  19810. --- /dev/null
  19811. +++ b/drivers/hid/surface-hid/surface_kbd.c
  19812. @@ -0,0 +1,300 @@
  19813. +// SPDX-License-Identifier: GPL-2.0+
  19814. +/*
  19815. + * Surface System Aggregator Module (SSAM) HID transport driver for the legacy
  19816. + * keyboard interface (KBD/TC=0x08 subsystem). Provides support for the
  19817. + * integrated HID keyboard on Surface Laptops 1 and 2.
  19818. + *
  19819. + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
  19820. + */
  19821. +
  19822. +#include <asm/unaligned.h>
  19823. +#include <linux/hid.h>
  19824. +#include <linux/kernel.h>
  19825. +#include <linux/module.h>
  19826. +#include <linux/platform_device.h>
  19827. +#include <linux/types.h>
  19828. +
  19829. +#include <linux/surface_aggregator/controller.h>
  19830. +
  19831. +#include "surface_hid_core.h"
  19832. +
  19833. +
  19834. +/* -- SAM interface (KBD). -------------------------------------------------- */
  19835. +
  19836. +#define KBD_FEATURE_REPORT_SIZE 7 /* 6 + report ID */
  19837. +
  19838. +enum surface_kbd_cid {
  19839. + SURFACE_KBD_CID_GET_DESCRIPTOR = 0x00,
  19840. + SURFACE_KBD_CID_SET_CAPSLOCK_LED = 0x01,
  19841. + SURFACE_KBD_CID_EVT_INPUT_GENERIC = 0x03,
  19842. + SURFACE_KBD_CID_EVT_INPUT_HOTKEYS = 0x04,
  19843. + SURFACE_KBD_CID_GET_FEATURE_REPORT = 0x0b,
  19844. +};
  19845. +
  19846. +static int ssam_kbd_get_descriptor(struct surface_hid_device *shid, u8 entry, u8 *buf, size_t len)
  19847. +{
  19848. + struct ssam_request rqst;
  19849. + struct ssam_response rsp;
  19850. + int status;
  19851. +
  19852. + rqst.target_category = shid->uid.category;
  19853. + rqst.target_id = shid->uid.target;
  19854. + rqst.command_id = SURFACE_KBD_CID_GET_DESCRIPTOR;
  19855. + rqst.instance_id = shid->uid.instance;
  19856. + rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
  19857. + rqst.length = sizeof(entry);
  19858. + rqst.payload = &entry;
  19859. +
  19860. + rsp.capacity = len;
  19861. + rsp.length = 0;
  19862. + rsp.pointer = buf;
  19863. +
  19864. + status = ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(entry));
  19865. + if (status)
  19866. + return status;
  19867. +
  19868. + if (rsp.length != len) {
  19869. + dev_err(shid->dev, "invalid descriptor length: got %zu, expected, %zu\n",
  19870. + rsp.length, len);
  19871. + return -EPROTO;
  19872. + }
  19873. +
  19874. + return 0;
  19875. +}
  19876. +
  19877. +static int ssam_kbd_set_caps_led(struct surface_hid_device *shid, bool value)
  19878. +{
  19879. + struct ssam_request rqst;
  19880. + u8 value_u8 = value;
  19881. +
  19882. + rqst.target_category = shid->uid.category;
  19883. + rqst.target_id = shid->uid.target;
  19884. + rqst.command_id = SURFACE_KBD_CID_SET_CAPSLOCK_LED;
  19885. + rqst.instance_id = shid->uid.instance;
  19886. + rqst.flags = 0;
  19887. + rqst.length = sizeof(value_u8);
  19888. + rqst.payload = &value_u8;
  19889. +
  19890. + return ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, NULL, sizeof(value_u8));
  19891. +}
  19892. +
  19893. +static int ssam_kbd_get_feature_report(struct surface_hid_device *shid, u8 *buf, size_t len)
  19894. +{
  19895. + struct ssam_request rqst;
  19896. + struct ssam_response rsp;
  19897. + u8 payload = 0;
  19898. + int status;
  19899. +
  19900. + rqst.target_category = shid->uid.category;
  19901. + rqst.target_id = shid->uid.target;
  19902. + rqst.command_id = SURFACE_KBD_CID_GET_FEATURE_REPORT;
  19903. + rqst.instance_id = shid->uid.instance;
  19904. + rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
  19905. + rqst.length = sizeof(payload);
  19906. + rqst.payload = &payload;
  19907. +
  19908. + rsp.capacity = len;
  19909. + rsp.length = 0;
  19910. + rsp.pointer = buf;
  19911. +
  19912. + status = ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(payload));
  19913. + if (status)
  19914. + return status;
  19915. +
  19916. + if (rsp.length != len) {
  19917. + dev_err(shid->dev, "invalid feature report length: got %zu, expected, %zu\n",
  19918. + rsp.length, len);
  19919. + return -EPROTO;
  19920. + }
  19921. +
  19922. + return 0;
  19923. +}
  19924. +
  19925. +static bool ssam_kbd_is_input_event(const struct ssam_event *event)
  19926. +{
  19927. + if (event->command_id == SURFACE_KBD_CID_EVT_INPUT_GENERIC)
  19928. + return true;
  19929. +
  19930. + if (event->command_id == SURFACE_KBD_CID_EVT_INPUT_HOTKEYS)
  19931. + return true;
  19932. +
  19933. + return false;
  19934. +}
  19935. +
  19936. +static u32 ssam_kbd_event_fn(struct ssam_event_notifier *nf, const struct ssam_event *event)
  19937. +{
  19938. + struct surface_hid_device *shid = container_of(nf, struct surface_hid_device, notif);
  19939. +
  19940. + /*
  19941. + * Check against device UID manually, as registry and device target
  19942. + * category doesn't line up.
  19943. + */
  19944. +
  19945. + if (shid->uid.category != event->target_category)
  19946. + return 0;
  19947. +
  19948. + if (shid->uid.target != event->target_id)
  19949. + return 0;
  19950. +
  19951. + if (shid->uid.instance != event->instance_id)
  19952. + return 0;
  19953. +
  19954. + if (!ssam_kbd_is_input_event(event))
  19955. + return 0;
  19956. +
  19957. + hid_input_report(shid->hid, HID_INPUT_REPORT, (u8 *)&event->data[0], event->length, 0);
  19958. + return SSAM_NOTIF_HANDLED;
  19959. +}
  19960. +
  19961. +
  19962. +/* -- Transport driver (KBD). ----------------------------------------------- */
  19963. +
  19964. +static int skbd_get_caps_led_value(struct hid_device *hid, u8 rprt_id, u8 *buf, size_t len)
  19965. +{
  19966. + struct hid_field *field;
  19967. + unsigned int offset, size;
  19968. + int i;
  19969. +
  19970. + /* Get LED field. */
  19971. + field = hidinput_get_led_field(hid);
  19972. + if (!field)
  19973. + return -ENOENT;
  19974. +
  19975. + /* Check if we got the correct report. */
  19976. + if (len != hid_report_len(field->report))
  19977. + return -ENOENT;
  19978. +
  19979. + if (rprt_id != field->report->id)
  19980. + return -ENOENT;
  19981. +
  19982. + /* Get caps lock LED index. */
  19983. + for (i = 0; i < field->report_count; i++)
  19984. + if ((field->usage[i].hid & 0xffff) == 0x02)
  19985. + break;
  19986. +
  19987. + if (i == field->report_count)
  19988. + return -ENOENT;
  19989. +
  19990. + /* Extract value. */
  19991. + size = field->report_size;
  19992. + offset = field->report_offset + i * size;
  19993. + return !!hid_field_extract(hid, buf + 1, size, offset);
  19994. +}
  19995. +
  19996. +static int skbd_output_report(struct surface_hid_device *shid, u8 rprt_id, u8 *buf, size_t len)
  19997. +{
  19998. + int caps_led;
  19999. + int status;
  20000. +
  20001. + caps_led = skbd_get_caps_led_value(shid->hid, rprt_id, buf, len);
  20002. + if (caps_led < 0)
  20003. + return -EIO; /* Only caps LED output reports are supported. */
  20004. +
  20005. + status = ssam_kbd_set_caps_led(shid, caps_led);
  20006. + if (status < 0)
  20007. + return status;
  20008. +
  20009. + return len;
  20010. +}
  20011. +
  20012. +static int skbd_get_feature_report(struct surface_hid_device *shid, u8 rprt_id, u8 *buf, size_t len)
  20013. +{
  20014. + u8 report[KBD_FEATURE_REPORT_SIZE];
  20015. + int status;
  20016. +
  20017. + /*
  20018. + * The keyboard only has a single hard-coded read-only feature report
  20019. + * of size KBD_FEATURE_REPORT_SIZE. Try to load it and compare its
  20020. + * report ID against the requested one.
  20021. + */
  20022. +
  20023. + if (len < ARRAY_SIZE(report))
  20024. + return -ENOSPC;
  20025. +
  20026. + status = ssam_kbd_get_feature_report(shid, report, ARRAY_SIZE(report));
  20027. + if (status < 0)
  20028. + return status;
  20029. +
  20030. + if (rprt_id != report[0])
  20031. + return -ENOENT;
  20032. +
  20033. + memcpy(buf, report, ARRAY_SIZE(report));
  20034. + return len;
  20035. +}
  20036. +
  20037. +static int skbd_set_feature_report(struct surface_hid_device *shid, u8 rprt_id, u8 *buf, size_t len)
  20038. +{
  20039. + /* Not supported. See skbd_get_feature_report() for details. */
  20040. + return -EIO;
  20041. +}
  20042. +
  20043. +
  20044. +/* -- Driver setup. --------------------------------------------------------- */
  20045. +
  20046. +static int surface_kbd_probe(struct platform_device *pdev)
  20047. +{
  20048. + struct ssam_controller *ctrl;
  20049. + struct surface_hid_device *shid;
  20050. +
  20051. + /* Add device link to EC. */
  20052. + ctrl = ssam_client_bind(&pdev->dev);
  20053. + if (IS_ERR(ctrl))
  20054. + return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl);
  20055. +
  20056. + shid = devm_kzalloc(&pdev->dev, sizeof(*shid), GFP_KERNEL);
  20057. + if (!shid)
  20058. + return -ENOMEM;
  20059. +
  20060. + shid->dev = &pdev->dev;
  20061. + shid->ctrl = ctrl;
  20062. +
  20063. + shid->uid.domain = SSAM_DOMAIN_SERIALHUB;
  20064. + shid->uid.category = SSAM_SSH_TC_KBD;
  20065. + shid->uid.target = 2;
  20066. + shid->uid.instance = 0;
  20067. + shid->uid.function = 0;
  20068. +
  20069. + shid->notif.base.priority = 1;
  20070. + shid->notif.base.fn = ssam_kbd_event_fn;
  20071. + shid->notif.event.reg = SSAM_EVENT_REGISTRY_SAM;
  20072. + shid->notif.event.id.target_category = shid->uid.category;
  20073. + shid->notif.event.id.instance = shid->uid.instance;
  20074. + shid->notif.event.mask = SSAM_EVENT_MASK_NONE;
  20075. + shid->notif.event.flags = 0;
  20076. +
  20077. + shid->ops.get_descriptor = ssam_kbd_get_descriptor;
  20078. + shid->ops.output_report = skbd_output_report;
  20079. + shid->ops.get_feature_report = skbd_get_feature_report;
  20080. + shid->ops.set_feature_report = skbd_set_feature_report;
  20081. +
  20082. + platform_set_drvdata(pdev, shid);
  20083. + return surface_hid_device_add(shid);
  20084. +}
  20085. +
  20086. +static int surface_kbd_remove(struct platform_device *pdev)
  20087. +{
  20088. + surface_hid_device_destroy(platform_get_drvdata(pdev));
  20089. + return 0;
  20090. +}
  20091. +
  20092. +static const struct acpi_device_id surface_kbd_match[] = {
  20093. + { "MSHW0096" },
  20094. + { },
  20095. +};
  20096. +MODULE_DEVICE_TABLE(acpi, surface_kbd_match);
  20097. +
  20098. +static struct platform_driver surface_kbd_driver = {
  20099. + .probe = surface_kbd_probe,
  20100. + .remove = surface_kbd_remove,
  20101. + .driver = {
  20102. + .name = "surface_keyboard",
  20103. + .acpi_match_table = surface_kbd_match,
  20104. + .pm = &surface_hid_pm_ops,
  20105. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  20106. + },
  20107. +};
  20108. +module_platform_driver(surface_kbd_driver);
  20109. +
  20110. +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  20111. +MODULE_DESCRIPTION("HID legacy transport driver for Surface System Aggregator Module");
  20112. +MODULE_LICENSE("GPL");
  20113. --
  20114. 2.31.0
  20115. From eed7178fa7ca26b93d87546094922b5749763b2d Mon Sep 17 00:00:00 2001
  20116. From: Maximilian Luz <luzmaximilian@gmail.com>
  20117. Date: Fri, 12 Feb 2021 21:06:12 +0100
  20118. Subject: [PATCH] power: supply: Add battery driver for Surface Aggregator
  20119. Module
  20120. On newer Microsoft Surface models (specifically 7th-generation, i.e.
  20121. Surface Pro 7, Surface Book 3, Surface Laptop 3, and Surface Laptop Go),
  20122. battery and AC status/information is no longer handled via standard ACPI
  20123. devices, but instead directly via the Surface System Aggregator Module
  20124. (SSAM), i.e. the embedded controller on those devices.
  20125. While on previous generation models, battery status is also handled via
  20126. SSAM, an ACPI shim was present to translate the standard ACPI battery
  20127. interface to SSAM requests. The SSAM interface itself, which is modeled
  20128. closely after the ACPI interface, has not changed.
  20129. This commit introduces a new SSAM client device driver to support
  20130. battery status/information via the aforementioned interface on said
  20131. Surface models. It is in parts based on the standard ACPI battery
  20132. driver.
  20133. Patchset: surface-sam
  20134. ---
  20135. MAINTAINERS | 7 +
  20136. drivers/power/supply/Kconfig | 16 +
  20137. drivers/power/supply/Makefile | 1 +
  20138. drivers/power/supply/surface_battery.c | 901 +++++++++++++++++++++++++
  20139. 4 files changed, 925 insertions(+)
  20140. create mode 100644 drivers/power/supply/surface_battery.c
  20141. diff --git a/MAINTAINERS b/MAINTAINERS
  20142. index 2eac975aee50..54a4769114e9 100644
  20143. --- a/MAINTAINERS
  20144. +++ b/MAINTAINERS
  20145. @@ -11785,6 +11785,13 @@ F: drivers/scsi/smartpqi/smartpqi*.[ch]
  20146. F: include/linux/cciss*.h
  20147. F: include/uapi/linux/cciss*.h
  20148. +MICROSOFT SURFACE BATTERY AND AC DRIVERS
  20149. +M: Maximilian Luz <luzmaximilian@gmail.com>
  20150. +L: linux-pm@vger.kernel.org
  20151. +L: platform-driver-x86@vger.kernel.org
  20152. +S: Maintained
  20153. +F: drivers/power/supply/surface_battery.c
  20154. +
  20155. MICROSOFT SURFACE DTX DRIVER
  20156. M: Maximilian Luz <luzmaximilian@gmail.com>
  20157. L: platform-driver-x86@vger.kernel.org
  20158. diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
  20159. index 1699b9269a78..b635331daba4 100644
  20160. --- a/drivers/power/supply/Kconfig
  20161. +++ b/drivers/power/supply/Kconfig
  20162. @@ -775,4 +775,20 @@ config RN5T618_POWER
  20163. This driver can also be built as a module. If so, the module will be
  20164. called rn5t618_power.
  20165. +config BATTERY_SURFACE
  20166. + tristate "Battery driver for 7th-generation Microsoft Surface devices"
  20167. + depends on SURFACE_AGGREGATOR_REGISTRY
  20168. + help
  20169. + Driver for battery devices connected via/managed by the Surface System
  20170. + Aggregator Module (SSAM).
  20171. +
  20172. + This driver provides battery-information and -status support for
  20173. + Surface devices where said data is not exposed via the standard ACPI
  20174. + devices. On those models (7th-generation), battery-information is
  20175. + instead handled directly via SSAM client devices and this driver.
  20176. +
  20177. + Say M or Y here to include battery status support for 7th-generation
  20178. + Microsoft Surface devices, i.e. Surface Pro 7, Surface Laptop 3,
  20179. + Surface Book 3, and Surface Laptop Go.
  20180. +
  20181. endif # POWER_SUPPLY
  20182. diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
  20183. index dd4b86318cd9..cddc18994119 100644
  20184. --- a/drivers/power/supply/Makefile
  20185. +++ b/drivers/power/supply/Makefile
  20186. @@ -98,3 +98,4 @@ obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o
  20187. obj-$(CONFIG_CHARGER_BD99954) += bd99954-charger.o
  20188. obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o
  20189. obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o
  20190. +obj-$(CONFIG_BATTERY_SURFACE) += surface_battery.o
  20191. diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c
  20192. new file mode 100644
  20193. index 000000000000..327fd7af386b
  20194. --- /dev/null
  20195. +++ b/drivers/power/supply/surface_battery.c
  20196. @@ -0,0 +1,901 @@
  20197. +// SPDX-License-Identifier: GPL-2.0+
  20198. +/*
  20199. + * Battery driver for 7th-generation Microsoft Surface devices via Surface
  20200. + * System Aggregator Module (SSAM).
  20201. + *
  20202. + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
  20203. + */
  20204. +
  20205. +#include <asm/unaligned.h>
  20206. +#include <linux/jiffies.h>
  20207. +#include <linux/kernel.h>
  20208. +#include <linux/module.h>
  20209. +#include <linux/mutex.h>
  20210. +#include <linux/power_supply.h>
  20211. +#include <linux/sysfs.h>
  20212. +#include <linux/types.h>
  20213. +#include <linux/workqueue.h>
  20214. +
  20215. +#include <linux/surface_aggregator/device.h>
  20216. +
  20217. +
  20218. +/* -- SAM interface. -------------------------------------------------------- */
  20219. +
  20220. +enum sam_event_cid_bat {
  20221. + SAM_EVENT_CID_BAT_BIX = 0x15,
  20222. + SAM_EVENT_CID_BAT_BST = 0x16,
  20223. + SAM_EVENT_CID_BAT_ADP = 0x17,
  20224. + SAM_EVENT_CID_BAT_PROT = 0x18,
  20225. + SAM_EVENT_CID_BAT_DPTF = 0x53,
  20226. +};
  20227. +
  20228. +enum sam_battery_sta {
  20229. + SAM_BATTERY_STA_OK = 0x0f,
  20230. + SAM_BATTERY_STA_PRESENT = 0x10,
  20231. +};
  20232. +
  20233. +enum sam_battery_state {
  20234. + SAM_BATTERY_STATE_DISCHARGING = BIT(0),
  20235. + SAM_BATTERY_STATE_CHARGING = BIT(1),
  20236. + SAM_BATTERY_STATE_CRITICAL = BIT(2),
  20237. +};
  20238. +
  20239. +enum sam_battery_power_unit {
  20240. + SAM_BATTERY_POWER_UNIT_mW = 0,
  20241. + SAM_BATTERY_POWER_UNIT_mA = 1,
  20242. +};
  20243. +
  20244. +/* Equivalent to data returned in ACPI _BIX method, revision 0. */
  20245. +struct spwr_bix {
  20246. + u8 revision;
  20247. + __le32 power_unit;
  20248. + __le32 design_cap;
  20249. + __le32 last_full_charge_cap;
  20250. + __le32 technology;
  20251. + __le32 design_voltage;
  20252. + __le32 design_cap_warn;
  20253. + __le32 design_cap_low;
  20254. + __le32 cycle_count;
  20255. + __le32 measurement_accuracy;
  20256. + __le32 max_sampling_time;
  20257. + __le32 min_sampling_time;
  20258. + __le32 max_avg_interval;
  20259. + __le32 min_avg_interval;
  20260. + __le32 bat_cap_granularity_1;
  20261. + __le32 bat_cap_granularity_2;
  20262. + __u8 model[21];
  20263. + __u8 serial[11];
  20264. + __u8 type[5];
  20265. + __u8 oem_info[21];
  20266. +} __packed;
  20267. +
  20268. +static_assert(sizeof(struct spwr_bix) == 119);
  20269. +
  20270. +/* Equivalent to data returned in ACPI _BST method. */
  20271. +struct spwr_bst {
  20272. + __le32 state;
  20273. + __le32 present_rate;
  20274. + __le32 remaining_cap;
  20275. + __le32 present_voltage;
  20276. +} __packed;
  20277. +
  20278. +static_assert(sizeof(struct spwr_bst) == 16);
  20279. +
  20280. +#define SPWR_BIX_REVISION 0
  20281. +#define SPWR_BATTERY_VALUE_UNKNOWN 0xffffffff
  20282. +
  20283. +/* Get battery status (_STA) */
  20284. +static SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, {
  20285. + .target_category = SSAM_SSH_TC_BAT,
  20286. + .command_id = 0x01,
  20287. +});
  20288. +
  20289. +/* Get battery static information (_BIX). */
  20290. +static SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_bix, struct spwr_bix, {
  20291. + .target_category = SSAM_SSH_TC_BAT,
  20292. + .command_id = 0x02,
  20293. +});
  20294. +
  20295. +/* Get battery dynamic information (_BST). */
  20296. +static SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_bst, struct spwr_bst, {
  20297. + .target_category = SSAM_SSH_TC_BAT,
  20298. + .command_id = 0x03,
  20299. +});
  20300. +
  20301. +/* Set battery trip point (_BTP). */
  20302. +static SSAM_DEFINE_SYNC_REQUEST_CL_W(ssam_bat_set_btp, __le32, {
  20303. + .target_category = SSAM_SSH_TC_BAT,
  20304. + .command_id = 0x04,
  20305. +});
  20306. +
  20307. +
  20308. +/* -- Device structures. ---------------------------------------------------- */
  20309. +
  20310. +struct spwr_psy_properties {
  20311. + const char *name;
  20312. + struct ssam_event_registry registry;
  20313. +};
  20314. +
  20315. +struct spwr_battery_device {
  20316. + struct ssam_device *sdev;
  20317. +
  20318. + char name[32];
  20319. + struct power_supply *psy;
  20320. + struct power_supply_desc psy_desc;
  20321. +
  20322. + struct delayed_work update_work;
  20323. +
  20324. + struct ssam_event_notifier notif;
  20325. +
  20326. + struct mutex lock; /* Guards access to state data below. */
  20327. + unsigned long timestamp;
  20328. +
  20329. + __le32 sta;
  20330. + struct spwr_bix bix;
  20331. + struct spwr_bst bst;
  20332. + u32 alarm;
  20333. +};
  20334. +
  20335. +
  20336. +/* -- Module parameters. ---------------------------------------------------- */
  20337. +
  20338. +static unsigned int cache_time = 1000;
  20339. +module_param(cache_time, uint, 0644);
  20340. +MODULE_PARM_DESC(cache_time, "battery state caching time in milliseconds [default: 1000]");
  20341. +
  20342. +
  20343. +/* -- State management. ----------------------------------------------------- */
  20344. +
  20345. +/*
  20346. + * Delay for battery update quirk. See spwr_battery_recheck_adapter() below
  20347. + * for more details.
  20348. + */
  20349. +#define SPWR_AC_BAT_UPDATE_DELAY msecs_to_jiffies(5000)
  20350. +
  20351. +static bool spwr_battery_present(struct spwr_battery_device *bat)
  20352. +{
  20353. + lockdep_assert_held(&bat->lock);
  20354. +
  20355. + return le32_to_cpu(bat->sta) & SAM_BATTERY_STA_PRESENT;
  20356. +}
  20357. +
  20358. +static int spwr_battery_load_sta(struct spwr_battery_device *bat)
  20359. +{
  20360. + lockdep_assert_held(&bat->lock);
  20361. +
  20362. + return ssam_retry(ssam_bat_get_sta, bat->sdev, &bat->sta);
  20363. +}
  20364. +
  20365. +static int spwr_battery_load_bix(struct spwr_battery_device *bat)
  20366. +{
  20367. + int status;
  20368. +
  20369. + lockdep_assert_held(&bat->lock);
  20370. +
  20371. + if (!spwr_battery_present(bat))
  20372. + return 0;
  20373. +
  20374. + status = ssam_retry(ssam_bat_get_bix, bat->sdev, &bat->bix);
  20375. +
  20376. + /* Enforce NULL terminated strings in case anything goes wrong... */
  20377. + bat->bix.model[ARRAY_SIZE(bat->bix.model) - 1] = 0;
  20378. + bat->bix.serial[ARRAY_SIZE(bat->bix.serial) - 1] = 0;
  20379. + bat->bix.type[ARRAY_SIZE(bat->bix.type) - 1] = 0;
  20380. + bat->bix.oem_info[ARRAY_SIZE(bat->bix.oem_info) - 1] = 0;
  20381. +
  20382. + return status;
  20383. +}
  20384. +
  20385. +static int spwr_battery_load_bst(struct spwr_battery_device *bat)
  20386. +{
  20387. + lockdep_assert_held(&bat->lock);
  20388. +
  20389. + if (!spwr_battery_present(bat))
  20390. + return 0;
  20391. +
  20392. + return ssam_retry(ssam_bat_get_bst, bat->sdev, &bat->bst);
  20393. +}
  20394. +
  20395. +static int spwr_battery_set_alarm_unlocked(struct spwr_battery_device *bat, u32 value)
  20396. +{
  20397. + __le32 value_le = cpu_to_le32(value);
  20398. +
  20399. + lockdep_assert_held(&bat->lock);
  20400. +
  20401. + bat->alarm = value;
  20402. + return ssam_retry(ssam_bat_set_btp, bat->sdev, &value_le);
  20403. +}
  20404. +
  20405. +static int spwr_battery_update_bst_unlocked(struct spwr_battery_device *bat, bool cached)
  20406. +{
  20407. + unsigned long cache_deadline = bat->timestamp + msecs_to_jiffies(cache_time);
  20408. + int status;
  20409. +
  20410. + lockdep_assert_held(&bat->lock);
  20411. +
  20412. + if (cached && bat->timestamp && time_is_after_jiffies(cache_deadline))
  20413. + return 0;
  20414. +
  20415. + status = spwr_battery_load_sta(bat);
  20416. + if (status)
  20417. + return status;
  20418. +
  20419. + status = spwr_battery_load_bst(bat);
  20420. + if (status)
  20421. + return status;
  20422. +
  20423. + bat->timestamp = jiffies;
  20424. + return 0;
  20425. +}
  20426. +
  20427. +static int spwr_battery_update_bst(struct spwr_battery_device *bat, bool cached)
  20428. +{
  20429. + int status;
  20430. +
  20431. + mutex_lock(&bat->lock);
  20432. + status = spwr_battery_update_bst_unlocked(bat, cached);
  20433. + mutex_unlock(&bat->lock);
  20434. +
  20435. + return status;
  20436. +}
  20437. +
  20438. +static int spwr_battery_update_bix_unlocked(struct spwr_battery_device *bat)
  20439. +{
  20440. + int status;
  20441. +
  20442. + lockdep_assert_held(&bat->lock);
  20443. +
  20444. + status = spwr_battery_load_sta(bat);
  20445. + if (status)
  20446. + return status;
  20447. +
  20448. + status = spwr_battery_load_bix(bat);
  20449. + if (status)
  20450. + return status;
  20451. +
  20452. + status = spwr_battery_load_bst(bat);
  20453. + if (status)
  20454. + return status;
  20455. +
  20456. + if (bat->bix.revision != SPWR_BIX_REVISION)
  20457. + dev_warn(&bat->sdev->dev, "unsupported battery revision: %u\n", bat->bix.revision);
  20458. +
  20459. + bat->timestamp = jiffies;
  20460. + return 0;
  20461. +}
  20462. +
  20463. +static u32 sprw_battery_get_full_cap_safe(struct spwr_battery_device *bat)
  20464. +{
  20465. + u32 full_cap = get_unaligned_le32(&bat->bix.last_full_charge_cap);
  20466. +
  20467. + lockdep_assert_held(&bat->lock);
  20468. +
  20469. + if (full_cap == 0 || full_cap == SPWR_BATTERY_VALUE_UNKNOWN)
  20470. + full_cap = get_unaligned_le32(&bat->bix.design_cap);
  20471. +
  20472. + return full_cap;
  20473. +}
  20474. +
  20475. +static bool spwr_battery_is_full(struct spwr_battery_device *bat)
  20476. +{
  20477. + u32 state = get_unaligned_le32(&bat->bst.state);
  20478. + u32 full_cap = sprw_battery_get_full_cap_safe(bat);
  20479. + u32 remaining_cap = get_unaligned_le32(&bat->bst.remaining_cap);
  20480. +
  20481. + lockdep_assert_held(&bat->lock);
  20482. +
  20483. + return full_cap != SPWR_BATTERY_VALUE_UNKNOWN && full_cap != 0 &&
  20484. + remaining_cap != SPWR_BATTERY_VALUE_UNKNOWN &&
  20485. + remaining_cap >= full_cap &&
  20486. + state == 0;
  20487. +}
  20488. +
  20489. +static int spwr_battery_recheck_full(struct spwr_battery_device *bat)
  20490. +{
  20491. + bool present;
  20492. + u32 unit;
  20493. + int status;
  20494. +
  20495. + mutex_lock(&bat->lock);
  20496. + unit = get_unaligned_le32(&bat->bix.power_unit);
  20497. + present = spwr_battery_present(bat);
  20498. +
  20499. + status = spwr_battery_update_bix_unlocked(bat);
  20500. + if (status)
  20501. + goto out;
  20502. +
  20503. + /* If battery has been attached, (re-)initialize alarm. */
  20504. + if (!present && spwr_battery_present(bat)) {
  20505. + u32 cap_warn = get_unaligned_le32(&bat->bix.design_cap_warn);
  20506. +
  20507. + status = spwr_battery_set_alarm_unlocked(bat, cap_warn);
  20508. + if (status)
  20509. + goto out;
  20510. + }
  20511. +
  20512. + /*
  20513. + * Warn if the unit has changed. This is something we genuinely don't
  20514. + * expect to happen, so make this a big warning. If it does, we'll
  20515. + * need to add support for it.
  20516. + */
  20517. + WARN_ON(unit != get_unaligned_le32(&bat->bix.power_unit));
  20518. +
  20519. +out:
  20520. + mutex_unlock(&bat->lock);
  20521. +
  20522. + if (!status)
  20523. + power_supply_changed(bat->psy);
  20524. +
  20525. + return status;
  20526. +}
  20527. +
  20528. +static int spwr_battery_recheck_status(struct spwr_battery_device *bat)
  20529. +{
  20530. + int status;
  20531. +
  20532. + status = spwr_battery_update_bst(bat, false);
  20533. + if (!status)
  20534. + power_supply_changed(bat->psy);
  20535. +
  20536. + return status;
  20537. +}
  20538. +
  20539. +static int spwr_battery_recheck_adapter(struct spwr_battery_device *bat)
  20540. +{
  20541. + /*
  20542. + * Handle battery update quirk: When the battery is fully charged (or
  20543. + * charged up to the limit imposed by the UEFI battery limit) and the
  20544. + * adapter is plugged in or removed, the EC does not send a separate
  20545. + * event for the state (charging/discharging) change. Furthermore it
  20546. + * may take some time until the state is updated on the battery.
  20547. + * Schedule an update to solve this.
  20548. + */
  20549. +
  20550. + schedule_delayed_work(&bat->update_work, SPWR_AC_BAT_UPDATE_DELAY);
  20551. + return 0;
  20552. +}
  20553. +
  20554. +static u32 spwr_notify_bat(struct ssam_event_notifier *nf, const struct ssam_event *event)
  20555. +{
  20556. + struct spwr_battery_device *bat = container_of(nf, struct spwr_battery_device, notif);
  20557. + int status;
  20558. +
  20559. + dev_dbg(&bat->sdev->dev, "power event (cid = %#04x, iid = %#04x, tid = %#04x)\n",
  20560. + event->command_id, event->instance_id, event->target_id);
  20561. +
  20562. + /* Handled here, needs to be handled for all targets/instances. */
  20563. + if (event->command_id == SAM_EVENT_CID_BAT_ADP) {
  20564. + status = spwr_battery_recheck_adapter(bat);
  20565. + return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED;
  20566. + }
  20567. +
  20568. + if (bat->sdev->uid.target != event->target_id)
  20569. + return 0;
  20570. +
  20571. + if (bat->sdev->uid.instance != event->instance_id)
  20572. + return 0;
  20573. +
  20574. + switch (event->command_id) {
  20575. + case SAM_EVENT_CID_BAT_BIX:
  20576. + status = spwr_battery_recheck_full(bat);
  20577. + break;
  20578. +
  20579. + case SAM_EVENT_CID_BAT_BST:
  20580. + status = spwr_battery_recheck_status(bat);
  20581. + break;
  20582. +
  20583. + case SAM_EVENT_CID_BAT_PROT:
  20584. + /*
  20585. + * TODO: Implement support for battery protection status change
  20586. + * event.
  20587. + */
  20588. + status = 0;
  20589. + break;
  20590. +
  20591. + case SAM_EVENT_CID_BAT_DPTF:
  20592. + /*
  20593. + * TODO: Implement support for DPTF event.
  20594. + */
  20595. + status = 0;
  20596. + break;
  20597. +
  20598. + default:
  20599. + return 0;
  20600. + }
  20601. +
  20602. + return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED;
  20603. +}
  20604. +
  20605. +static void spwr_battery_update_bst_workfn(struct work_struct *work)
  20606. +{
  20607. + struct delayed_work *dwork = to_delayed_work(work);
  20608. + struct spwr_battery_device *bat;
  20609. + int status;
  20610. +
  20611. + bat = container_of(dwork, struct spwr_battery_device, update_work);
  20612. +
  20613. + status = spwr_battery_update_bst(bat, false);
  20614. + if (!status)
  20615. + power_supply_changed(bat->psy);
  20616. +
  20617. + if (status)
  20618. + dev_err(&bat->sdev->dev, "failed to update battery state: %d\n", status);
  20619. +}
  20620. +
  20621. +
  20622. +/* -- Properties. ----------------------------------------------------------- */
  20623. +
  20624. +static enum power_supply_property spwr_battery_props_chg[] = {
  20625. + POWER_SUPPLY_PROP_STATUS,
  20626. + POWER_SUPPLY_PROP_PRESENT,
  20627. + POWER_SUPPLY_PROP_TECHNOLOGY,
  20628. + POWER_SUPPLY_PROP_CYCLE_COUNT,
  20629. + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
  20630. + POWER_SUPPLY_PROP_VOLTAGE_NOW,
  20631. + POWER_SUPPLY_PROP_CURRENT_NOW,
  20632. + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
  20633. + POWER_SUPPLY_PROP_CHARGE_FULL,
  20634. + POWER_SUPPLY_PROP_CHARGE_NOW,
  20635. + POWER_SUPPLY_PROP_CAPACITY,
  20636. + POWER_SUPPLY_PROP_CAPACITY_LEVEL,
  20637. + POWER_SUPPLY_PROP_MODEL_NAME,
  20638. + POWER_SUPPLY_PROP_MANUFACTURER,
  20639. + POWER_SUPPLY_PROP_SERIAL_NUMBER,
  20640. +};
  20641. +
  20642. +static enum power_supply_property spwr_battery_props_eng[] = {
  20643. + POWER_SUPPLY_PROP_STATUS,
  20644. + POWER_SUPPLY_PROP_PRESENT,
  20645. + POWER_SUPPLY_PROP_TECHNOLOGY,
  20646. + POWER_SUPPLY_PROP_CYCLE_COUNT,
  20647. + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
  20648. + POWER_SUPPLY_PROP_VOLTAGE_NOW,
  20649. + POWER_SUPPLY_PROP_POWER_NOW,
  20650. + POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
  20651. + POWER_SUPPLY_PROP_ENERGY_FULL,
  20652. + POWER_SUPPLY_PROP_ENERGY_NOW,
  20653. + POWER_SUPPLY_PROP_CAPACITY,
  20654. + POWER_SUPPLY_PROP_CAPACITY_LEVEL,
  20655. + POWER_SUPPLY_PROP_MODEL_NAME,
  20656. + POWER_SUPPLY_PROP_MANUFACTURER,
  20657. + POWER_SUPPLY_PROP_SERIAL_NUMBER,
  20658. +};
  20659. +
  20660. +static int spwr_battery_prop_status(struct spwr_battery_device *bat)
  20661. +{
  20662. + u32 state = get_unaligned_le32(&bat->bst.state);
  20663. + u32 present_rate = get_unaligned_le32(&bat->bst.present_rate);
  20664. +
  20665. + lockdep_assert_held(&bat->lock);
  20666. +
  20667. + if (state & SAM_BATTERY_STATE_DISCHARGING)
  20668. + return POWER_SUPPLY_STATUS_DISCHARGING;
  20669. +
  20670. + if (state & SAM_BATTERY_STATE_CHARGING)
  20671. + return POWER_SUPPLY_STATUS_CHARGING;
  20672. +
  20673. + if (spwr_battery_is_full(bat))
  20674. + return POWER_SUPPLY_STATUS_FULL;
  20675. +
  20676. + if (present_rate == 0)
  20677. + return POWER_SUPPLY_STATUS_NOT_CHARGING;
  20678. +
  20679. + return POWER_SUPPLY_STATUS_UNKNOWN;
  20680. +}
  20681. +
  20682. +static int spwr_battery_prop_technology(struct spwr_battery_device *bat)
  20683. +{
  20684. + lockdep_assert_held(&bat->lock);
  20685. +
  20686. + if (!strcasecmp("NiCd", bat->bix.type))
  20687. + return POWER_SUPPLY_TECHNOLOGY_NiCd;
  20688. +
  20689. + if (!strcasecmp("NiMH", bat->bix.type))
  20690. + return POWER_SUPPLY_TECHNOLOGY_NiMH;
  20691. +
  20692. + if (!strcasecmp("LION", bat->bix.type))
  20693. + return POWER_SUPPLY_TECHNOLOGY_LION;
  20694. +
  20695. + if (!strncasecmp("LI-ION", bat->bix.type, 6))
  20696. + return POWER_SUPPLY_TECHNOLOGY_LION;
  20697. +
  20698. + if (!strcasecmp("LiP", bat->bix.type))
  20699. + return POWER_SUPPLY_TECHNOLOGY_LIPO;
  20700. +
  20701. + return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
  20702. +}
  20703. +
  20704. +static int spwr_battery_prop_capacity(struct spwr_battery_device *bat)
  20705. +{
  20706. + u32 full_cap = sprw_battery_get_full_cap_safe(bat);
  20707. + u32 remaining_cap = get_unaligned_le32(&bat->bst.remaining_cap);
  20708. +
  20709. + lockdep_assert_held(&bat->lock);
  20710. +
  20711. + if (full_cap == 0 || full_cap == SPWR_BATTERY_VALUE_UNKNOWN)
  20712. + return -ENODEV;
  20713. +
  20714. + if (remaining_cap == SPWR_BATTERY_VALUE_UNKNOWN)
  20715. + return -ENODEV;
  20716. +
  20717. + return remaining_cap * 100 / full_cap;
  20718. +}
  20719. +
  20720. +static int spwr_battery_prop_capacity_level(struct spwr_battery_device *bat)
  20721. +{
  20722. + u32 state = get_unaligned_le32(&bat->bst.state);
  20723. + u32 remaining_cap = get_unaligned_le32(&bat->bst.remaining_cap);
  20724. +
  20725. + lockdep_assert_held(&bat->lock);
  20726. +
  20727. + if (state & SAM_BATTERY_STATE_CRITICAL)
  20728. + return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
  20729. +
  20730. + if (spwr_battery_is_full(bat))
  20731. + return POWER_SUPPLY_CAPACITY_LEVEL_FULL;
  20732. +
  20733. + if (remaining_cap <= bat->alarm)
  20734. + return POWER_SUPPLY_CAPACITY_LEVEL_LOW;
  20735. +
  20736. + return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
  20737. +}
  20738. +
  20739. +static int spwr_battery_get_property(struct power_supply *psy, enum power_supply_property psp,
  20740. + union power_supply_propval *val)
  20741. +{
  20742. + struct spwr_battery_device *bat = power_supply_get_drvdata(psy);
  20743. + u32 value;
  20744. + int status;
  20745. +
  20746. + mutex_lock(&bat->lock);
  20747. +
  20748. + status = spwr_battery_update_bst_unlocked(bat, true);
  20749. + if (status)
  20750. + goto out;
  20751. +
  20752. + /* Abort if battery is not present. */
  20753. + if (!spwr_battery_present(bat) && psp != POWER_SUPPLY_PROP_PRESENT) {
  20754. + status = -ENODEV;
  20755. + goto out;
  20756. + }
  20757. +
  20758. + switch (psp) {
  20759. + case POWER_SUPPLY_PROP_STATUS:
  20760. + val->intval = spwr_battery_prop_status(bat);
  20761. + break;
  20762. +
  20763. + case POWER_SUPPLY_PROP_PRESENT:
  20764. + val->intval = spwr_battery_present(bat);
  20765. + break;
  20766. +
  20767. + case POWER_SUPPLY_PROP_TECHNOLOGY:
  20768. + val->intval = spwr_battery_prop_technology(bat);
  20769. + break;
  20770. +
  20771. + case POWER_SUPPLY_PROP_CYCLE_COUNT:
  20772. + value = get_unaligned_le32(&bat->bix.cycle_count);
  20773. + if (value != SPWR_BATTERY_VALUE_UNKNOWN)
  20774. + val->intval = value;
  20775. + else
  20776. + status = -ENODEV;
  20777. + break;
  20778. +
  20779. + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
  20780. + value = get_unaligned_le32(&bat->bix.design_voltage);
  20781. + if (value != SPWR_BATTERY_VALUE_UNKNOWN)
  20782. + val->intval = value * 1000;
  20783. + else
  20784. + status = -ENODEV;
  20785. + break;
  20786. +
  20787. + case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  20788. + value = get_unaligned_le32(&bat->bst.present_voltage);
  20789. + if (value != SPWR_BATTERY_VALUE_UNKNOWN)
  20790. + val->intval = value * 1000;
  20791. + else
  20792. + status = -ENODEV;
  20793. + break;
  20794. +
  20795. + case POWER_SUPPLY_PROP_CURRENT_NOW:
  20796. + case POWER_SUPPLY_PROP_POWER_NOW:
  20797. + value = get_unaligned_le32(&bat->bst.present_rate);
  20798. + if (value != SPWR_BATTERY_VALUE_UNKNOWN)
  20799. + val->intval = value * 1000;
  20800. + else
  20801. + status = -ENODEV;
  20802. + break;
  20803. +
  20804. + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
  20805. + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
  20806. + value = get_unaligned_le32(&bat->bix.design_cap);
  20807. + if (value != SPWR_BATTERY_VALUE_UNKNOWN)
  20808. + val->intval = value * 1000;
  20809. + else
  20810. + status = -ENODEV;
  20811. + break;
  20812. +
  20813. + case POWER_SUPPLY_PROP_CHARGE_FULL:
  20814. + case POWER_SUPPLY_PROP_ENERGY_FULL:
  20815. + value = get_unaligned_le32(&bat->bix.last_full_charge_cap);
  20816. + if (value != SPWR_BATTERY_VALUE_UNKNOWN)
  20817. + val->intval = value * 1000;
  20818. + else
  20819. + status = -ENODEV;
  20820. + break;
  20821. +
  20822. + case POWER_SUPPLY_PROP_CHARGE_NOW:
  20823. + case POWER_SUPPLY_PROP_ENERGY_NOW:
  20824. + value = get_unaligned_le32(&bat->bst.remaining_cap);
  20825. + if (value != SPWR_BATTERY_VALUE_UNKNOWN)
  20826. + val->intval = value * 1000;
  20827. + else
  20828. + status = -ENODEV;
  20829. + break;
  20830. +
  20831. + case POWER_SUPPLY_PROP_CAPACITY:
  20832. + val->intval = spwr_battery_prop_capacity(bat);
  20833. + break;
  20834. +
  20835. + case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
  20836. + val->intval = spwr_battery_prop_capacity_level(bat);
  20837. + break;
  20838. +
  20839. + case POWER_SUPPLY_PROP_MODEL_NAME:
  20840. + val->strval = bat->bix.model;
  20841. + break;
  20842. +
  20843. + case POWER_SUPPLY_PROP_MANUFACTURER:
  20844. + val->strval = bat->bix.oem_info;
  20845. + break;
  20846. +
  20847. + case POWER_SUPPLY_PROP_SERIAL_NUMBER:
  20848. + val->strval = bat->bix.serial;
  20849. + break;
  20850. +
  20851. + default:
  20852. + status = -EINVAL;
  20853. + break;
  20854. + }
  20855. +
  20856. +out:
  20857. + mutex_unlock(&bat->lock);
  20858. + return status;
  20859. +}
  20860. +
  20861. +
  20862. +/* -- Alarm attribute. ------------------------------------------------------ */
  20863. +
  20864. +static ssize_t spwr_battery_alarm_show(struct device *dev, struct device_attribute *attr, char *buf)
  20865. +{
  20866. + struct power_supply *psy = dev_get_drvdata(dev);
  20867. + struct spwr_battery_device *bat = power_supply_get_drvdata(psy);
  20868. + int status;
  20869. +
  20870. + mutex_lock(&bat->lock);
  20871. + status = sysfs_emit(buf, "%d\n", bat->alarm * 1000);
  20872. + mutex_unlock(&bat->lock);
  20873. +
  20874. + return status;
  20875. +}
  20876. +
  20877. +static ssize_t spwr_battery_alarm_store(struct device *dev, struct device_attribute *attr,
  20878. + const char *buf, size_t count)
  20879. +{
  20880. + struct power_supply *psy = dev_get_drvdata(dev);
  20881. + struct spwr_battery_device *bat = power_supply_get_drvdata(psy);
  20882. + unsigned long value;
  20883. + int status;
  20884. +
  20885. + status = kstrtoul(buf, 0, &value);
  20886. + if (status)
  20887. + return status;
  20888. +
  20889. + mutex_lock(&bat->lock);
  20890. +
  20891. + if (!spwr_battery_present(bat)) {
  20892. + mutex_unlock(&bat->lock);
  20893. + return -ENODEV;
  20894. + }
  20895. +
  20896. + status = spwr_battery_set_alarm_unlocked(bat, value / 1000);
  20897. + if (status) {
  20898. + mutex_unlock(&bat->lock);
  20899. + return status;
  20900. + }
  20901. +
  20902. + mutex_unlock(&bat->lock);
  20903. + return count;
  20904. +}
  20905. +
  20906. +static const struct device_attribute alarm_attr = {
  20907. + .attr = {.name = "alarm", .mode = 0644},
  20908. + .show = spwr_battery_alarm_show,
  20909. + .store = spwr_battery_alarm_store,
  20910. +};
  20911. +
  20912. +
  20913. +/* -- Device setup. --------------------------------------------------------- */
  20914. +
  20915. +static void spwr_battery_init(struct spwr_battery_device *bat, struct ssam_device *sdev,
  20916. + struct ssam_event_registry registry, const char *name)
  20917. +{
  20918. + mutex_init(&bat->lock);
  20919. + strncpy(bat->name, name, ARRAY_SIZE(bat->name) - 1);
  20920. +
  20921. + bat->sdev = sdev;
  20922. +
  20923. + bat->notif.base.priority = 1;
  20924. + bat->notif.base.fn = spwr_notify_bat;
  20925. + bat->notif.event.reg = registry;
  20926. + bat->notif.event.id.target_category = sdev->uid.category;
  20927. + bat->notif.event.id.instance = 0;
  20928. + bat->notif.event.mask = SSAM_EVENT_MASK_NONE;
  20929. + bat->notif.event.flags = SSAM_EVENT_SEQUENCED;
  20930. +
  20931. + bat->psy_desc.name = bat->name;
  20932. + bat->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY;
  20933. + bat->psy_desc.get_property = spwr_battery_get_property;
  20934. +
  20935. + INIT_DELAYED_WORK(&bat->update_work, spwr_battery_update_bst_workfn);
  20936. +}
  20937. +
  20938. +static void spwr_battery_destroy(struct spwr_battery_device *bat)
  20939. +{
  20940. + mutex_destroy(&bat->lock);
  20941. +}
  20942. +
  20943. +static int spwr_battery_register(struct spwr_battery_device *bat)
  20944. +{
  20945. + struct power_supply_config psy_cfg = {};
  20946. + __le32 sta;
  20947. + int status;
  20948. +
  20949. + /* Make sure the device is there and functioning properly. */
  20950. + status = ssam_retry(ssam_bat_get_sta, bat->sdev, &sta);
  20951. + if (status)
  20952. + return status;
  20953. +
  20954. + if ((le32_to_cpu(sta) & SAM_BATTERY_STA_OK) != SAM_BATTERY_STA_OK)
  20955. + return -ENODEV;
  20956. +
  20957. + /* Satisfy lockdep although we are in an exclusive context here. */
  20958. + mutex_lock(&bat->lock);
  20959. +
  20960. + status = spwr_battery_update_bix_unlocked(bat);
  20961. + if (status) {
  20962. + mutex_unlock(&bat->lock);
  20963. + return status;
  20964. + }
  20965. +
  20966. + if (spwr_battery_present(bat)) {
  20967. + u32 cap_warn = get_unaligned_le32(&bat->bix.design_cap_warn);
  20968. +
  20969. + status = spwr_battery_set_alarm_unlocked(bat, cap_warn);
  20970. + if (status) {
  20971. + mutex_unlock(&bat->lock);
  20972. + return status;
  20973. + }
  20974. + }
  20975. +
  20976. + mutex_unlock(&bat->lock);
  20977. +
  20978. + switch (get_unaligned_le32(&bat->bix.power_unit)) {
  20979. + case SAM_BATTERY_POWER_UNIT_mW:
  20980. + bat->psy_desc.properties = spwr_battery_props_eng;
  20981. + bat->psy_desc.num_properties = ARRAY_SIZE(spwr_battery_props_eng);
  20982. + break;
  20983. +
  20984. + case SAM_BATTERY_POWER_UNIT_mA:
  20985. + bat->psy_desc.properties = spwr_battery_props_chg;
  20986. + bat->psy_desc.num_properties = ARRAY_SIZE(spwr_battery_props_chg);
  20987. + break;
  20988. +
  20989. + default:
  20990. + dev_err(&bat->sdev->dev, "unsupported battery power unit: %u\n",
  20991. + get_unaligned_le32(&bat->bix.power_unit));
  20992. + return -EINVAL;
  20993. + }
  20994. +
  20995. + psy_cfg.drv_data = bat;
  20996. + bat->psy = power_supply_register(&bat->sdev->dev, &bat->psy_desc, &psy_cfg);
  20997. + if (IS_ERR(bat->psy))
  20998. + return PTR_ERR(bat->psy);
  20999. +
  21000. + status = ssam_notifier_register(bat->sdev->ctrl, &bat->notif);
  21001. + if (status)
  21002. + goto err_notif;
  21003. +
  21004. + status = device_create_file(&bat->psy->dev, &alarm_attr);
  21005. + if (status)
  21006. + goto err_file;
  21007. +
  21008. + return 0;
  21009. +
  21010. +err_file:
  21011. + ssam_notifier_unregister(bat->sdev->ctrl, &bat->notif);
  21012. +err_notif:
  21013. + power_supply_unregister(bat->psy);
  21014. + return status;
  21015. +}
  21016. +
  21017. +static void spwr_battery_unregister(struct spwr_battery_device *bat)
  21018. +{
  21019. + ssam_notifier_unregister(bat->sdev->ctrl, &bat->notif);
  21020. + cancel_delayed_work_sync(&bat->update_work);
  21021. + device_remove_file(&bat->psy->dev, &alarm_attr);
  21022. + power_supply_unregister(bat->psy);
  21023. +}
  21024. +
  21025. +
  21026. +/* -- Driver setup. --------------------------------------------------------- */
  21027. +
  21028. +static int __maybe_unused surface_battery_resume(struct device *dev)
  21029. +{
  21030. + return spwr_battery_recheck_full(dev_get_drvdata(dev));
  21031. +}
  21032. +SIMPLE_DEV_PM_OPS(surface_battery_pm_ops, NULL, surface_battery_resume);
  21033. +
  21034. +static int surface_battery_probe(struct ssam_device *sdev)
  21035. +{
  21036. + const struct spwr_psy_properties *p;
  21037. + struct spwr_battery_device *bat;
  21038. + int status;
  21039. +
  21040. + p = ssam_device_get_match_data(sdev);
  21041. + if (!p)
  21042. + return -ENODEV;
  21043. +
  21044. + bat = devm_kzalloc(&sdev->dev, sizeof(*bat), GFP_KERNEL);
  21045. + if (!bat)
  21046. + return -ENOMEM;
  21047. +
  21048. + spwr_battery_init(bat, sdev, p->registry, p->name);
  21049. + ssam_device_set_drvdata(sdev, bat);
  21050. +
  21051. + status = spwr_battery_register(bat);
  21052. + if (status)
  21053. + spwr_battery_destroy(bat);
  21054. +
  21055. + return status;
  21056. +}
  21057. +
  21058. +static void surface_battery_remove(struct ssam_device *sdev)
  21059. +{
  21060. + struct spwr_battery_device *bat = ssam_device_get_drvdata(sdev);
  21061. +
  21062. + spwr_battery_unregister(bat);
  21063. + spwr_battery_destroy(bat);
  21064. +}
  21065. +
  21066. +static const struct spwr_psy_properties spwr_psy_props_bat1 = {
  21067. + .name = "BAT1",
  21068. + .registry = SSAM_EVENT_REGISTRY_SAM,
  21069. +};
  21070. +
  21071. +static const struct spwr_psy_properties spwr_psy_props_bat2_sb3 = {
  21072. + .name = "BAT2",
  21073. + .registry = SSAM_EVENT_REGISTRY_KIP,
  21074. +};
  21075. +
  21076. +static const struct ssam_device_id surface_battery_match[] = {
  21077. + { SSAM_SDEV(BAT, 0x01, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat1 },
  21078. + { SSAM_SDEV(BAT, 0x02, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat2_sb3 },
  21079. + { },
  21080. +};
  21081. +MODULE_DEVICE_TABLE(ssam, surface_battery_match);
  21082. +
  21083. +static struct ssam_device_driver surface_battery_driver = {
  21084. + .probe = surface_battery_probe,
  21085. + .remove = surface_battery_remove,
  21086. + .match_table = surface_battery_match,
  21087. + .driver = {
  21088. + .name = "surface_battery",
  21089. + .pm = &surface_battery_pm_ops,
  21090. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  21091. + },
  21092. +};
  21093. +module_ssam_device_driver(surface_battery_driver);
  21094. +
  21095. +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  21096. +MODULE_DESCRIPTION("Battery driver for Surface System Aggregator Module");
  21097. +MODULE_LICENSE("GPL");
  21098. --
  21099. 2.31.0
  21100. From ac720c108673ef509b68ff0c1bb47a818cf98ed2 Mon Sep 17 00:00:00 2001
  21101. From: Maximilian Luz <luzmaximilian@gmail.com>
  21102. Date: Fri, 12 Feb 2021 21:07:17 +0100
  21103. Subject: [PATCH] power: supply: Add AC driver for Surface Aggregator Module
  21104. On newer Microsoft Surface models (specifically 7th-generation, i.e.
  21105. Surface Pro 7, Surface Book 3, Surface Laptop 3, and Surface Laptop Go),
  21106. battery and AC status/information is no longer handled via standard ACPI
  21107. devices, but instead directly via the Surface System Aggregator Module
  21108. (SSAM), i.e. the embedded controller on those devices.
  21109. While on previous generation models, AC status is also handled via SSAM,
  21110. an ACPI shim was present to translate the standard ACPI AC interface to
  21111. SSAM requests. The SSAM interface itself, which is modeled closely after
  21112. the ACPI interface, has not changed.
  21113. This commit introduces a new SSAM client device driver to support AC
  21114. status/information via the aforementioned interface on said Surface
  21115. models.
  21116. Patchset: surface-sam
  21117. ---
  21118. MAINTAINERS | 1 +
  21119. drivers/power/supply/Kconfig | 16 ++
  21120. drivers/power/supply/Makefile | 1 +
  21121. drivers/power/supply/surface_charger.c | 296 +++++++++++++++++++++++++
  21122. 4 files changed, 314 insertions(+)
  21123. create mode 100644 drivers/power/supply/surface_charger.c
  21124. diff --git a/MAINTAINERS b/MAINTAINERS
  21125. index 54a4769114e9..3d57740df499 100644
  21126. --- a/MAINTAINERS
  21127. +++ b/MAINTAINERS
  21128. @@ -11791,6 +11791,7 @@ L: linux-pm@vger.kernel.org
  21129. L: platform-driver-x86@vger.kernel.org
  21130. S: Maintained
  21131. F: drivers/power/supply/surface_battery.c
  21132. +F: drivers/power/supply/surface_charger.c
  21133. MICROSOFT SURFACE DTX DRIVER
  21134. M: Maximilian Luz <luzmaximilian@gmail.com>
  21135. diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
  21136. index b635331daba4..d4d756d95778 100644
  21137. --- a/drivers/power/supply/Kconfig
  21138. +++ b/drivers/power/supply/Kconfig
  21139. @@ -791,4 +791,20 @@ config BATTERY_SURFACE
  21140. Microsoft Surface devices, i.e. Surface Pro 7, Surface Laptop 3,
  21141. Surface Book 3, and Surface Laptop Go.
  21142. +config CHARGER_SURFACE
  21143. + tristate "AC driver for 7th-generation Microsoft Surface devices"
  21144. + depends on SURFACE_AGGREGATOR_REGISTRY
  21145. + help
  21146. + Driver for AC devices connected via/managed by the Surface System
  21147. + Aggregator Module (SSAM).
  21148. +
  21149. + This driver provides AC-information and -status support for Surface
  21150. + devices where said data is not exposed via the standard ACPI devices.
  21151. + On those models (7th-generation), AC-information is instead handled
  21152. + directly via a SSAM client device and this driver.
  21153. +
  21154. + Say M or Y here to include AC status support for 7th-generation
  21155. + Microsoft Surface devices, i.e. Surface Pro 7, Surface Laptop 3,
  21156. + Surface Book 3, and Surface Laptop Go.
  21157. +
  21158. endif # POWER_SUPPLY
  21159. diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
  21160. index cddc18994119..9fdd34956153 100644
  21161. --- a/drivers/power/supply/Makefile
  21162. +++ b/drivers/power/supply/Makefile
  21163. @@ -99,3 +99,4 @@ obj-$(CONFIG_CHARGER_BD99954) += bd99954-charger.o
  21164. obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o
  21165. obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o
  21166. obj-$(CONFIG_BATTERY_SURFACE) += surface_battery.o
  21167. +obj-$(CONFIG_CHARGER_SURFACE) += surface_charger.o
  21168. diff --git a/drivers/power/supply/surface_charger.c b/drivers/power/supply/surface_charger.c
  21169. new file mode 100644
  21170. index 000000000000..982f9b9ef6f5
  21171. --- /dev/null
  21172. +++ b/drivers/power/supply/surface_charger.c
  21173. @@ -0,0 +1,296 @@
  21174. +// SPDX-License-Identifier: GPL-2.0+
  21175. +/*
  21176. + * AC driver for 7th-generation Microsoft Surface devices via Surface System
  21177. + * Aggregator Module (SSAM).
  21178. + *
  21179. + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
  21180. + */
  21181. +
  21182. +#include <asm/unaligned.h>
  21183. +#include <linux/kernel.h>
  21184. +#include <linux/module.h>
  21185. +#include <linux/mutex.h>
  21186. +#include <linux/power_supply.h>
  21187. +#include <linux/types.h>
  21188. +
  21189. +#include <linux/surface_aggregator/device.h>
  21190. +
  21191. +
  21192. +/* -- SAM interface. -------------------------------------------------------- */
  21193. +
  21194. +enum sam_event_cid_bat {
  21195. + SAM_EVENT_CID_BAT_ADP = 0x17,
  21196. +};
  21197. +
  21198. +enum sam_battery_sta {
  21199. + SAM_BATTERY_STA_OK = 0x0f,
  21200. + SAM_BATTERY_STA_PRESENT = 0x10,
  21201. +};
  21202. +
  21203. +/* Get battery status (_STA). */
  21204. +static SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, {
  21205. + .target_category = SSAM_SSH_TC_BAT,
  21206. + .command_id = 0x01,
  21207. +});
  21208. +
  21209. +/* Get platform power source for battery (_PSR / DPTF PSRC). */
  21210. +static SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_psrc, __le32, {
  21211. + .target_category = SSAM_SSH_TC_BAT,
  21212. + .command_id = 0x0d,
  21213. +});
  21214. +
  21215. +
  21216. +/* -- Device structures. ---------------------------------------------------- */
  21217. +
  21218. +struct spwr_psy_properties {
  21219. + const char *name;
  21220. + struct ssam_event_registry registry;
  21221. +};
  21222. +
  21223. +struct spwr_ac_device {
  21224. + struct ssam_device *sdev;
  21225. +
  21226. + char name[32];
  21227. + struct power_supply *psy;
  21228. + struct power_supply_desc psy_desc;
  21229. +
  21230. + struct ssam_event_notifier notif;
  21231. +
  21232. + struct mutex lock; /* Guards access to state below. */
  21233. +
  21234. + __le32 state;
  21235. +};
  21236. +
  21237. +
  21238. +/* -- State management. ----------------------------------------------------- */
  21239. +
  21240. +static int spwr_ac_update_unlocked(struct spwr_ac_device *ac)
  21241. +{
  21242. + u32 old = ac->state;
  21243. + int status;
  21244. +
  21245. + lockdep_assert_held(&ac->lock);
  21246. +
  21247. + status = ssam_retry(ssam_bat_get_psrc, ac->sdev, &ac->state);
  21248. + if (status < 0)
  21249. + return status;
  21250. +
  21251. + return old != ac->state;
  21252. +}
  21253. +
  21254. +static int spwr_ac_update(struct spwr_ac_device *ac)
  21255. +{
  21256. + int status;
  21257. +
  21258. + mutex_lock(&ac->lock);
  21259. + status = spwr_ac_update_unlocked(ac);
  21260. + mutex_unlock(&ac->lock);
  21261. +
  21262. + return status;
  21263. +}
  21264. +
  21265. +static int spwr_ac_recheck(struct spwr_ac_device *ac)
  21266. +{
  21267. + int status;
  21268. +
  21269. + status = spwr_ac_update(ac);
  21270. + if (status > 0)
  21271. + power_supply_changed(ac->psy);
  21272. +
  21273. + return status >= 0 ? 0 : status;
  21274. +}
  21275. +
  21276. +static u32 spwr_notify_ac(struct ssam_event_notifier *nf, const struct ssam_event *event)
  21277. +{
  21278. + struct spwr_ac_device *ac;
  21279. + int status;
  21280. +
  21281. + ac = container_of(nf, struct spwr_ac_device, notif);
  21282. +
  21283. + dev_dbg(&ac->sdev->dev, "power event (cid = %#04x, iid = %#04x, tid = %#04x)\n",
  21284. + event->command_id, event->instance_id, event->target_id);
  21285. +
  21286. + /*
  21287. + * Allow events of all targets/instances here. Global adapter status
  21288. + * seems to be handled via target=1 and instance=1, but events are
  21289. + * reported on all targets/instances in use.
  21290. + *
  21291. + * While it should be enough to just listen on 1/1, listen everywhere to
  21292. + * make sure we don't miss anything.
  21293. + */
  21294. +
  21295. + switch (event->command_id) {
  21296. + case SAM_EVENT_CID_BAT_ADP:
  21297. + status = spwr_ac_recheck(ac);
  21298. + return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED;
  21299. +
  21300. + default:
  21301. + return 0;
  21302. + }
  21303. +}
  21304. +
  21305. +
  21306. +/* -- Properties. ----------------------------------------------------------- */
  21307. +
  21308. +static enum power_supply_property spwr_ac_props[] = {
  21309. + POWER_SUPPLY_PROP_ONLINE,
  21310. +};
  21311. +
  21312. +static int spwr_ac_get_property(struct power_supply *psy, enum power_supply_property psp,
  21313. + union power_supply_propval *val)
  21314. +{
  21315. + struct spwr_ac_device *ac = power_supply_get_drvdata(psy);
  21316. + int status;
  21317. +
  21318. + mutex_lock(&ac->lock);
  21319. +
  21320. + status = spwr_ac_update_unlocked(ac);
  21321. + if (status)
  21322. + goto out;
  21323. +
  21324. + switch (psp) {
  21325. + case POWER_SUPPLY_PROP_ONLINE:
  21326. + val->intval = !!le32_to_cpu(ac->state);
  21327. + break;
  21328. +
  21329. + default:
  21330. + status = -EINVAL;
  21331. + goto out;
  21332. + }
  21333. +
  21334. +out:
  21335. + mutex_unlock(&ac->lock);
  21336. + return status;
  21337. +}
  21338. +
  21339. +
  21340. +/* -- Device setup. --------------------------------------------------------- */
  21341. +
  21342. +static void spwr_ac_init(struct spwr_ac_device *ac, struct ssam_device *sdev,
  21343. + struct ssam_event_registry registry, const char *name)
  21344. +{
  21345. + mutex_init(&ac->lock);
  21346. + strncpy(ac->name, name, ARRAY_SIZE(ac->name) - 1);
  21347. +
  21348. + ac->sdev = sdev;
  21349. +
  21350. + ac->notif.base.priority = 1;
  21351. + ac->notif.base.fn = spwr_notify_ac;
  21352. + ac->notif.event.reg = registry;
  21353. + ac->notif.event.id.target_category = sdev->uid.category;
  21354. + ac->notif.event.id.instance = 0;
  21355. + ac->notif.event.mask = SSAM_EVENT_MASK_NONE;
  21356. + ac->notif.event.flags = SSAM_EVENT_SEQUENCED;
  21357. +
  21358. + ac->psy_desc.name = ac->name;
  21359. + ac->psy_desc.type = POWER_SUPPLY_TYPE_MAINS;
  21360. + ac->psy_desc.properties = spwr_ac_props;
  21361. + ac->psy_desc.num_properties = ARRAY_SIZE(spwr_ac_props);
  21362. + ac->psy_desc.get_property = spwr_ac_get_property;
  21363. +}
  21364. +
  21365. +static void spwr_ac_destroy(struct spwr_ac_device *ac)
  21366. +{
  21367. + mutex_destroy(&ac->lock);
  21368. +}
  21369. +
  21370. +static int spwr_ac_register(struct spwr_ac_device *ac)
  21371. +{
  21372. + struct power_supply_config psy_cfg = {};
  21373. + __le32 sta;
  21374. + int status;
  21375. +
  21376. + /* Make sure the device is there and functioning properly. */
  21377. + status = ssam_retry(ssam_bat_get_sta, ac->sdev, &sta);
  21378. + if (status)
  21379. + return status;
  21380. +
  21381. + if ((le32_to_cpu(sta) & SAM_BATTERY_STA_OK) != SAM_BATTERY_STA_OK)
  21382. + return -ENODEV;
  21383. +
  21384. + psy_cfg.drv_data = ac;
  21385. + ac->psy = power_supply_register(&ac->sdev->dev, &ac->psy_desc, &psy_cfg);
  21386. + if (IS_ERR(ac->psy))
  21387. + return PTR_ERR(ac->psy);
  21388. +
  21389. + status = ssam_notifier_register(ac->sdev->ctrl, &ac->notif);
  21390. + if (status)
  21391. + power_supply_unregister(ac->psy);
  21392. +
  21393. + return status;
  21394. +}
  21395. +
  21396. +static int spwr_ac_unregister(struct spwr_ac_device *ac)
  21397. +{
  21398. + ssam_notifier_unregister(ac->sdev->ctrl, &ac->notif);
  21399. + power_supply_unregister(ac->psy);
  21400. + return 0;
  21401. +}
  21402. +
  21403. +
  21404. +/* -- Driver setup. --------------------------------------------------------- */
  21405. +
  21406. +static int __maybe_unused surface_ac_resume(struct device *dev)
  21407. +{
  21408. + return spwr_ac_recheck(dev_get_drvdata(dev));
  21409. +}
  21410. +SIMPLE_DEV_PM_OPS(surface_ac_pm_ops, NULL, surface_ac_resume);
  21411. +
  21412. +static int surface_ac_probe(struct ssam_device *sdev)
  21413. +{
  21414. + const struct spwr_psy_properties *p;
  21415. + struct spwr_ac_device *ac;
  21416. + int status;
  21417. +
  21418. + p = ssam_device_get_match_data(sdev);
  21419. + if (!p)
  21420. + return -ENODEV;
  21421. +
  21422. + ac = devm_kzalloc(&sdev->dev, sizeof(*ac), GFP_KERNEL);
  21423. + if (!ac)
  21424. + return -ENOMEM;
  21425. +
  21426. + spwr_ac_init(ac, sdev, p->registry, p->name);
  21427. + ssam_device_set_drvdata(sdev, ac);
  21428. +
  21429. + status = spwr_ac_register(ac);
  21430. + if (status)
  21431. + spwr_ac_destroy(ac);
  21432. +
  21433. + return status;
  21434. +}
  21435. +
  21436. +static void surface_ac_remove(struct ssam_device *sdev)
  21437. +{
  21438. + struct spwr_ac_device *ac = ssam_device_get_drvdata(sdev);
  21439. +
  21440. + spwr_ac_unregister(ac);
  21441. + spwr_ac_destroy(ac);
  21442. +}
  21443. +
  21444. +static const struct spwr_psy_properties spwr_psy_props_adp1 = {
  21445. + .name = "ADP1",
  21446. + .registry = SSAM_EVENT_REGISTRY_SAM,
  21447. +};
  21448. +
  21449. +static const struct ssam_device_id surface_ac_match[] = {
  21450. + { SSAM_SDEV(BAT, 0x01, 0x01, 0x01), (unsigned long)&spwr_psy_props_adp1 },
  21451. + { },
  21452. +};
  21453. +MODULE_DEVICE_TABLE(ssam, surface_ac_match);
  21454. +
  21455. +static struct ssam_device_driver surface_ac_driver = {
  21456. + .probe = surface_ac_probe,
  21457. + .remove = surface_ac_remove,
  21458. + .match_table = surface_ac_match,
  21459. + .driver = {
  21460. + .name = "surface_ac",
  21461. + .pm = &surface_ac_pm_ops,
  21462. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  21463. + },
  21464. +};
  21465. +module_ssam_device_driver(surface_ac_driver);
  21466. +
  21467. +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  21468. +MODULE_DESCRIPTION("AC driver for Surface System Aggregator Module");
  21469. +MODULE_LICENSE("GPL");
  21470. --
  21471. 2.31.0
  21472. From 8fc7d4f6d7efcf2a5b53bbd759affba0fa8f2f47 Mon Sep 17 00:00:00 2001
  21473. From: Maximilian Luz <luzmaximilian@gmail.com>
  21474. Date: Sat, 13 Feb 2021 19:58:50 +0100
  21475. Subject: [PATCH] platform/surface: Add performance mode driver
  21476. Add driver to support performance mode on Surface devices with Surface
  21477. Aggregator Module.
  21478. Intended to be replaced by a platform profile driver in 5.12.
  21479. Patchset: surface-sam
  21480. ---
  21481. drivers/platform/surface/Kconfig | 17 +++
  21482. drivers/platform/surface/Makefile | 1 +
  21483. drivers/platform/surface/surface_perfmode.c | 122 ++++++++++++++++++++
  21484. 3 files changed, 140 insertions(+)
  21485. create mode 100644 drivers/platform/surface/surface_perfmode.c
  21486. diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig
  21487. index dea313989b4c..3ceeb316d56e 100644
  21488. --- a/drivers/platform/surface/Kconfig
  21489. +++ b/drivers/platform/surface/Kconfig
  21490. @@ -140,6 +140,23 @@ config SURFACE_GPE
  21491. accordingly. It is required on those devices to allow wake-ups from
  21492. suspend by opening the lid.
  21493. +config SURFACE_PERFMODE
  21494. + tristate "Surface Performance-Mode Driver"
  21495. + depends on SURFACE_AGGREGATOR_BUS
  21496. + depends on SYSFS
  21497. + help
  21498. + Driver for the performance-/cooling-mode interface of Microsoft
  21499. + Surface devices.
  21500. +
  21501. + Microsoft Surface devices using the Surface System Aggregator Module
  21502. + (SSAM) can be switched between different performance modes. This,
  21503. + depending on the device, can influence their cooling behavior and may
  21504. + influence power limits, allowing users to choose between performance
  21505. + and higher power-draw, or lower power-draw and more silent operation.
  21506. +
  21507. + This driver provides a user-space interface (via sysfs) for
  21508. + controlling said mode via the corresponding client device.
  21509. +
  21510. config SURFACE_PRO3_BUTTON
  21511. tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet"
  21512. depends on INPUT
  21513. diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile
  21514. index 19b661e274c3..31098983decc 100644
  21515. --- a/drivers/platform/surface/Makefile
  21516. +++ b/drivers/platform/surface/Makefile
  21517. @@ -14,4 +14,5 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o
  21518. obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o
  21519. obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o
  21520. obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o
  21521. +obj-$(CONFIG_SURFACE_PERFMODE) += surface_perfmode.o
  21522. obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
  21523. diff --git a/drivers/platform/surface/surface_perfmode.c b/drivers/platform/surface/surface_perfmode.c
  21524. new file mode 100644
  21525. index 000000000000..3b92a43f8606
  21526. --- /dev/null
  21527. +++ b/drivers/platform/surface/surface_perfmode.c
  21528. @@ -0,0 +1,122 @@
  21529. +// SPDX-License-Identifier: GPL-2.0+
  21530. +/*
  21531. + * Surface performance-mode driver.
  21532. + *
  21533. + * Provides a user-space interface for the performance mode control provided
  21534. + * by the Surface System Aggregator Module (SSAM), influencing cooling
  21535. + * behavior of the device and potentially managing power limits.
  21536. + *
  21537. + * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
  21538. + */
  21539. +
  21540. +#include <asm/unaligned.h>
  21541. +#include <linux/kernel.h>
  21542. +#include <linux/module.h>
  21543. +#include <linux/sysfs.h>
  21544. +#include <linux/types.h>
  21545. +
  21546. +#include <linux/surface_aggregator/device.h>
  21547. +
  21548. +enum sam_perf_mode {
  21549. + SAM_PERF_MODE_NORMAL = 1,
  21550. + SAM_PERF_MODE_BATTERY = 2,
  21551. + SAM_PERF_MODE_PERF1 = 3,
  21552. + SAM_PERF_MODE_PERF2 = 4,
  21553. +
  21554. + __SAM_PERF_MODE__MIN = 1,
  21555. + __SAM_PERF_MODE__MAX = 4,
  21556. +};
  21557. +
  21558. +struct ssam_perf_info {
  21559. + __le32 mode;
  21560. + __le16 unknown1;
  21561. + __le16 unknown2;
  21562. +} __packed;
  21563. +
  21564. +static SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_tmp_perf_mode_get, struct ssam_perf_info, {
  21565. + .target_category = SSAM_SSH_TC_TMP,
  21566. + .command_id = 0x02,
  21567. +});
  21568. +
  21569. +static SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_perf_mode_set, __le32, {
  21570. + .target_category = SSAM_SSH_TC_TMP,
  21571. + .command_id = 0x03,
  21572. +});
  21573. +
  21574. +static int ssam_tmp_perf_mode_set(struct ssam_device *sdev, u32 mode)
  21575. +{
  21576. + __le32 mode_le = cpu_to_le32(mode);
  21577. +
  21578. + if (mode < __SAM_PERF_MODE__MIN || mode > __SAM_PERF_MODE__MAX)
  21579. + return -EINVAL;
  21580. +
  21581. + return ssam_retry(__ssam_tmp_perf_mode_set, sdev, &mode_le);
  21582. +}
  21583. +
  21584. +static ssize_t perf_mode_show(struct device *dev, struct device_attribute *attr,
  21585. + char *data)
  21586. +{
  21587. + struct ssam_device *sdev = to_ssam_device(dev);
  21588. + struct ssam_perf_info info;
  21589. + int status;
  21590. +
  21591. + status = ssam_retry(ssam_tmp_perf_mode_get, sdev, &info);
  21592. + if (status) {
  21593. + dev_err(dev, "failed to get current performance mode: %d\n",
  21594. + status);
  21595. + return -EIO;
  21596. + }
  21597. +
  21598. + return sprintf(data, "%d\n", le32_to_cpu(info.mode));
  21599. +}
  21600. +
  21601. +static ssize_t perf_mode_store(struct device *dev, struct device_attribute *attr,
  21602. + const char *data, size_t count)
  21603. +{
  21604. + struct ssam_device *sdev = to_ssam_device(dev);
  21605. + int perf_mode;
  21606. + int status;
  21607. +
  21608. + status = kstrtoint(data, 0, &perf_mode);
  21609. + if (status < 0)
  21610. + return status;
  21611. +
  21612. + status = ssam_tmp_perf_mode_set(sdev, perf_mode);
  21613. + if (status < 0)
  21614. + return status;
  21615. +
  21616. + return count;
  21617. +}
  21618. +
  21619. +static const DEVICE_ATTR_RW(perf_mode);
  21620. +
  21621. +static int surface_sam_sid_perfmode_probe(struct ssam_device *sdev)
  21622. +{
  21623. + return sysfs_create_file(&sdev->dev.kobj, &dev_attr_perf_mode.attr);
  21624. +}
  21625. +
  21626. +static void surface_sam_sid_perfmode_remove(struct ssam_device *sdev)
  21627. +{
  21628. + sysfs_remove_file(&sdev->dev.kobj, &dev_attr_perf_mode.attr);
  21629. +}
  21630. +
  21631. +static const struct ssam_device_id ssam_perfmode_match[] = {
  21632. + { SSAM_SDEV(TMP, 0x01, 0x00, 0x01) },
  21633. + { },
  21634. +};
  21635. +MODULE_DEVICE_TABLE(ssam, ssam_perfmode_match);
  21636. +
  21637. +static struct ssam_device_driver surface_sam_sid_perfmode = {
  21638. + .probe = surface_sam_sid_perfmode_probe,
  21639. + .remove = surface_sam_sid_perfmode_remove,
  21640. + .match_table = ssam_perfmode_match,
  21641. + .driver = {
  21642. + .name = "surface_performance_mode",
  21643. + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
  21644. + },
  21645. +};
  21646. +module_ssam_device_driver(surface_sam_sid_perfmode);
  21647. +
  21648. +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
  21649. +MODULE_DESCRIPTION("Performance mode interface for Surface System Aggregator Module");
  21650. +MODULE_LICENSE("GPL");
  21651. --
  21652. 2.31.0
  21653. From 784252e94930063aec12fbdd0f4e60f899fbfdbc Mon Sep 17 00:00:00 2001
  21654. From: Maximilian Luz <luzmaximilian@gmail.com>
  21655. Date: Thu, 4 Mar 2021 20:05:24 +0100
  21656. Subject: [PATCH] platform/surface: aggregator: Make SSAM_DEFINE_SYNC_REQUEST_x
  21657. define static functions
  21658. The SSAM_DEFINE_SYNC_REQUEST_x() macros are intended to reduce
  21659. boiler-plate code for SSAM request definitions by defining a wrapper
  21660. function for the specified request. The client device variants of those
  21661. macros, i.e. SSAM_DEFINE_SYNC_REQUEST_CL_x() in particular rely on the
  21662. multi-device (MD) variants, e.g.:
  21663. #define SSAM_DEFINE_SYNC_REQUEST_CL_R(name, rtype, spec...) \
  21664. SSAM_DEFINE_SYNC_REQUEST_MD_R(__raw_##name, rtype, spec) \
  21665. int name(struct ssam_device *sdev, rtype *ret) \
  21666. { \
  21667. return __raw_##name(sdev->ctrl, sdev->uid.target, \
  21668. sdev->uid.instance, ret); \
  21669. }
  21670. This now creates the problem that it is not possible to declare the
  21671. generated functions static via
  21672. static SSAM_DEFINE_SYNC_REQUEST_CL_R(...)
  21673. as this will only apply to the function defined by the multi-device
  21674. macro, i.e. SSAM_DEFINE_SYNC_REQUEST_MD_R(). Thus compiling with
  21675. `-Wmissing-prototypes' rightfully complains that there is a 'static'
  21676. keyword missing.
  21677. To solve this, make all SSAM_DEFINE_SYNC_REQUEST_x() macros define
  21678. static functions. Non-client-device macros are also changed for
  21679. consistency. In general, we expect those functions to be only used
  21680. locally in the respective drivers for the corresponding interfaces, so
  21681. having to define a wrapper function to be able to export this should be
  21682. the odd case out.
  21683. Reported-by: kernel test robot <lkp@intel.com>
  21684. Fixes: b78b4982d763 ("platform/surface: Add platform profile driver")
  21685. Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
  21686. Link: https://lore.kernel.org/r/20210304190524.1172197-1-luzmaximilian@gmail.com
  21687. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  21688. Patchset: surface-sam
  21689. ---
  21690. .../driver-api/surface_aggregator/client.rst | 4 +-
  21691. .../platform/surface/aggregator/controller.c | 10 +--
  21692. .../surface/surface_aggregator_registry.c | 2 +-
  21693. drivers/platform/surface/surface_dtx.c | 18 ++---
  21694. drivers/platform/surface/surface_perfmode.c | 4 +-
  21695. drivers/power/supply/surface_battery.c | 8 +-
  21696. drivers/power/supply/surface_charger.c | 4 +-
  21697. include/linux/surface_aggregator/controller.h | 74 +++++++++----------
  21698. include/linux/surface_aggregator/device.h | 31 ++++----
  21699. 9 files changed, 78 insertions(+), 77 deletions(-)
  21700. diff --git a/Documentation/driver-api/surface_aggregator/client.rst b/Documentation/driver-api/surface_aggregator/client.rst
  21701. index 26d13085a117..e519d374c378 100644
  21702. --- a/Documentation/driver-api/surface_aggregator/client.rst
  21703. +++ b/Documentation/driver-api/surface_aggregator/client.rst
  21704. @@ -248,7 +248,7 @@ This example defines a function
  21705. .. code-block:: c
  21706. - int __ssam_tmp_perf_mode_set(struct ssam_controller *ctrl, const __le32 *arg);
  21707. + static int __ssam_tmp_perf_mode_set(struct ssam_controller *ctrl, const __le32 *arg);
  21708. executing the specified request, with the controller passed in when calling
  21709. said function. In this example, the argument is provided via the ``arg``
  21710. @@ -296,7 +296,7 @@ This invocation of the macro defines a function
  21711. .. code-block:: c
  21712. - int ssam_bat_get_sta(struct ssam_device *sdev, __le32 *ret);
  21713. + static int ssam_bat_get_sta(struct ssam_device *sdev, __le32 *ret);
  21714. executing the specified request, using the device IDs and controller given
  21715. in the client device. The full list of such macros for client devices is:
  21716. diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
  21717. index 5bcb59ed579d..aa6f37b4f46e 100644
  21718. --- a/drivers/platform/surface/aggregator/controller.c
  21719. +++ b/drivers/platform/surface/aggregator/controller.c
  21720. @@ -1750,35 +1750,35 @@ EXPORT_SYMBOL_GPL(ssam_request_sync_with_buffer);
  21721. /* -- Internal SAM requests. ------------------------------------------------ */
  21722. -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_get_firmware_version, __le32, {
  21723. +SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_get_firmware_version, __le32, {
  21724. .target_category = SSAM_SSH_TC_SAM,
  21725. .target_id = 0x01,
  21726. .command_id = 0x13,
  21727. .instance_id = 0x00,
  21728. });
  21729. -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_off, u8, {
  21730. +SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_off, u8, {
  21731. .target_category = SSAM_SSH_TC_SAM,
  21732. .target_id = 0x01,
  21733. .command_id = 0x15,
  21734. .instance_id = 0x00,
  21735. });
  21736. -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_on, u8, {
  21737. +SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_on, u8, {
  21738. .target_category = SSAM_SSH_TC_SAM,
  21739. .target_id = 0x01,
  21740. .command_id = 0x16,
  21741. .instance_id = 0x00,
  21742. });
  21743. -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_exit, u8, {
  21744. +SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_exit, u8, {
  21745. .target_category = SSAM_SSH_TC_SAM,
  21746. .target_id = 0x01,
  21747. .command_id = 0x33,
  21748. .instance_id = 0x00,
  21749. });
  21750. -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_entry, u8, {
  21751. +SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_entry, u8, {
  21752. .target_category = SSAM_SSH_TC_SAM,
  21753. .target_id = 0x01,
  21754. .command_id = 0x34,
  21755. diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
  21756. index 304d601980ed..eccb9d1007cd 100644
  21757. --- a/drivers/platform/surface/surface_aggregator_registry.c
  21758. +++ b/drivers/platform/surface/surface_aggregator_registry.c
  21759. @@ -302,7 +302,7 @@ struct ssam_base_hub {
  21760. struct ssam_event_notifier notif;
  21761. };
  21762. -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, {
  21763. +SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, {
  21764. .target_category = SSAM_SSH_TC_BAS,
  21765. .target_id = 0x01,
  21766. .command_id = 0x0d,
  21767. diff --git a/drivers/platform/surface/surface_dtx.c b/drivers/platform/surface/surface_dtx.c
  21768. index 4bb5d286bf95..85451eb94d98 100644
  21769. --- a/drivers/platform/surface/surface_dtx.c
  21770. +++ b/drivers/platform/surface/surface_dtx.c
  21771. @@ -69,63 +69,63 @@ struct ssam_bas_base_info {
  21772. static_assert(sizeof(struct ssam_bas_base_info) == 2);
  21773. -static SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_lock, {
  21774. +SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_lock, {
  21775. .target_category = SSAM_SSH_TC_BAS,
  21776. .target_id = 0x01,
  21777. .command_id = 0x06,
  21778. .instance_id = 0x00,
  21779. });
  21780. -static SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_unlock, {
  21781. +SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_unlock, {
  21782. .target_category = SSAM_SSH_TC_BAS,
  21783. .target_id = 0x01,
  21784. .command_id = 0x07,
  21785. .instance_id = 0x00,
  21786. });
  21787. -static SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_request, {
  21788. +SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_request, {
  21789. .target_category = SSAM_SSH_TC_BAS,
  21790. .target_id = 0x01,
  21791. .command_id = 0x08,
  21792. .instance_id = 0x00,
  21793. });
  21794. -static SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_confirm, {
  21795. +SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_confirm, {
  21796. .target_category = SSAM_SSH_TC_BAS,
  21797. .target_id = 0x01,
  21798. .command_id = 0x09,
  21799. .instance_id = 0x00,
  21800. });
  21801. -static SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_heartbeat, {
  21802. +SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_heartbeat, {
  21803. .target_category = SSAM_SSH_TC_BAS,
  21804. .target_id = 0x01,
  21805. .command_id = 0x0a,
  21806. .instance_id = 0x00,
  21807. });
  21808. -static SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_cancel, {
  21809. +SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_cancel, {
  21810. .target_category = SSAM_SSH_TC_BAS,
  21811. .target_id = 0x01,
  21812. .command_id = 0x0b,
  21813. .instance_id = 0x00,
  21814. });
  21815. -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_base, struct ssam_bas_base_info, {
  21816. +SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_base, struct ssam_bas_base_info, {
  21817. .target_category = SSAM_SSH_TC_BAS,
  21818. .target_id = 0x01,
  21819. .command_id = 0x0c,
  21820. .instance_id = 0x00,
  21821. });
  21822. -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_device_mode, u8, {
  21823. +SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_device_mode, u8, {
  21824. .target_category = SSAM_SSH_TC_BAS,
  21825. .target_id = 0x01,
  21826. .command_id = 0x0d,
  21827. .instance_id = 0x00,
  21828. });
  21829. -static SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_latch_status, u8, {
  21830. +SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_latch_status, u8, {
  21831. .target_category = SSAM_SSH_TC_BAS,
  21832. .target_id = 0x01,
  21833. .command_id = 0x11,
  21834. diff --git a/drivers/platform/surface/surface_perfmode.c b/drivers/platform/surface/surface_perfmode.c
  21835. index 3b92a43f8606..a9114e001d0d 100644
  21836. --- a/drivers/platform/surface/surface_perfmode.c
  21837. +++ b/drivers/platform/surface/surface_perfmode.c
  21838. @@ -33,12 +33,12 @@ struct ssam_perf_info {
  21839. __le16 unknown2;
  21840. } __packed;
  21841. -static SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_tmp_perf_mode_get, struct ssam_perf_info, {
  21842. +SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_tmp_perf_mode_get, struct ssam_perf_info, {
  21843. .target_category = SSAM_SSH_TC_TMP,
  21844. .command_id = 0x02,
  21845. });
  21846. -static SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_perf_mode_set, __le32, {
  21847. +SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_perf_mode_set, __le32, {
  21848. .target_category = SSAM_SSH_TC_TMP,
  21849. .command_id = 0x03,
  21850. });
  21851. diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c
  21852. index 327fd7af386b..b93a4f556b5c 100644
  21853. --- a/drivers/power/supply/surface_battery.c
  21854. +++ b/drivers/power/supply/surface_battery.c
  21855. @@ -85,25 +85,25 @@ static_assert(sizeof(struct spwr_bst) == 16);
  21856. #define SPWR_BATTERY_VALUE_UNKNOWN 0xffffffff
  21857. /* Get battery status (_STA) */
  21858. -static SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, {
  21859. +SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, {
  21860. .target_category = SSAM_SSH_TC_BAT,
  21861. .command_id = 0x01,
  21862. });
  21863. /* Get battery static information (_BIX). */
  21864. -static SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_bix, struct spwr_bix, {
  21865. +SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_bix, struct spwr_bix, {
  21866. .target_category = SSAM_SSH_TC_BAT,
  21867. .command_id = 0x02,
  21868. });
  21869. /* Get battery dynamic information (_BST). */
  21870. -static SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_bst, struct spwr_bst, {
  21871. +SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_bst, struct spwr_bst, {
  21872. .target_category = SSAM_SSH_TC_BAT,
  21873. .command_id = 0x03,
  21874. });
  21875. /* Set battery trip point (_BTP). */
  21876. -static SSAM_DEFINE_SYNC_REQUEST_CL_W(ssam_bat_set_btp, __le32, {
  21877. +SSAM_DEFINE_SYNC_REQUEST_CL_W(ssam_bat_set_btp, __le32, {
  21878. .target_category = SSAM_SSH_TC_BAT,
  21879. .command_id = 0x04,
  21880. });
  21881. diff --git a/drivers/power/supply/surface_charger.c b/drivers/power/supply/surface_charger.c
  21882. index 982f9b9ef6f5..fe484523a2c2 100644
  21883. --- a/drivers/power/supply/surface_charger.c
  21884. +++ b/drivers/power/supply/surface_charger.c
  21885. @@ -28,13 +28,13 @@ enum sam_battery_sta {
  21886. };
  21887. /* Get battery status (_STA). */
  21888. -static SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, {
  21889. +SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, {
  21890. .target_category = SSAM_SSH_TC_BAT,
  21891. .command_id = 0x01,
  21892. });
  21893. /* Get platform power source for battery (_PSR / DPTF PSRC). */
  21894. -static SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_psrc, __le32, {
  21895. +SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_psrc, __le32, {
  21896. .target_category = SSAM_SSH_TC_BAT,
  21897. .command_id = 0x0d,
  21898. });
  21899. diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h
  21900. index f4b1ba887384..0806796eabcb 100644
  21901. --- a/include/linux/surface_aggregator/controller.h
  21902. +++ b/include/linux/surface_aggregator/controller.h
  21903. @@ -344,16 +344,16 @@ struct ssam_request_spec_md {
  21904. * request has been fully completed. The required transport buffer will be
  21905. * allocated on the stack.
  21906. *
  21907. - * The generated function is defined as ``int name(struct ssam_controller
  21908. - * *ctrl)``, returning the status of the request, which is zero on success and
  21909. - * negative on failure. The ``ctrl`` parameter is the controller via which the
  21910. - * request is being sent.
  21911. + * The generated function is defined as ``static int name(struct
  21912. + * ssam_controller *ctrl)``, returning the status of the request, which is
  21913. + * zero on success and negative on failure. The ``ctrl`` parameter is the
  21914. + * controller via which the request is being sent.
  21915. *
  21916. * Refer to ssam_request_sync_onstack() for more details on the behavior of
  21917. * the generated function.
  21918. */
  21919. #define SSAM_DEFINE_SYNC_REQUEST_N(name, spec...) \
  21920. - int name(struct ssam_controller *ctrl) \
  21921. + static int name(struct ssam_controller *ctrl) \
  21922. { \
  21923. struct ssam_request_spec s = (struct ssam_request_spec)spec; \
  21924. struct ssam_request rqst; \
  21925. @@ -383,17 +383,17 @@ struct ssam_request_spec_md {
  21926. * returning once the request has been fully completed. The required transport
  21927. * buffer will be allocated on the stack.
  21928. *
  21929. - * The generated function is defined as ``int name(struct ssam_controller
  21930. - * *ctrl, const atype *arg)``, returning the status of the request, which is
  21931. - * zero on success and negative on failure. The ``ctrl`` parameter is the
  21932. - * controller via which the request is sent. The request argument is specified
  21933. - * via the ``arg`` pointer.
  21934. + * The generated function is defined as ``static int name(struct
  21935. + * ssam_controller *ctrl, const atype *arg)``, returning the status of the
  21936. + * request, which is zero on success and negative on failure. The ``ctrl``
  21937. + * parameter is the controller via which the request is sent. The request
  21938. + * argument is specified via the ``arg`` pointer.
  21939. *
  21940. * Refer to ssam_request_sync_onstack() for more details on the behavior of
  21941. * the generated function.
  21942. */
  21943. #define SSAM_DEFINE_SYNC_REQUEST_W(name, atype, spec...) \
  21944. - int name(struct ssam_controller *ctrl, const atype *arg) \
  21945. + static int name(struct ssam_controller *ctrl, const atype *arg) \
  21946. { \
  21947. struct ssam_request_spec s = (struct ssam_request_spec)spec; \
  21948. struct ssam_request rqst; \
  21949. @@ -424,17 +424,17 @@ struct ssam_request_spec_md {
  21950. * request itself, returning once the request has been fully completed. The
  21951. * required transport buffer will be allocated on the stack.
  21952. *
  21953. - * The generated function is defined as ``int name(struct ssam_controller
  21954. - * *ctrl, rtype *ret)``, returning the status of the request, which is zero on
  21955. - * success and negative on failure. The ``ctrl`` parameter is the controller
  21956. - * via which the request is sent. The request's return value is written to the
  21957. - * memory pointed to by the ``ret`` parameter.
  21958. + * The generated function is defined as ``static int name(struct
  21959. + * ssam_controller *ctrl, rtype *ret)``, returning the status of the request,
  21960. + * which is zero on success and negative on failure. The ``ctrl`` parameter is
  21961. + * the controller via which the request is sent. The request's return value is
  21962. + * written to the memory pointed to by the ``ret`` parameter.
  21963. *
  21964. * Refer to ssam_request_sync_onstack() for more details on the behavior of
  21965. * the generated function.
  21966. */
  21967. #define SSAM_DEFINE_SYNC_REQUEST_R(name, rtype, spec...) \
  21968. - int name(struct ssam_controller *ctrl, rtype *ret) \
  21969. + static int name(struct ssam_controller *ctrl, rtype *ret) \
  21970. { \
  21971. struct ssam_request_spec s = (struct ssam_request_spec)spec; \
  21972. struct ssam_request rqst; \
  21973. @@ -483,17 +483,17 @@ struct ssam_request_spec_md {
  21974. * returning once the request has been fully completed. The required transport
  21975. * buffer will be allocated on the stack.
  21976. *
  21977. - * The generated function is defined as ``int name(struct ssam_controller
  21978. - * *ctrl, u8 tid, u8 iid)``, returning the status of the request, which is
  21979. - * zero on success and negative on failure. The ``ctrl`` parameter is the
  21980. - * controller via which the request is sent, ``tid`` the target ID for the
  21981. - * request, and ``iid`` the instance ID.
  21982. + * The generated function is defined as ``static int name(struct
  21983. + * ssam_controller *ctrl, u8 tid, u8 iid)``, returning the status of the
  21984. + * request, which is zero on success and negative on failure. The ``ctrl``
  21985. + * parameter is the controller via which the request is sent, ``tid`` the
  21986. + * target ID for the request, and ``iid`` the instance ID.
  21987. *
  21988. * Refer to ssam_request_sync_onstack() for more details on the behavior of
  21989. * the generated function.
  21990. */
  21991. #define SSAM_DEFINE_SYNC_REQUEST_MD_N(name, spec...) \
  21992. - int name(struct ssam_controller *ctrl, u8 tid, u8 iid) \
  21993. + static int name(struct ssam_controller *ctrl, u8 tid, u8 iid) \
  21994. { \
  21995. struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \
  21996. struct ssam_request rqst; \
  21997. @@ -524,18 +524,18 @@ struct ssam_request_spec_md {
  21998. * the request itself, returning once the request has been fully completed.
  21999. * The required transport buffer will be allocated on the stack.
  22000. *
  22001. - * The generated function is defined as ``int name(struct ssam_controller
  22002. - * *ctrl, u8 tid, u8 iid, const atype *arg)``, returning the status of the
  22003. - * request, which is zero on success and negative on failure. The ``ctrl``
  22004. - * parameter is the controller via which the request is sent, ``tid`` the
  22005. - * target ID for the request, and ``iid`` the instance ID. The request argument
  22006. - * is specified via the ``arg`` pointer.
  22007. + * The generated function is defined as ``static int name(struct
  22008. + * ssam_controller *ctrl, u8 tid, u8 iid, const atype *arg)``, returning the
  22009. + * status of the request, which is zero on success and negative on failure.
  22010. + * The ``ctrl`` parameter is the controller via which the request is sent,
  22011. + * ``tid`` the target ID for the request, and ``iid`` the instance ID. The
  22012. + * request argument is specified via the ``arg`` pointer.
  22013. *
  22014. * Refer to ssam_request_sync_onstack() for more details on the behavior of
  22015. * the generated function.
  22016. */
  22017. #define SSAM_DEFINE_SYNC_REQUEST_MD_W(name, atype, spec...) \
  22018. - int name(struct ssam_controller *ctrl, u8 tid, u8 iid, const atype *arg)\
  22019. + static int name(struct ssam_controller *ctrl, u8 tid, u8 iid, const atype *arg) \
  22020. { \
  22021. struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \
  22022. struct ssam_request rqst; \
  22023. @@ -567,18 +567,18 @@ struct ssam_request_spec_md {
  22024. * execution of the request itself, returning once the request has been fully
  22025. * completed. The required transport buffer will be allocated on the stack.
  22026. *
  22027. - * The generated function is defined as ``int name(struct ssam_controller
  22028. - * *ctrl, u8 tid, u8 iid, rtype *ret)``, returning the status of the request,
  22029. - * which is zero on success and negative on failure. The ``ctrl`` parameter is
  22030. - * the controller via which the request is sent, ``tid`` the target ID for the
  22031. - * request, and ``iid`` the instance ID. The request's return value is written
  22032. - * to the memory pointed to by the ``ret`` parameter.
  22033. + * The generated function is defined as ``static int name(struct
  22034. + * ssam_controller *ctrl, u8 tid, u8 iid, rtype *ret)``, returning the status
  22035. + * of the request, which is zero on success and negative on failure. The
  22036. + * ``ctrl`` parameter is the controller via which the request is sent, ``tid``
  22037. + * the target ID for the request, and ``iid`` the instance ID. The request's
  22038. + * return value is written to the memory pointed to by the ``ret`` parameter.
  22039. *
  22040. * Refer to ssam_request_sync_onstack() for more details on the behavior of
  22041. * the generated function.
  22042. */
  22043. #define SSAM_DEFINE_SYNC_REQUEST_MD_R(name, rtype, spec...) \
  22044. - int name(struct ssam_controller *ctrl, u8 tid, u8 iid, rtype *ret) \
  22045. + static int name(struct ssam_controller *ctrl, u8 tid, u8 iid, rtype *ret) \
  22046. { \
  22047. struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \
  22048. struct ssam_request rqst; \
  22049. diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h
  22050. index 02f3e06c0a60..4441ad667c3f 100644
  22051. --- a/include/linux/surface_aggregator/device.h
  22052. +++ b/include/linux/surface_aggregator/device.h
  22053. @@ -336,17 +336,18 @@ void ssam_device_driver_unregister(struct ssam_device_driver *d);
  22054. * request has been fully completed. The required transport buffer will be
  22055. * allocated on the stack.
  22056. *
  22057. - * The generated function is defined as ``int name(struct ssam_device *sdev)``,
  22058. - * returning the status of the request, which is zero on success and negative
  22059. - * on failure. The ``sdev`` parameter specifies both the target device of the
  22060. - * request and by association the controller via which the request is sent.
  22061. + * The generated function is defined as ``static int name(struct ssam_device
  22062. + * *sdev)``, returning the status of the request, which is zero on success and
  22063. + * negative on failure. The ``sdev`` parameter specifies both the target
  22064. + * device of the request and by association the controller via which the
  22065. + * request is sent.
  22066. *
  22067. * Refer to ssam_request_sync_onstack() for more details on the behavior of
  22068. * the generated function.
  22069. */
  22070. #define SSAM_DEFINE_SYNC_REQUEST_CL_N(name, spec...) \
  22071. SSAM_DEFINE_SYNC_REQUEST_MD_N(__raw_##name, spec) \
  22072. - int name(struct ssam_device *sdev) \
  22073. + static int name(struct ssam_device *sdev) \
  22074. { \
  22075. return __raw_##name(sdev->ctrl, sdev->uid.target, \
  22076. sdev->uid.instance); \
  22077. @@ -368,19 +369,19 @@ void ssam_device_driver_unregister(struct ssam_device_driver *d);
  22078. * itself, returning once the request has been fully completed. The required
  22079. * transport buffer will be allocated on the stack.
  22080. *
  22081. - * The generated function is defined as ``int name(struct ssam_device *sdev,
  22082. - * const atype *arg)``, returning the status of the request, which is zero on
  22083. - * success and negative on failure. The ``sdev`` parameter specifies both the
  22084. - * target device of the request and by association the controller via which
  22085. - * the request is sent. The request's argument is specified via the ``arg``
  22086. - * pointer.
  22087. + * The generated function is defined as ``static int name(struct ssam_device
  22088. + * *sdev, const atype *arg)``, returning the status of the request, which is
  22089. + * zero on success and negative on failure. The ``sdev`` parameter specifies
  22090. + * both the target device of the request and by association the controller via
  22091. + * which the request is sent. The request's argument is specified via the
  22092. + * ``arg`` pointer.
  22093. *
  22094. * Refer to ssam_request_sync_onstack() for more details on the behavior of
  22095. * the generated function.
  22096. */
  22097. #define SSAM_DEFINE_SYNC_REQUEST_CL_W(name, atype, spec...) \
  22098. SSAM_DEFINE_SYNC_REQUEST_MD_W(__raw_##name, atype, spec) \
  22099. - int name(struct ssam_device *sdev, const atype *arg) \
  22100. + static int name(struct ssam_device *sdev, const atype *arg) \
  22101. { \
  22102. return __raw_##name(sdev->ctrl, sdev->uid.target, \
  22103. sdev->uid.instance, arg); \
  22104. @@ -402,8 +403,8 @@ void ssam_device_driver_unregister(struct ssam_device_driver *d);
  22105. * itself, returning once the request has been fully completed. The required
  22106. * transport buffer will be allocated on the stack.
  22107. *
  22108. - * The generated function is defined as ``int name(struct ssam_device *sdev,
  22109. - * rtype *ret)``, returning the status of the request, which is zero on
  22110. + * The generated function is defined as ``static int name(struct ssam_device
  22111. + * *sdev, rtype *ret)``, returning the status of the request, which is zero on
  22112. * success and negative on failure. The ``sdev`` parameter specifies both the
  22113. * target device of the request and by association the controller via which
  22114. * the request is sent. The request's return value is written to the memory
  22115. @@ -414,7 +415,7 @@ void ssam_device_driver_unregister(struct ssam_device_driver *d);
  22116. */
  22117. #define SSAM_DEFINE_SYNC_REQUEST_CL_R(name, rtype, spec...) \
  22118. SSAM_DEFINE_SYNC_REQUEST_MD_R(__raw_##name, rtype, spec) \
  22119. - int name(struct ssam_device *sdev, rtype *ret) \
  22120. + static int name(struct ssam_device *sdev, rtype *ret) \
  22121. { \
  22122. return __raw_##name(sdev->ctrl, sdev->uid.target, \
  22123. sdev->uid.instance, ret); \
  22124. --
  22125. 2.31.0