123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990 |
- From 30367636930864f71b2bd462adedcf8484313864 Mon Sep 17 00:00:00 2001
- From: Linus Walleij <[email protected]>
- Date: Sun, 23 Oct 2022 16:47:06 +0200
- Subject: [PATCH 02/29] usb: fotg210: Collect pieces of dual mode controller
- The Faraday FOTG210 is a dual-mode OTG USB controller that can
- act as host, peripheral or both. To be able to probe from one
- hardware description and to follow the pattern of other dual-
- mode controllers such as MUSB or MTU3 we need to collect the
- two, currently completely separate drivers in the same
- directory.
- After this, users need to select the main symbol USB_FOTG210
- and then each respective subdriver. We pave the road to
- compile both drivers into the same kernel and select the
- one we want to use at probe() time, and possibly add OTG
- support in the end.
- This patch doesn't do much more than create the new symbol
- and collect the drivers in one place. We also add a comment
- for the section of dual-mode controllers in the Kconfig
- file so people can see what these selections are about.
- Also add myself as maintainer as there has been little
- response on my patches to these drivers.
- Cc: Fabian Vogt <[email protected]>
- Cc: Yuan-Hsin Chen <[email protected]>
- Cc: Felipe Balbi <[email protected]>
- Signed-off-by: Linus Walleij <[email protected]>
- Link: https://lore.kernel.org/r/[email protected]
- Signed-off-by: Greg Kroah-Hartman <[email protected]>
- ---
- --- a/drivers/usb/Kconfig
- +++ b/drivers/usb/Kconfig
- @@ -111,8 +111,12 @@ source "drivers/usb/usbip/Kconfig"
-
- endif
-
- +comment "USB dual-mode controller drivers"
- +
- source "drivers/usb/cdns3/Kconfig"
-
- +source "drivers/usb/fotg210/Kconfig"
- +
- source "drivers/usb/mtu3/Kconfig"
-
- source "drivers/usb/musb/Kconfig"
- --- a/drivers/usb/Makefile
- +++ b/drivers/usb/Makefile
- @@ -17,6 +17,8 @@ obj-$(CONFIG_USB_CDNS_SUPPORT) += cdns3/
- obj-$(CONFIG_USB_CDNS3) += cdns3/
- obj-$(CONFIG_USB_CDNSP_PCI) += cdns3/
-
- +obj-$(CONFIG_USB_FOTG210) += fotg210/
- +
- obj-$(CONFIG_USB_MON) += mon/
- obj-$(CONFIG_USB_MTU3) += mtu3/
-
- --- /dev/null
- +++ b/drivers/usb/fotg210/Kconfig
- @@ -0,0 +1,36 @@
- +# SPDX-License-Identifier: GPL-2.0
- +
- +config USB_FOTG210
- + tristate "Faraday FOTG210 USB2 Dual Role controller"
- + depends on USB || USB_GADGET
- + depends on HAS_DMA && HAS_IOMEM
- + default ARCH_GEMINI
- + help
- + Faraday FOTG210 is a dual-mode USB controller that can act
- + in both host controller and peripheral controller mode.
- +
- +if USB_FOTG210
- +
- +config USB_FOTG210_HCD
- + tristate "Faraday FOTG210 USB Host Controller support"
- + depends on USB
- + help
- + Faraday FOTG210 is an OTG controller which can be configured as
- + an USB2.0 host. It is designed to meet USB2.0 EHCI specification
- + with minor modification.
- +
- + To compile this driver as a module, choose M here: the
- + module will be called fotg210-hcd.
- +
- +config USB_FOTG210_UDC
- + depends on USB_GADGET
- + tristate "Faraday FOTG210 USB Peripheral Controller support"
- + help
- + Faraday USB2.0 OTG controller which can be configured as
- + high speed or full speed USB device. This driver suppports
- + Bulk Transfer so far.
- +
- + Say "y" to link the driver statically, or "m" to build a
- + dynamically linked module called "fotg210-udc".
- +
- +endif
- --- /dev/null
- +++ b/drivers/usb/fotg210/Makefile
- @@ -0,0 +1,3 @@
- +# SPDX-License-Identifier: GPL-2.0
- +obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
- +obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
- --- a/drivers/usb/host/fotg210-hcd.c
- +++ /dev/null
- @@ -1,5724 +0,0 @@
- -// SPDX-License-Identifier: GPL-2.0+
- -/* Faraday FOTG210 EHCI-like driver
- - *
- - * Copyright (c) 2013 Faraday Technology Corporation
- - *
- - * Author: Yuan-Hsin Chen <[email protected]>
- - * Feng-Hsin Chiang <[email protected]>
- - * Po-Yu Chuang <[email protected]>
- - *
- - * Most of code borrowed from the Linux-3.7 EHCI driver
- - */
- -#include <linux/module.h>
- -#include <linux/of.h>
- -#include <linux/device.h>
- -#include <linux/dmapool.h>
- -#include <linux/kernel.h>
- -#include <linux/delay.h>
- -#include <linux/ioport.h>
- -#include <linux/sched.h>
- -#include <linux/vmalloc.h>
- -#include <linux/errno.h>
- -#include <linux/init.h>
- -#include <linux/hrtimer.h>
- -#include <linux/list.h>
- -#include <linux/interrupt.h>
- -#include <linux/usb.h>
- -#include <linux/usb/hcd.h>
- -#include <linux/moduleparam.h>
- -#include <linux/dma-mapping.h>
- -#include <linux/debugfs.h>
- -#include <linux/slab.h>
- -#include <linux/uaccess.h>
- -#include <linux/platform_device.h>
- -#include <linux/io.h>
- -#include <linux/iopoll.h>
- -#include <linux/clk.h>
- -
- -#include <asm/byteorder.h>
- -#include <asm/irq.h>
- -#include <asm/unaligned.h>
- -
- -#define DRIVER_AUTHOR "Yuan-Hsin Chen"
- -#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver"
- -static const char hcd_name[] = "fotg210_hcd";
- -
- -#undef FOTG210_URB_TRACE
- -#define FOTG210_STATS
- -
- -/* magic numbers that can affect system performance */
- -#define FOTG210_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
- -#define FOTG210_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
- -#define FOTG210_TUNE_RL_TT 0
- -#define FOTG210_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
- -#define FOTG210_TUNE_MULT_TT 1
- -
- -/* Some drivers think it's safe to schedule isochronous transfers more than 256
- - * ms into the future (partly as a result of an old bug in the scheduling
- - * code). In an attempt to avoid trouble, we will use a minimum scheduling
- - * length of 512 frames instead of 256.
- - */
- -#define FOTG210_TUNE_FLS 1 /* (medium) 512-frame schedule */
- -
- -/* Initial IRQ latency: faster than hw default */
- -static int log2_irq_thresh; /* 0 to 6 */
- -module_param(log2_irq_thresh, int, S_IRUGO);
- -MODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
- -
- -/* initial park setting: slower than hw default */
- -static unsigned park;
- -module_param(park, uint, S_IRUGO);
- -MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets");
- -
- -/* for link power management(LPM) feature */
- -static unsigned int hird;
- -module_param(hird, int, S_IRUGO);
- -MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
- -
- -#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
- -
- -#include "fotg210.h"
- -
- -#define fotg210_dbg(fotg210, fmt, args...) \
- - dev_dbg(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
- -#define fotg210_err(fotg210, fmt, args...) \
- - dev_err(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
- -#define fotg210_info(fotg210, fmt, args...) \
- - dev_info(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
- -#define fotg210_warn(fotg210, fmt, args...) \
- - dev_warn(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
- -
- -/* check the values in the HCSPARAMS register (host controller _Structural_
- - * parameters) see EHCI spec, Table 2-4 for each value
- - */
- -static void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label)
- -{
- - u32 params = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
- -
- - fotg210_dbg(fotg210, "%s hcs_params 0x%x ports=%d\n", label, params,
- - HCS_N_PORTS(params));
- -}
- -
- -/* check the values in the HCCPARAMS register (host controller _Capability_
- - * parameters) see EHCI Spec, Table 2-5 for each value
- - */
- -static void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label)
- -{
- - u32 params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
- -
- - fotg210_dbg(fotg210, "%s hcc_params %04x uframes %s%s\n", label,
- - params,
- - HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
- - HCC_CANPARK(params) ? " park" : "");
- -}
- -
- -static void __maybe_unused
- -dbg_qtd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd)
- -{
- - fotg210_dbg(fotg210, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
- - hc32_to_cpup(fotg210, &qtd->hw_next),
- - hc32_to_cpup(fotg210, &qtd->hw_alt_next),
- - hc32_to_cpup(fotg210, &qtd->hw_token),
- - hc32_to_cpup(fotg210, &qtd->hw_buf[0]));
- - if (qtd->hw_buf[1])
- - fotg210_dbg(fotg210, " p1=%08x p2=%08x p3=%08x p4=%08x\n",
- - hc32_to_cpup(fotg210, &qtd->hw_buf[1]),
- - hc32_to_cpup(fotg210, &qtd->hw_buf[2]),
- - hc32_to_cpup(fotg210, &qtd->hw_buf[3]),
- - hc32_to_cpup(fotg210, &qtd->hw_buf[4]));
- -}
- -
- -static void __maybe_unused
- -dbg_qh(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- -{
- - struct fotg210_qh_hw *hw = qh->hw;
- -
- - fotg210_dbg(fotg210, "%s qh %p n%08x info %x %x qtd %x\n", label, qh,
- - hw->hw_next, hw->hw_info1, hw->hw_info2,
- - hw->hw_current);
- -
- - dbg_qtd("overlay", fotg210, (struct fotg210_qtd *) &hw->hw_qtd_next);
- -}
- -
- -static void __maybe_unused
- -dbg_itd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
- -{
- - fotg210_dbg(fotg210, "%s[%d] itd %p, next %08x, urb %p\n", label,
- - itd->frame, itd, hc32_to_cpu(fotg210, itd->hw_next),
- - itd->urb);
- -
- - fotg210_dbg(fotg210,
- - " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
- - hc32_to_cpu(fotg210, itd->hw_transaction[0]),
- - hc32_to_cpu(fotg210, itd->hw_transaction[1]),
- - hc32_to_cpu(fotg210, itd->hw_transaction[2]),
- - hc32_to_cpu(fotg210, itd->hw_transaction[3]),
- - hc32_to_cpu(fotg210, itd->hw_transaction[4]),
- - hc32_to_cpu(fotg210, itd->hw_transaction[5]),
- - hc32_to_cpu(fotg210, itd->hw_transaction[6]),
- - hc32_to_cpu(fotg210, itd->hw_transaction[7]));
- -
- - fotg210_dbg(fotg210,
- - " buf: %08x %08x %08x %08x %08x %08x %08x\n",
- - hc32_to_cpu(fotg210, itd->hw_bufp[0]),
- - hc32_to_cpu(fotg210, itd->hw_bufp[1]),
- - hc32_to_cpu(fotg210, itd->hw_bufp[2]),
- - hc32_to_cpu(fotg210, itd->hw_bufp[3]),
- - hc32_to_cpu(fotg210, itd->hw_bufp[4]),
- - hc32_to_cpu(fotg210, itd->hw_bufp[5]),
- - hc32_to_cpu(fotg210, itd->hw_bufp[6]));
- -
- - fotg210_dbg(fotg210, " index: %d %d %d %d %d %d %d %d\n",
- - itd->index[0], itd->index[1], itd->index[2],
- - itd->index[3], itd->index[4], itd->index[5],
- - itd->index[6], itd->index[7]);
- -}
- -
- -static int __maybe_unused
- -dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
- -{
- - return scnprintf(buf, len, "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
- - label, label[0] ? " " : "", status,
- - (status & STS_ASS) ? " Async" : "",
- - (status & STS_PSS) ? " Periodic" : "",
- - (status & STS_RECL) ? " Recl" : "",
- - (status & STS_HALT) ? " Halt" : "",
- - (status & STS_IAA) ? " IAA" : "",
- - (status & STS_FATAL) ? " FATAL" : "",
- - (status & STS_FLR) ? " FLR" : "",
- - (status & STS_PCD) ? " PCD" : "",
- - (status & STS_ERR) ? " ERR" : "",
- - (status & STS_INT) ? " INT" : "");
- -}
- -
- -static int __maybe_unused
- -dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
- -{
- - return scnprintf(buf, len, "%s%sintrenable %02x%s%s%s%s%s%s",
- - label, label[0] ? " " : "", enable,
- - (enable & STS_IAA) ? " IAA" : "",
- - (enable & STS_FATAL) ? " FATAL" : "",
- - (enable & STS_FLR) ? " FLR" : "",
- - (enable & STS_PCD) ? " PCD" : "",
- - (enable & STS_ERR) ? " ERR" : "",
- - (enable & STS_INT) ? " INT" : "");
- -}
- -
- -static const char *const fls_strings[] = { "1024", "512", "256", "??" };
- -
- -static int dbg_command_buf(char *buf, unsigned len, const char *label,
- - u32 command)
- -{
- - return scnprintf(buf, len,
- - "%s%scommand %07x %s=%d ithresh=%d%s%s%s period=%s%s %s",
- - label, label[0] ? " " : "", command,
- - (command & CMD_PARK) ? " park" : "(park)",
- - CMD_PARK_CNT(command),
- - (command >> 16) & 0x3f,
- - (command & CMD_IAAD) ? " IAAD" : "",
- - (command & CMD_ASE) ? " Async" : "",
- - (command & CMD_PSE) ? " Periodic" : "",
- - fls_strings[(command >> 2) & 0x3],
- - (command & CMD_RESET) ? " Reset" : "",
- - (command & CMD_RUN) ? "RUN" : "HALT");
- -}
- -
- -static char *dbg_port_buf(char *buf, unsigned len, const char *label, int port,
- - u32 status)
- -{
- - char *sig;
- -
- - /* signaling state */
- - switch (status & (3 << 10)) {
- - case 0 << 10:
- - sig = "se0";
- - break;
- - case 1 << 10:
- - sig = "k";
- - break; /* low speed */
- - case 2 << 10:
- - sig = "j";
- - break;
- - default:
- - sig = "?";
- - break;
- - }
- -
- - scnprintf(buf, len, "%s%sport:%d status %06x %d sig=%s%s%s%s%s%s%s%s",
- - label, label[0] ? " " : "", port, status,
- - status >> 25, /*device address */
- - sig,
- - (status & PORT_RESET) ? " RESET" : "",
- - (status & PORT_SUSPEND) ? " SUSPEND" : "",
- - (status & PORT_RESUME) ? " RESUME" : "",
- - (status & PORT_PEC) ? " PEC" : "",
- - (status & PORT_PE) ? " PE" : "",
- - (status & PORT_CSC) ? " CSC" : "",
- - (status & PORT_CONNECT) ? " CONNECT" : "");
- -
- - return buf;
- -}
- -
- -/* functions have the "wrong" filename when they're output... */
- -#define dbg_status(fotg210, label, status) { \
- - char _buf[80]; \
- - dbg_status_buf(_buf, sizeof(_buf), label, status); \
- - fotg210_dbg(fotg210, "%s\n", _buf); \
- -}
- -
- -#define dbg_cmd(fotg210, label, command) { \
- - char _buf[80]; \
- - dbg_command_buf(_buf, sizeof(_buf), label, command); \
- - fotg210_dbg(fotg210, "%s\n", _buf); \
- -}
- -
- -#define dbg_port(fotg210, label, port, status) { \
- - char _buf[80]; \
- - fotg210_dbg(fotg210, "%s\n", \
- - dbg_port_buf(_buf, sizeof(_buf), label, port, status));\
- -}
- -
- -/* troubleshooting help: expose state in debugfs */
- -static int debug_async_open(struct inode *, struct file *);
- -static int debug_periodic_open(struct inode *, struct file *);
- -static int debug_registers_open(struct inode *, struct file *);
- -static int debug_async_open(struct inode *, struct file *);
- -
- -static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
- -static int debug_close(struct inode *, struct file *);
- -
- -static const struct file_operations debug_async_fops = {
- - .owner = THIS_MODULE,
- - .open = debug_async_open,
- - .read = debug_output,
- - .release = debug_close,
- - .llseek = default_llseek,
- -};
- -static const struct file_operations debug_periodic_fops = {
- - .owner = THIS_MODULE,
- - .open = debug_periodic_open,
- - .read = debug_output,
- - .release = debug_close,
- - .llseek = default_llseek,
- -};
- -static const struct file_operations debug_registers_fops = {
- - .owner = THIS_MODULE,
- - .open = debug_registers_open,
- - .read = debug_output,
- - .release = debug_close,
- - .llseek = default_llseek,
- -};
- -
- -static struct dentry *fotg210_debug_root;
- -
- -struct debug_buffer {
- - ssize_t (*fill_func)(struct debug_buffer *); /* fill method */
- - struct usb_bus *bus;
- - struct mutex mutex; /* protect filling of buffer */
- - size_t count; /* number of characters filled into buffer */
- - char *output_buf;
- - size_t alloc_size;
- -};
- -
- -static inline char speed_char(u32 scratch)
- -{
- - switch (scratch & (3 << 12)) {
- - case QH_FULL_SPEED:
- - return 'f';
- -
- - case QH_LOW_SPEED:
- - return 'l';
- -
- - case QH_HIGH_SPEED:
- - return 'h';
- -
- - default:
- - return '?';
- - }
- -}
- -
- -static inline char token_mark(struct fotg210_hcd *fotg210, __hc32 token)
- -{
- - __u32 v = hc32_to_cpu(fotg210, token);
- -
- - if (v & QTD_STS_ACTIVE)
- - return '*';
- - if (v & QTD_STS_HALT)
- - return '-';
- - if (!IS_SHORT_READ(v))
- - return ' ';
- - /* tries to advance through hw_alt_next */
- - return '/';
- -}
- -
- -static void qh_lines(struct fotg210_hcd *fotg210, struct fotg210_qh *qh,
- - char **nextp, unsigned *sizep)
- -{
- - u32 scratch;
- - u32 hw_curr;
- - struct fotg210_qtd *td;
- - unsigned temp;
- - unsigned size = *sizep;
- - char *next = *nextp;
- - char mark;
- - __le32 list_end = FOTG210_LIST_END(fotg210);
- - struct fotg210_qh_hw *hw = qh->hw;
- -
- - if (hw->hw_qtd_next == list_end) /* NEC does this */
- - mark = '@';
- - else
- - mark = token_mark(fotg210, hw->hw_token);
- - if (mark == '/') { /* qh_alt_next controls qh advance? */
- - if ((hw->hw_alt_next & QTD_MASK(fotg210)) ==
- - fotg210->async->hw->hw_alt_next)
- - mark = '#'; /* blocked */
- - else if (hw->hw_alt_next == list_end)
- - mark = '.'; /* use hw_qtd_next */
- - /* else alt_next points to some other qtd */
- - }
- - scratch = hc32_to_cpup(fotg210, &hw->hw_info1);
- - hw_curr = (mark == '*') ? hc32_to_cpup(fotg210, &hw->hw_current) : 0;
- - temp = scnprintf(next, size,
- - "qh/%p dev%d %cs ep%d %08x %08x(%08x%c %s nak%d)",
- - qh, scratch & 0x007f,
- - speed_char(scratch),
- - (scratch >> 8) & 0x000f,
- - scratch, hc32_to_cpup(fotg210, &hw->hw_info2),
- - hc32_to_cpup(fotg210, &hw->hw_token), mark,
- - (cpu_to_hc32(fotg210, QTD_TOGGLE) & hw->hw_token)
- - ? "data1" : "data0",
- - (hc32_to_cpup(fotg210, &hw->hw_alt_next) >> 1) & 0x0f);
- - size -= temp;
- - next += temp;
- -
- - /* hc may be modifying the list as we read it ... */
- - list_for_each_entry(td, &qh->qtd_list, qtd_list) {
- - scratch = hc32_to_cpup(fotg210, &td->hw_token);
- - mark = ' ';
- - if (hw_curr == td->qtd_dma)
- - mark = '*';
- - else if (hw->hw_qtd_next == cpu_to_hc32(fotg210, td->qtd_dma))
- - mark = '+';
- - else if (QTD_LENGTH(scratch)) {
- - if (td->hw_alt_next == fotg210->async->hw->hw_alt_next)
- - mark = '#';
- - else if (td->hw_alt_next != list_end)
- - mark = '/';
- - }
- - temp = snprintf(next, size,
- - "\n\t%p%c%s len=%d %08x urb %p",
- - td, mark, ({ char *tmp;
- - switch ((scratch>>8)&0x03) {
- - case 0:
- - tmp = "out";
- - break;
- - case 1:
- - tmp = "in";
- - break;
- - case 2:
- - tmp = "setup";
- - break;
- - default:
- - tmp = "?";
- - break;
- - } tmp; }),
- - (scratch >> 16) & 0x7fff,
- - scratch,
- - td->urb);
- - if (size < temp)
- - temp = size;
- - size -= temp;
- - next += temp;
- - }
- -
- - temp = snprintf(next, size, "\n");
- - if (size < temp)
- - temp = size;
- -
- - size -= temp;
- - next += temp;
- -
- - *sizep = size;
- - *nextp = next;
- -}
- -
- -static ssize_t fill_async_buffer(struct debug_buffer *buf)
- -{
- - struct usb_hcd *hcd;
- - struct fotg210_hcd *fotg210;
- - unsigned long flags;
- - unsigned temp, size;
- - char *next;
- - struct fotg210_qh *qh;
- -
- - hcd = bus_to_hcd(buf->bus);
- - fotg210 = hcd_to_fotg210(hcd);
- - next = buf->output_buf;
- - size = buf->alloc_size;
- -
- - *next = 0;
- -
- - /* dumps a snapshot of the async schedule.
- - * usually empty except for long-term bulk reads, or head.
- - * one QH per line, and TDs we know about
- - */
- - spin_lock_irqsave(&fotg210->lock, flags);
- - for (qh = fotg210->async->qh_next.qh; size > 0 && qh;
- - qh = qh->qh_next.qh)
- - qh_lines(fotg210, qh, &next, &size);
- - if (fotg210->async_unlink && size > 0) {
- - temp = scnprintf(next, size, "\nunlink =\n");
- - size -= temp;
- - next += temp;
- -
- - for (qh = fotg210->async_unlink; size > 0 && qh;
- - qh = qh->unlink_next)
- - qh_lines(fotg210, qh, &next, &size);
- - }
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- -
- - return strlen(buf->output_buf);
- -}
- -
- -/* count tds, get ep direction */
- -static unsigned output_buf_tds_dir(char *buf, struct fotg210_hcd *fotg210,
- - struct fotg210_qh_hw *hw, struct fotg210_qh *qh, unsigned size)
- -{
- - u32 scratch = hc32_to_cpup(fotg210, &hw->hw_info1);
- - struct fotg210_qtd *qtd;
- - char *type = "";
- - unsigned temp = 0;
- -
- - /* count tds, get ep direction */
- - list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
- - temp++;
- - switch ((hc32_to_cpu(fotg210, qtd->hw_token) >> 8) & 0x03) {
- - case 0:
- - type = "out";
- - continue;
- - case 1:
- - type = "in";
- - continue;
- - }
- - }
- -
- - return scnprintf(buf, size, "(%c%d ep%d%s [%d/%d] q%d p%d)",
- - speed_char(scratch), scratch & 0x007f,
- - (scratch >> 8) & 0x000f, type, qh->usecs,
- - qh->c_usecs, temp, (scratch >> 16) & 0x7ff);
- -}
- -
- -#define DBG_SCHED_LIMIT 64
- -static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
- -{
- - struct usb_hcd *hcd;
- - struct fotg210_hcd *fotg210;
- - unsigned long flags;
- - union fotg210_shadow p, *seen;
- - unsigned temp, size, seen_count;
- - char *next;
- - unsigned i;
- - __hc32 tag;
- -
- - seen = kmalloc_array(DBG_SCHED_LIMIT, sizeof(*seen), GFP_ATOMIC);
- - if (!seen)
- - return 0;
- -
- - seen_count = 0;
- -
- - hcd = bus_to_hcd(buf->bus);
- - fotg210 = hcd_to_fotg210(hcd);
- - next = buf->output_buf;
- - size = buf->alloc_size;
- -
- - temp = scnprintf(next, size, "size = %d\n", fotg210->periodic_size);
- - size -= temp;
- - next += temp;
- -
- - /* dump a snapshot of the periodic schedule.
- - * iso changes, interrupt usually doesn't.
- - */
- - spin_lock_irqsave(&fotg210->lock, flags);
- - for (i = 0; i < fotg210->periodic_size; i++) {
- - p = fotg210->pshadow[i];
- - if (likely(!p.ptr))
- - continue;
- -
- - tag = Q_NEXT_TYPE(fotg210, fotg210->periodic[i]);
- -
- - temp = scnprintf(next, size, "%4d: ", i);
- - size -= temp;
- - next += temp;
- -
- - do {
- - struct fotg210_qh_hw *hw;
- -
- - switch (hc32_to_cpu(fotg210, tag)) {
- - case Q_TYPE_QH:
- - hw = p.qh->hw;
- - temp = scnprintf(next, size, " qh%d-%04x/%p",
- - p.qh->period,
- - hc32_to_cpup(fotg210,
- - &hw->hw_info2)
- - /* uframe masks */
- - & (QH_CMASK | QH_SMASK),
- - p.qh);
- - size -= temp;
- - next += temp;
- - /* don't repeat what follows this qh */
- - for (temp = 0; temp < seen_count; temp++) {
- - if (seen[temp].ptr != p.ptr)
- - continue;
- - if (p.qh->qh_next.ptr) {
- - temp = scnprintf(next, size,
- - " ...");
- - size -= temp;
- - next += temp;
- - }
- - break;
- - }
- - /* show more info the first time around */
- - if (temp == seen_count) {
- - temp = output_buf_tds_dir(next,
- - fotg210, hw,
- - p.qh, size);
- -
- - if (seen_count < DBG_SCHED_LIMIT)
- - seen[seen_count++].qh = p.qh;
- - } else
- - temp = 0;
- - tag = Q_NEXT_TYPE(fotg210, hw->hw_next);
- - p = p.qh->qh_next;
- - break;
- - case Q_TYPE_FSTN:
- - temp = scnprintf(next, size,
- - " fstn-%8x/%p",
- - p.fstn->hw_prev, p.fstn);
- - tag = Q_NEXT_TYPE(fotg210, p.fstn->hw_next);
- - p = p.fstn->fstn_next;
- - break;
- - case Q_TYPE_ITD:
- - temp = scnprintf(next, size,
- - " itd/%p", p.itd);
- - tag = Q_NEXT_TYPE(fotg210, p.itd->hw_next);
- - p = p.itd->itd_next;
- - break;
- - }
- - size -= temp;
- - next += temp;
- - } while (p.ptr);
- -
- - temp = scnprintf(next, size, "\n");
- - size -= temp;
- - next += temp;
- - }
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - kfree(seen);
- -
- - return buf->alloc_size - size;
- -}
- -#undef DBG_SCHED_LIMIT
- -
- -static const char *rh_state_string(struct fotg210_hcd *fotg210)
- -{
- - switch (fotg210->rh_state) {
- - case FOTG210_RH_HALTED:
- - return "halted";
- - case FOTG210_RH_SUSPENDED:
- - return "suspended";
- - case FOTG210_RH_RUNNING:
- - return "running";
- - case FOTG210_RH_STOPPING:
- - return "stopping";
- - }
- - return "?";
- -}
- -
- -static ssize_t fill_registers_buffer(struct debug_buffer *buf)
- -{
- - struct usb_hcd *hcd;
- - struct fotg210_hcd *fotg210;
- - unsigned long flags;
- - unsigned temp, size, i;
- - char *next, scratch[80];
- - static const char fmt[] = "%*s\n";
- - static const char label[] = "";
- -
- - hcd = bus_to_hcd(buf->bus);
- - fotg210 = hcd_to_fotg210(hcd);
- - next = buf->output_buf;
- - size = buf->alloc_size;
- -
- - spin_lock_irqsave(&fotg210->lock, flags);
- -
- - if (!HCD_HW_ACCESSIBLE(hcd)) {
- - size = scnprintf(next, size,
- - "bus %s, device %s\n"
- - "%s\n"
- - "SUSPENDED(no register access)\n",
- - hcd->self.controller->bus->name,
- - dev_name(hcd->self.controller),
- - hcd->product_desc);
- - goto done;
- - }
- -
- - /* Capability Registers */
- - i = HC_VERSION(fotg210, fotg210_readl(fotg210,
- - &fotg210->caps->hc_capbase));
- - temp = scnprintf(next, size,
- - "bus %s, device %s\n"
- - "%s\n"
- - "EHCI %x.%02x, rh state %s\n",
- - hcd->self.controller->bus->name,
- - dev_name(hcd->self.controller),
- - hcd->product_desc,
- - i >> 8, i & 0x0ff, rh_state_string(fotg210));
- - size -= temp;
- - next += temp;
- -
- - /* FIXME interpret both types of params */
- - i = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
- - temp = scnprintf(next, size, "structural params 0x%08x\n", i);
- - size -= temp;
- - next += temp;
- -
- - i = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
- - temp = scnprintf(next, size, "capability params 0x%08x\n", i);
- - size -= temp;
- - next += temp;
- -
- - /* Operational Registers */
- - temp = dbg_status_buf(scratch, sizeof(scratch), label,
- - fotg210_readl(fotg210, &fotg210->regs->status));
- - temp = scnprintf(next, size, fmt, temp, scratch);
- - size -= temp;
- - next += temp;
- -
- - temp = dbg_command_buf(scratch, sizeof(scratch), label,
- - fotg210_readl(fotg210, &fotg210->regs->command));
- - temp = scnprintf(next, size, fmt, temp, scratch);
- - size -= temp;
- - next += temp;
- -
- - temp = dbg_intr_buf(scratch, sizeof(scratch), label,
- - fotg210_readl(fotg210, &fotg210->regs->intr_enable));
- - temp = scnprintf(next, size, fmt, temp, scratch);
- - size -= temp;
- - next += temp;
- -
- - temp = scnprintf(next, size, "uframe %04x\n",
- - fotg210_read_frame_index(fotg210));
- - size -= temp;
- - next += temp;
- -
- - if (fotg210->async_unlink) {
- - temp = scnprintf(next, size, "async unlink qh %p\n",
- - fotg210->async_unlink);
- - size -= temp;
- - next += temp;
- - }
- -
- -#ifdef FOTG210_STATS
- - temp = scnprintf(next, size,
- - "irq normal %ld err %ld iaa %ld(lost %ld)\n",
- - fotg210->stats.normal, fotg210->stats.error,
- - fotg210->stats.iaa, fotg210->stats.lost_iaa);
- - size -= temp;
- - next += temp;
- -
- - temp = scnprintf(next, size, "complete %ld unlink %ld\n",
- - fotg210->stats.complete, fotg210->stats.unlink);
- - size -= temp;
- - next += temp;
- -#endif
- -
- -done:
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- -
- - return buf->alloc_size - size;
- -}
- -
- -static struct debug_buffer
- -*alloc_buffer(struct usb_bus *bus, ssize_t (*fill_func)(struct debug_buffer *))
- -{
- - struct debug_buffer *buf;
- -
- - buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
- -
- - if (buf) {
- - buf->bus = bus;
- - buf->fill_func = fill_func;
- - mutex_init(&buf->mutex);
- - buf->alloc_size = PAGE_SIZE;
- - }
- -
- - return buf;
- -}
- -
- -static int fill_buffer(struct debug_buffer *buf)
- -{
- - int ret = 0;
- -
- - if (!buf->output_buf)
- - buf->output_buf = vmalloc(buf->alloc_size);
- -
- - if (!buf->output_buf) {
- - ret = -ENOMEM;
- - goto out;
- - }
- -
- - ret = buf->fill_func(buf);
- -
- - if (ret >= 0) {
- - buf->count = ret;
- - ret = 0;
- - }
- -
- -out:
- - return ret;
- -}
- -
- -static ssize_t debug_output(struct file *file, char __user *user_buf,
- - size_t len, loff_t *offset)
- -{
- - struct debug_buffer *buf = file->private_data;
- - int ret = 0;
- -
- - mutex_lock(&buf->mutex);
- - if (buf->count == 0) {
- - ret = fill_buffer(buf);
- - if (ret != 0) {
- - mutex_unlock(&buf->mutex);
- - goto out;
- - }
- - }
- - mutex_unlock(&buf->mutex);
- -
- - ret = simple_read_from_buffer(user_buf, len, offset,
- - buf->output_buf, buf->count);
- -
- -out:
- - return ret;
- -
- -}
- -
- -static int debug_close(struct inode *inode, struct file *file)
- -{
- - struct debug_buffer *buf = file->private_data;
- -
- - if (buf) {
- - vfree(buf->output_buf);
- - kfree(buf);
- - }
- -
- - return 0;
- -}
- -static int debug_async_open(struct inode *inode, struct file *file)
- -{
- - file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
- -
- - return file->private_data ? 0 : -ENOMEM;
- -}
- -
- -static int debug_periodic_open(struct inode *inode, struct file *file)
- -{
- - struct debug_buffer *buf;
- -
- - buf = alloc_buffer(inode->i_private, fill_periodic_buffer);
- - if (!buf)
- - return -ENOMEM;
- -
- - buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE;
- - file->private_data = buf;
- - return 0;
- -}
- -
- -static int debug_registers_open(struct inode *inode, struct file *file)
- -{
- - file->private_data = alloc_buffer(inode->i_private,
- - fill_registers_buffer);
- -
- - return file->private_data ? 0 : -ENOMEM;
- -}
- -
- -static inline void create_debug_files(struct fotg210_hcd *fotg210)
- -{
- - struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
- - struct dentry *root;
- -
- - root = debugfs_create_dir(bus->bus_name, fotg210_debug_root);
- -
- - debugfs_create_file("async", S_IRUGO, root, bus, &debug_async_fops);
- - debugfs_create_file("periodic", S_IRUGO, root, bus,
- - &debug_periodic_fops);
- - debugfs_create_file("registers", S_IRUGO, root, bus,
- - &debug_registers_fops);
- -}
- -
- -static inline void remove_debug_files(struct fotg210_hcd *fotg210)
- -{
- - struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
- -
- - debugfs_lookup_and_remove(bus->bus_name, fotg210_debug_root);
- -}
- -
- -/* handshake - spin reading hc until handshake completes or fails
- - * @ptr: address of hc register to be read
- - * @mask: bits to look at in result of read
- - * @done: value of those bits when handshake succeeds
- - * @usec: timeout in microseconds
- - *
- - * Returns negative errno, or zero on success
- - *
- - * Success happens when the "mask" bits have the specified value (hardware
- - * handshake done). There are two failure modes: "usec" have passed (major
- - * hardware flakeout), or the register reads as all-ones (hardware removed).
- - *
- - * That last failure should_only happen in cases like physical cardbus eject
- - * before driver shutdown. But it also seems to be caused by bugs in cardbus
- - * bridge shutdown: shutting down the bridge before the devices using it.
- - */
- -static int handshake(struct fotg210_hcd *fotg210, void __iomem *ptr,
- - u32 mask, u32 done, int usec)
- -{
- - u32 result;
- - int ret;
- -
- - ret = readl_poll_timeout_atomic(ptr, result,
- - ((result & mask) == done ||
- - result == U32_MAX), 1, usec);
- - if (result == U32_MAX) /* card removed */
- - return -ENODEV;
- -
- - return ret;
- -}
- -
- -/* Force HC to halt state from unknown (EHCI spec section 2.3).
- - * Must be called with interrupts enabled and the lock not held.
- - */
- -static int fotg210_halt(struct fotg210_hcd *fotg210)
- -{
- - u32 temp;
- -
- - spin_lock_irq(&fotg210->lock);
- -
- - /* disable any irqs left enabled by previous code */
- - fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
- -
- - /*
- - * This routine gets called during probe before fotg210->command
- - * has been initialized, so we can't rely on its value.
- - */
- - fotg210->command &= ~CMD_RUN;
- - temp = fotg210_readl(fotg210, &fotg210->regs->command);
- - temp &= ~(CMD_RUN | CMD_IAAD);
- - fotg210_writel(fotg210, temp, &fotg210->regs->command);
- -
- - spin_unlock_irq(&fotg210->lock);
- - synchronize_irq(fotg210_to_hcd(fotg210)->irq);
- -
- - return handshake(fotg210, &fotg210->regs->status,
- - STS_HALT, STS_HALT, 16 * 125);
- -}
- -
- -/* Reset a non-running (STS_HALT == 1) controller.
- - * Must be called with interrupts enabled and the lock not held.
- - */
- -static int fotg210_reset(struct fotg210_hcd *fotg210)
- -{
- - int retval;
- - u32 command = fotg210_readl(fotg210, &fotg210->regs->command);
- -
- - /* If the EHCI debug controller is active, special care must be
- - * taken before and after a host controller reset
- - */
- - if (fotg210->debug && !dbgp_reset_prep(fotg210_to_hcd(fotg210)))
- - fotg210->debug = NULL;
- -
- - command |= CMD_RESET;
- - dbg_cmd(fotg210, "reset", command);
- - fotg210_writel(fotg210, command, &fotg210->regs->command);
- - fotg210->rh_state = FOTG210_RH_HALTED;
- - fotg210->next_statechange = jiffies;
- - retval = handshake(fotg210, &fotg210->regs->command,
- - CMD_RESET, 0, 250 * 1000);
- -
- - if (retval)
- - return retval;
- -
- - if (fotg210->debug)
- - dbgp_external_startup(fotg210_to_hcd(fotg210));
- -
- - fotg210->port_c_suspend = fotg210->suspended_ports =
- - fotg210->resuming_ports = 0;
- - return retval;
- -}
- -
- -/* Idle the controller (turn off the schedules).
- - * Must be called with interrupts enabled and the lock not held.
- - */
- -static void fotg210_quiesce(struct fotg210_hcd *fotg210)
- -{
- - u32 temp;
- -
- - if (fotg210->rh_state != FOTG210_RH_RUNNING)
- - return;
- -
- - /* wait for any schedule enables/disables to take effect */
- - temp = (fotg210->command << 10) & (STS_ASS | STS_PSS);
- - handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, temp,
- - 16 * 125);
- -
- - /* then disable anything that's still active */
- - spin_lock_irq(&fotg210->lock);
- - fotg210->command &= ~(CMD_ASE | CMD_PSE);
- - fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
- - spin_unlock_irq(&fotg210->lock);
- -
- - /* hardware can take 16 microframes to turn off ... */
- - handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, 0,
- - 16 * 125);
- -}
- -
- -static void end_unlink_async(struct fotg210_hcd *fotg210);
- -static void unlink_empty_async(struct fotg210_hcd *fotg210);
- -static void fotg210_work(struct fotg210_hcd *fotg210);
- -static void start_unlink_intr(struct fotg210_hcd *fotg210,
- - struct fotg210_qh *qh);
- -static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
- -
- -/* Set a bit in the USBCMD register */
- -static void fotg210_set_command_bit(struct fotg210_hcd *fotg210, u32 bit)
- -{
- - fotg210->command |= bit;
- - fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
- -
- - /* unblock posted write */
- - fotg210_readl(fotg210, &fotg210->regs->command);
- -}
- -
- -/* Clear a bit in the USBCMD register */
- -static void fotg210_clear_command_bit(struct fotg210_hcd *fotg210, u32 bit)
- -{
- - fotg210->command &= ~bit;
- - fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
- -
- - /* unblock posted write */
- - fotg210_readl(fotg210, &fotg210->regs->command);
- -}
- -
- -/* EHCI timer support... Now using hrtimers.
- - *
- - * Lots of different events are triggered from fotg210->hrtimer. Whenever
- - * the timer routine runs, it checks each possible event; events that are
- - * currently enabled and whose expiration time has passed get handled.
- - * The set of enabled events is stored as a collection of bitflags in
- - * fotg210->enabled_hrtimer_events, and they are numbered in order of
- - * increasing delay values (ranging between 1 ms and 100 ms).
- - *
- - * Rather than implementing a sorted list or tree of all pending events,
- - * we keep track only of the lowest-numbered pending event, in
- - * fotg210->next_hrtimer_event. Whenever fotg210->hrtimer gets restarted, its
- - * expiration time is set to the timeout value for this event.
- - *
- - * As a result, events might not get handled right away; the actual delay
- - * could be anywhere up to twice the requested delay. This doesn't
- - * matter, because none of the events are especially time-critical. The
- - * ones that matter most all have a delay of 1 ms, so they will be
- - * handled after 2 ms at most, which is okay. In addition to this, we
- - * allow for an expiration range of 1 ms.
- - */
- -
- -/* Delay lengths for the hrtimer event types.
- - * Keep this list sorted by delay length, in the same order as
- - * the event types indexed by enum fotg210_hrtimer_event in fotg210.h.
- - */
- -static unsigned event_delays_ns[] = {
- - 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_ASS */
- - 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_PSS */
- - 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_DEAD */
- - 1125 * NSEC_PER_USEC, /* FOTG210_HRTIMER_UNLINK_INTR */
- - 2 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_FREE_ITDS */
- - 6 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_ASYNC_UNLINKS */
- - 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IAA_WATCHDOG */
- - 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_PERIODIC */
- - 15 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_ASYNC */
- - 100 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IO_WATCHDOG */
- -};
- -
- -/* Enable a pending hrtimer event */
- -static void fotg210_enable_event(struct fotg210_hcd *fotg210, unsigned event,
- - bool resched)
- -{
- - ktime_t *timeout = &fotg210->hr_timeouts[event];
- -
- - if (resched)
- - *timeout = ktime_add(ktime_get(), event_delays_ns[event]);
- - fotg210->enabled_hrtimer_events |= (1 << event);
- -
- - /* Track only the lowest-numbered pending event */
- - if (event < fotg210->next_hrtimer_event) {
- - fotg210->next_hrtimer_event = event;
- - hrtimer_start_range_ns(&fotg210->hrtimer, *timeout,
- - NSEC_PER_MSEC, HRTIMER_MODE_ABS);
- - }
- -}
- -
- -
- -/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */
- -static void fotg210_poll_ASS(struct fotg210_hcd *fotg210)
- -{
- - unsigned actual, want;
- -
- - /* Don't enable anything if the controller isn't running (e.g., died) */
- - if (fotg210->rh_state != FOTG210_RH_RUNNING)
- - return;
- -
- - want = (fotg210->command & CMD_ASE) ? STS_ASS : 0;
- - actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_ASS;
- -
- - if (want != actual) {
- -
- - /* Poll again later, but give up after about 20 ms */
- - if (fotg210->ASS_poll_count++ < 20) {
- - fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_ASS,
- - true);
- - return;
- - }
- - fotg210_dbg(fotg210, "Waited too long for the async schedule status (%x/%x), giving up\n",
- - want, actual);
- - }
- - fotg210->ASS_poll_count = 0;
- -
- - /* The status is up-to-date; restart or stop the schedule as needed */
- - if (want == 0) { /* Stopped */
- - if (fotg210->async_count > 0)
- - fotg210_set_command_bit(fotg210, CMD_ASE);
- -
- - } else { /* Running */
- - if (fotg210->async_count == 0) {
- -
- - /* Turn off the schedule after a while */
- - fotg210_enable_event(fotg210,
- - FOTG210_HRTIMER_DISABLE_ASYNC,
- - true);
- - }
- - }
- -}
- -
- -/* Turn off the async schedule after a brief delay */
- -static void fotg210_disable_ASE(struct fotg210_hcd *fotg210)
- -{
- - fotg210_clear_command_bit(fotg210, CMD_ASE);
- -}
- -
- -
- -/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
- -static void fotg210_poll_PSS(struct fotg210_hcd *fotg210)
- -{
- - unsigned actual, want;
- -
- - /* Don't do anything if the controller isn't running (e.g., died) */
- - if (fotg210->rh_state != FOTG210_RH_RUNNING)
- - return;
- -
- - want = (fotg210->command & CMD_PSE) ? STS_PSS : 0;
- - actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_PSS;
- -
- - if (want != actual) {
- -
- - /* Poll again later, but give up after about 20 ms */
- - if (fotg210->PSS_poll_count++ < 20) {
- - fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_PSS,
- - true);
- - return;
- - }
- - fotg210_dbg(fotg210, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
- - want, actual);
- - }
- - fotg210->PSS_poll_count = 0;
- -
- - /* The status is up-to-date; restart or stop the schedule as needed */
- - if (want == 0) { /* Stopped */
- - if (fotg210->periodic_count > 0)
- - fotg210_set_command_bit(fotg210, CMD_PSE);
- -
- - } else { /* Running */
- - if (fotg210->periodic_count == 0) {
- -
- - /* Turn off the schedule after a while */
- - fotg210_enable_event(fotg210,
- - FOTG210_HRTIMER_DISABLE_PERIODIC,
- - true);
- - }
- - }
- -}
- -
- -/* Turn off the periodic schedule after a brief delay */
- -static void fotg210_disable_PSE(struct fotg210_hcd *fotg210)
- -{
- - fotg210_clear_command_bit(fotg210, CMD_PSE);
- -}
- -
- -
- -/* Poll the STS_HALT status bit; see when a dead controller stops */
- -static void fotg210_handle_controller_death(struct fotg210_hcd *fotg210)
- -{
- - if (!(fotg210_readl(fotg210, &fotg210->regs->status) & STS_HALT)) {
- -
- - /* Give up after a few milliseconds */
- - if (fotg210->died_poll_count++ < 5) {
- - /* Try again later */
- - fotg210_enable_event(fotg210,
- - FOTG210_HRTIMER_POLL_DEAD, true);
- - return;
- - }
- - fotg210_warn(fotg210, "Waited too long for the controller to stop, giving up\n");
- - }
- -
- - /* Clean up the mess */
- - fotg210->rh_state = FOTG210_RH_HALTED;
- - fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
- - fotg210_work(fotg210);
- - end_unlink_async(fotg210);
- -
- - /* Not in process context, so don't try to reset the controller */
- -}
- -
- -
- -/* Handle unlinked interrupt QHs once they are gone from the hardware */
- -static void fotg210_handle_intr_unlinks(struct fotg210_hcd *fotg210)
- -{
- - bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING);
- -
- - /*
- - * Process all the QHs on the intr_unlink list that were added
- - * before the current unlink cycle began. The list is in
- - * temporal order, so stop when we reach the first entry in the
- - * current cycle. But if the root hub isn't running then
- - * process all the QHs on the list.
- - */
- - fotg210->intr_unlinking = true;
- - while (fotg210->intr_unlink) {
- - struct fotg210_qh *qh = fotg210->intr_unlink;
- -
- - if (!stopped && qh->unlink_cycle == fotg210->intr_unlink_cycle)
- - break;
- - fotg210->intr_unlink = qh->unlink_next;
- - qh->unlink_next = NULL;
- - end_unlink_intr(fotg210, qh);
- - }
- -
- - /* Handle remaining entries later */
- - if (fotg210->intr_unlink) {
- - fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
- - true);
- - ++fotg210->intr_unlink_cycle;
- - }
- - fotg210->intr_unlinking = false;
- -}
- -
- -
- -/* Start another free-iTDs/siTDs cycle */
- -static void start_free_itds(struct fotg210_hcd *fotg210)
- -{
- - if (!(fotg210->enabled_hrtimer_events &
- - BIT(FOTG210_HRTIMER_FREE_ITDS))) {
- - fotg210->last_itd_to_free = list_entry(
- - fotg210->cached_itd_list.prev,
- - struct fotg210_itd, itd_list);
- - fotg210_enable_event(fotg210, FOTG210_HRTIMER_FREE_ITDS, true);
- - }
- -}
- -
- -/* Wait for controller to stop using old iTDs and siTDs */
- -static void end_free_itds(struct fotg210_hcd *fotg210)
- -{
- - struct fotg210_itd *itd, *n;
- -
- - if (fotg210->rh_state < FOTG210_RH_RUNNING)
- - fotg210->last_itd_to_free = NULL;
- -
- - list_for_each_entry_safe(itd, n, &fotg210->cached_itd_list, itd_list) {
- - list_del(&itd->itd_list);
- - dma_pool_free(fotg210->itd_pool, itd, itd->itd_dma);
- - if (itd == fotg210->last_itd_to_free)
- - break;
- - }
- -
- - if (!list_empty(&fotg210->cached_itd_list))
- - start_free_itds(fotg210);
- -}
- -
- -
- -/* Handle lost (or very late) IAA interrupts */
- -static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210)
- -{
- - if (fotg210->rh_state != FOTG210_RH_RUNNING)
- - return;
- -
- - /*
- - * Lost IAA irqs wedge things badly; seen first with a vt8235.
- - * So we need this watchdog, but must protect it against both
- - * (a) SMP races against real IAA firing and retriggering, and
- - * (b) clean HC shutdown, when IAA watchdog was pending.
- - */
- - if (fotg210->async_iaa) {
- - u32 cmd, status;
- -
- - /* If we get here, IAA is *REALLY* late. It's barely
- - * conceivable that the system is so busy that CMD_IAAD
- - * is still legitimately set, so let's be sure it's
- - * clear before we read STS_IAA. (The HC should clear
- - * CMD_IAAD when it sets STS_IAA.)
- - */
- - cmd = fotg210_readl(fotg210, &fotg210->regs->command);
- -
- - /*
- - * If IAA is set here it either legitimately triggered
- - * after the watchdog timer expired (_way_ late, so we'll
- - * still count it as lost) ... or a silicon erratum:
- - * - VIA seems to set IAA without triggering the IRQ;
- - * - IAAD potentially cleared without setting IAA.
- - */
- - status = fotg210_readl(fotg210, &fotg210->regs->status);
- - if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
- - INCR(fotg210->stats.lost_iaa);
- - fotg210_writel(fotg210, STS_IAA,
- - &fotg210->regs->status);
- - }
- -
- - fotg210_dbg(fotg210, "IAA watchdog: status %x cmd %x\n",
- - status, cmd);
- - end_unlink_async(fotg210);
- - }
- -}
- -
- -
- -/* Enable the I/O watchdog, if appropriate */
- -static void turn_on_io_watchdog(struct fotg210_hcd *fotg210)
- -{
- - /* Not needed if the controller isn't running or it's already enabled */
- - if (fotg210->rh_state != FOTG210_RH_RUNNING ||
- - (fotg210->enabled_hrtimer_events &
- - BIT(FOTG210_HRTIMER_IO_WATCHDOG)))
- - return;
- -
- - /*
- - * Isochronous transfers always need the watchdog.
- - * For other sorts we use it only if the flag is set.
- - */
- - if (fotg210->isoc_count > 0 || (fotg210->need_io_watchdog &&
- - fotg210->async_count + fotg210->intr_count > 0))
- - fotg210_enable_event(fotg210, FOTG210_HRTIMER_IO_WATCHDOG,
- - true);
- -}
- -
- -
- -/* Handler functions for the hrtimer event types.
- - * Keep this array in the same order as the event types indexed by
- - * enum fotg210_hrtimer_event in fotg210.h.
- - */
- -static void (*event_handlers[])(struct fotg210_hcd *) = {
- - fotg210_poll_ASS, /* FOTG210_HRTIMER_POLL_ASS */
- - fotg210_poll_PSS, /* FOTG210_HRTIMER_POLL_PSS */
- - fotg210_handle_controller_death, /* FOTG210_HRTIMER_POLL_DEAD */
- - fotg210_handle_intr_unlinks, /* FOTG210_HRTIMER_UNLINK_INTR */
- - end_free_itds, /* FOTG210_HRTIMER_FREE_ITDS */
- - unlink_empty_async, /* FOTG210_HRTIMER_ASYNC_UNLINKS */
- - fotg210_iaa_watchdog, /* FOTG210_HRTIMER_IAA_WATCHDOG */
- - fotg210_disable_PSE, /* FOTG210_HRTIMER_DISABLE_PERIODIC */
- - fotg210_disable_ASE, /* FOTG210_HRTIMER_DISABLE_ASYNC */
- - fotg210_work, /* FOTG210_HRTIMER_IO_WATCHDOG */
- -};
- -
- -static enum hrtimer_restart fotg210_hrtimer_func(struct hrtimer *t)
- -{
- - struct fotg210_hcd *fotg210 =
- - container_of(t, struct fotg210_hcd, hrtimer);
- - ktime_t now;
- - unsigned long events;
- - unsigned long flags;
- - unsigned e;
- -
- - spin_lock_irqsave(&fotg210->lock, flags);
- -
- - events = fotg210->enabled_hrtimer_events;
- - fotg210->enabled_hrtimer_events = 0;
- - fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
- -
- - /*
- - * Check each pending event. If its time has expired, handle
- - * the event; otherwise re-enable it.
- - */
- - now = ktime_get();
- - for_each_set_bit(e, &events, FOTG210_HRTIMER_NUM_EVENTS) {
- - if (ktime_compare(now, fotg210->hr_timeouts[e]) >= 0)
- - event_handlers[e](fotg210);
- - else
- - fotg210_enable_event(fotg210, e, false);
- - }
- -
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - return HRTIMER_NORESTART;
- -}
- -
- -#define fotg210_bus_suspend NULL
- -#define fotg210_bus_resume NULL
- -
- -static int check_reset_complete(struct fotg210_hcd *fotg210, int index,
- - u32 __iomem *status_reg, int port_status)
- -{
- - if (!(port_status & PORT_CONNECT))
- - return port_status;
- -
- - /* if reset finished and it's still not enabled -- handoff */
- - if (!(port_status & PORT_PE))
- - /* with integrated TT, there's nobody to hand it to! */
- - fotg210_dbg(fotg210, "Failed to enable port %d on root hub TT\n",
- - index + 1);
- - else
- - fotg210_dbg(fotg210, "port %d reset complete, port enabled\n",
- - index + 1);
- -
- - return port_status;
- -}
- -
- -
- -/* build "status change" packet (one or two bytes) from HC registers */
- -
- -static int fotg210_hub_status_data(struct usb_hcd *hcd, char *buf)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- - u32 temp, status;
- - u32 mask;
- - int retval = 1;
- - unsigned long flags;
- -
- - /* init status to no-changes */
- - buf[0] = 0;
- -
- - /* Inform the core about resumes-in-progress by returning
- - * a non-zero value even if there are no status changes.
- - */
- - status = fotg210->resuming_ports;
- -
- - mask = PORT_CSC | PORT_PEC;
- - /* PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND */
- -
- - /* no hub change reports (bit 0) for now (power, ...) */
- -
- - /* port N changes (bit N)? */
- - spin_lock_irqsave(&fotg210->lock, flags);
- -
- - temp = fotg210_readl(fotg210, &fotg210->regs->port_status);
- -
- - /*
- - * Return status information even for ports with OWNER set.
- - * Otherwise hub_wq wouldn't see the disconnect event when a
- - * high-speed device is switched over to the companion
- - * controller by the user.
- - */
- -
- - if ((temp & mask) != 0 || test_bit(0, &fotg210->port_c_suspend) ||
- - (fotg210->reset_done[0] &&
- - time_after_eq(jiffies, fotg210->reset_done[0]))) {
- - buf[0] |= 1 << 1;
- - status = STS_PCD;
- - }
- - /* FIXME autosuspend idle root hubs */
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - return status ? retval : 0;
- -}
- -
- -static void fotg210_hub_descriptor(struct fotg210_hcd *fotg210,
- - struct usb_hub_descriptor *desc)
- -{
- - int ports = HCS_N_PORTS(fotg210->hcs_params);
- - u16 temp;
- -
- - desc->bDescriptorType = USB_DT_HUB;
- - desc->bPwrOn2PwrGood = 10; /* fotg210 1.0, 2.3.9 says 20ms max */
- - desc->bHubContrCurrent = 0;
- -
- - desc->bNbrPorts = ports;
- - temp = 1 + (ports / 8);
- - desc->bDescLength = 7 + 2 * temp;
- -
- - /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
- - memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
- - memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
- -
- - temp = HUB_CHAR_INDV_PORT_OCPM; /* per-port overcurrent reporting */
- - temp |= HUB_CHAR_NO_LPSM; /* no power switching */
- - desc->wHubCharacteristics = cpu_to_le16(temp);
- -}
- -
- -static int fotg210_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
- - u16 wIndex, char *buf, u16 wLength)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- - int ports = HCS_N_PORTS(fotg210->hcs_params);
- - u32 __iomem *status_reg = &fotg210->regs->port_status;
- - u32 temp, temp1, status;
- - unsigned long flags;
- - int retval = 0;
- - unsigned selector;
- -
- - /*
- - * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
- - * HCS_INDICATOR may say we can change LEDs to off/amber/green.
- - * (track current state ourselves) ... blink for diagnostics,
- - * power, "this is the one", etc. EHCI spec supports this.
- - */
- -
- - spin_lock_irqsave(&fotg210->lock, flags);
- - switch (typeReq) {
- - case ClearHubFeature:
- - switch (wValue) {
- - case C_HUB_LOCAL_POWER:
- - case C_HUB_OVER_CURRENT:
- - /* no hub-wide feature/status flags */
- - break;
- - default:
- - goto error;
- - }
- - break;
- - case ClearPortFeature:
- - if (!wIndex || wIndex > ports)
- - goto error;
- - wIndex--;
- - temp = fotg210_readl(fotg210, status_reg);
- - temp &= ~PORT_RWC_BITS;
- -
- - /*
- - * Even if OWNER is set, so the port is owned by the
- - * companion controller, hub_wq needs to be able to clear
- - * the port-change status bits (especially
- - * USB_PORT_STAT_C_CONNECTION).
- - */
- -
- - switch (wValue) {
- - case USB_PORT_FEAT_ENABLE:
- - fotg210_writel(fotg210, temp & ~PORT_PE, status_reg);
- - break;
- - case USB_PORT_FEAT_C_ENABLE:
- - fotg210_writel(fotg210, temp | PORT_PEC, status_reg);
- - break;
- - case USB_PORT_FEAT_SUSPEND:
- - if (temp & PORT_RESET)
- - goto error;
- - if (!(temp & PORT_SUSPEND))
- - break;
- - if ((temp & PORT_PE) == 0)
- - goto error;
- -
- - /* resume signaling for 20 msec */
- - fotg210_writel(fotg210, temp | PORT_RESUME, status_reg);
- - fotg210->reset_done[wIndex] = jiffies
- - + msecs_to_jiffies(USB_RESUME_TIMEOUT);
- - break;
- - case USB_PORT_FEAT_C_SUSPEND:
- - clear_bit(wIndex, &fotg210->port_c_suspend);
- - break;
- - case USB_PORT_FEAT_C_CONNECTION:
- - fotg210_writel(fotg210, temp | PORT_CSC, status_reg);
- - break;
- - case USB_PORT_FEAT_C_OVER_CURRENT:
- - fotg210_writel(fotg210, temp | OTGISR_OVC,
- - &fotg210->regs->otgisr);
- - break;
- - case USB_PORT_FEAT_C_RESET:
- - /* GetPortStatus clears reset */
- - break;
- - default:
- - goto error;
- - }
- - fotg210_readl(fotg210, &fotg210->regs->command);
- - break;
- - case GetHubDescriptor:
- - fotg210_hub_descriptor(fotg210, (struct usb_hub_descriptor *)
- - buf);
- - break;
- - case GetHubStatus:
- - /* no hub-wide feature/status flags */
- - memset(buf, 0, 4);
- - /*cpu_to_le32s ((u32 *) buf); */
- - break;
- - case GetPortStatus:
- - if (!wIndex || wIndex > ports)
- - goto error;
- - wIndex--;
- - status = 0;
- - temp = fotg210_readl(fotg210, status_reg);
- -
- - /* wPortChange bits */
- - if (temp & PORT_CSC)
- - status |= USB_PORT_STAT_C_CONNECTION << 16;
- - if (temp & PORT_PEC)
- - status |= USB_PORT_STAT_C_ENABLE << 16;
- -
- - temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
- - if (temp1 & OTGISR_OVC)
- - status |= USB_PORT_STAT_C_OVERCURRENT << 16;
- -
- - /* whoever resumes must GetPortStatus to complete it!! */
- - if (temp & PORT_RESUME) {
- -
- - /* Remote Wakeup received? */
- - if (!fotg210->reset_done[wIndex]) {
- - /* resume signaling for 20 msec */
- - fotg210->reset_done[wIndex] = jiffies
- - + msecs_to_jiffies(20);
- - /* check the port again */
- - mod_timer(&fotg210_to_hcd(fotg210)->rh_timer,
- - fotg210->reset_done[wIndex]);
- - }
- -
- - /* resume completed? */
- - else if (time_after_eq(jiffies,
- - fotg210->reset_done[wIndex])) {
- - clear_bit(wIndex, &fotg210->suspended_ports);
- - set_bit(wIndex, &fotg210->port_c_suspend);
- - fotg210->reset_done[wIndex] = 0;
- -
- - /* stop resume signaling */
- - temp = fotg210_readl(fotg210, status_reg);
- - fotg210_writel(fotg210, temp &
- - ~(PORT_RWC_BITS | PORT_RESUME),
- - status_reg);
- - clear_bit(wIndex, &fotg210->resuming_ports);
- - retval = handshake(fotg210, status_reg,
- - PORT_RESUME, 0, 2000);/* 2ms */
- - if (retval != 0) {
- - fotg210_err(fotg210,
- - "port %d resume error %d\n",
- - wIndex + 1, retval);
- - goto error;
- - }
- - temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
- - }
- - }
- -
- - /* whoever resets must GetPortStatus to complete it!! */
- - if ((temp & PORT_RESET) && time_after_eq(jiffies,
- - fotg210->reset_done[wIndex])) {
- - status |= USB_PORT_STAT_C_RESET << 16;
- - fotg210->reset_done[wIndex] = 0;
- - clear_bit(wIndex, &fotg210->resuming_ports);
- -
- - /* force reset to complete */
- - fotg210_writel(fotg210,
- - temp & ~(PORT_RWC_BITS | PORT_RESET),
- - status_reg);
- - /* REVISIT: some hardware needs 550+ usec to clear
- - * this bit; seems too long to spin routinely...
- - */
- - retval = handshake(fotg210, status_reg,
- - PORT_RESET, 0, 1000);
- - if (retval != 0) {
- - fotg210_err(fotg210, "port %d reset error %d\n",
- - wIndex + 1, retval);
- - goto error;
- - }
- -
- - /* see what we found out */
- - temp = check_reset_complete(fotg210, wIndex, status_reg,
- - fotg210_readl(fotg210, status_reg));
- -
- - /* restart schedule */
- - fotg210->command |= CMD_RUN;
- - fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
- - }
- -
- - if (!(temp & (PORT_RESUME|PORT_RESET))) {
- - fotg210->reset_done[wIndex] = 0;
- - clear_bit(wIndex, &fotg210->resuming_ports);
- - }
- -
- - /* transfer dedicated ports to the companion hc */
- - if ((temp & PORT_CONNECT) &&
- - test_bit(wIndex, &fotg210->companion_ports)) {
- - temp &= ~PORT_RWC_BITS;
- - fotg210_writel(fotg210, temp, status_reg);
- - fotg210_dbg(fotg210, "port %d --> companion\n",
- - wIndex + 1);
- - temp = fotg210_readl(fotg210, status_reg);
- - }
- -
- - /*
- - * Even if OWNER is set, there's no harm letting hub_wq
- - * see the wPortStatus values (they should all be 0 except
- - * for PORT_POWER anyway).
- - */
- -
- - if (temp & PORT_CONNECT) {
- - status |= USB_PORT_STAT_CONNECTION;
- - status |= fotg210_port_speed(fotg210, temp);
- - }
- - if (temp & PORT_PE)
- - status |= USB_PORT_STAT_ENABLE;
- -
- - /* maybe the port was unsuspended without our knowledge */
- - if (temp & (PORT_SUSPEND|PORT_RESUME)) {
- - status |= USB_PORT_STAT_SUSPEND;
- - } else if (test_bit(wIndex, &fotg210->suspended_ports)) {
- - clear_bit(wIndex, &fotg210->suspended_ports);
- - clear_bit(wIndex, &fotg210->resuming_ports);
- - fotg210->reset_done[wIndex] = 0;
- - if (temp & PORT_PE)
- - set_bit(wIndex, &fotg210->port_c_suspend);
- - }
- -
- - temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
- - if (temp1 & OTGISR_OVC)
- - status |= USB_PORT_STAT_OVERCURRENT;
- - if (temp & PORT_RESET)
- - status |= USB_PORT_STAT_RESET;
- - if (test_bit(wIndex, &fotg210->port_c_suspend))
- - status |= USB_PORT_STAT_C_SUSPEND << 16;
- -
- - if (status & ~0xffff) /* only if wPortChange is interesting */
- - dbg_port(fotg210, "GetStatus", wIndex + 1, temp);
- - put_unaligned_le32(status, buf);
- - break;
- - case SetHubFeature:
- - switch (wValue) {
- - case C_HUB_LOCAL_POWER:
- - case C_HUB_OVER_CURRENT:
- - /* no hub-wide feature/status flags */
- - break;
- - default:
- - goto error;
- - }
- - break;
- - case SetPortFeature:
- - selector = wIndex >> 8;
- - wIndex &= 0xff;
- -
- - if (!wIndex || wIndex > ports)
- - goto error;
- - wIndex--;
- - temp = fotg210_readl(fotg210, status_reg);
- - temp &= ~PORT_RWC_BITS;
- - switch (wValue) {
- - case USB_PORT_FEAT_SUSPEND:
- - if ((temp & PORT_PE) == 0
- - || (temp & PORT_RESET) != 0)
- - goto error;
- -
- - /* After above check the port must be connected.
- - * Set appropriate bit thus could put phy into low power
- - * mode if we have hostpc feature
- - */
- - fotg210_writel(fotg210, temp | PORT_SUSPEND,
- - status_reg);
- - set_bit(wIndex, &fotg210->suspended_ports);
- - break;
- - case USB_PORT_FEAT_RESET:
- - if (temp & PORT_RESUME)
- - goto error;
- - /* line status bits may report this as low speed,
- - * which can be fine if this root hub has a
- - * transaction translator built in.
- - */
- - fotg210_dbg(fotg210, "port %d reset\n", wIndex + 1);
- - temp |= PORT_RESET;
- - temp &= ~PORT_PE;
- -
- - /*
- - * caller must wait, then call GetPortStatus
- - * usb 2.0 spec says 50 ms resets on root
- - */
- - fotg210->reset_done[wIndex] = jiffies
- - + msecs_to_jiffies(50);
- - fotg210_writel(fotg210, temp, status_reg);
- - break;
- -
- - /* For downstream facing ports (these): one hub port is put
- - * into test mode according to USB2 11.24.2.13, then the hub
- - * must be reset (which for root hub now means rmmod+modprobe,
- - * or else system reboot). See EHCI 2.3.9 and 4.14 for info
- - * about the EHCI-specific stuff.
- - */
- - case USB_PORT_FEAT_TEST:
- - if (!selector || selector > 5)
- - goto error;
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - fotg210_quiesce(fotg210);
- - spin_lock_irqsave(&fotg210->lock, flags);
- -
- - /* Put all enabled ports into suspend */
- - temp = fotg210_readl(fotg210, status_reg) &
- - ~PORT_RWC_BITS;
- - if (temp & PORT_PE)
- - fotg210_writel(fotg210, temp | PORT_SUSPEND,
- - status_reg);
- -
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - fotg210_halt(fotg210);
- - spin_lock_irqsave(&fotg210->lock, flags);
- -
- - temp = fotg210_readl(fotg210, status_reg);
- - temp |= selector << 16;
- - fotg210_writel(fotg210, temp, status_reg);
- - break;
- -
- - default:
- - goto error;
- - }
- - fotg210_readl(fotg210, &fotg210->regs->command);
- - break;
- -
- - default:
- -error:
- - /* "stall" on error */
- - retval = -EPIPE;
- - }
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - return retval;
- -}
- -
- -static void __maybe_unused fotg210_relinquish_port(struct usb_hcd *hcd,
- - int portnum)
- -{
- - return;
- -}
- -
- -static int __maybe_unused fotg210_port_handed_over(struct usb_hcd *hcd,
- - int portnum)
- -{
- - return 0;
- -}
- -
- -/* There's basically three types of memory:
- - * - data used only by the HCD ... kmalloc is fine
- - * - async and periodic schedules, shared by HC and HCD ... these
- - * need to use dma_pool or dma_alloc_coherent
- - * - driver buffers, read/written by HC ... single shot DMA mapped
- - *
- - * There's also "register" data (e.g. PCI or SOC), which is memory mapped.
- - * No memory seen by this driver is pageable.
- - */
- -
- -/* Allocate the key transfer structures from the previously allocated pool */
- -static inline void fotg210_qtd_init(struct fotg210_hcd *fotg210,
- - struct fotg210_qtd *qtd, dma_addr_t dma)
- -{
- - memset(qtd, 0, sizeof(*qtd));
- - qtd->qtd_dma = dma;
- - qtd->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
- - qtd->hw_next = FOTG210_LIST_END(fotg210);
- - qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
- - INIT_LIST_HEAD(&qtd->qtd_list);
- -}
- -
- -static struct fotg210_qtd *fotg210_qtd_alloc(struct fotg210_hcd *fotg210,
- - gfp_t flags)
- -{
- - struct fotg210_qtd *qtd;
- - dma_addr_t dma;
- -
- - qtd = dma_pool_alloc(fotg210->qtd_pool, flags, &dma);
- - if (qtd != NULL)
- - fotg210_qtd_init(fotg210, qtd, dma);
- -
- - return qtd;
- -}
- -
- -static inline void fotg210_qtd_free(struct fotg210_hcd *fotg210,
- - struct fotg210_qtd *qtd)
- -{
- - dma_pool_free(fotg210->qtd_pool, qtd, qtd->qtd_dma);
- -}
- -
- -
- -static void qh_destroy(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- -{
- - /* clean qtds first, and know this is not linked */
- - if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) {
- - fotg210_dbg(fotg210, "unused qh not empty!\n");
- - BUG();
- - }
- - if (qh->dummy)
- - fotg210_qtd_free(fotg210, qh->dummy);
- - dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
- - kfree(qh);
- -}
- -
- -static struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210,
- - gfp_t flags)
- -{
- - struct fotg210_qh *qh;
- - dma_addr_t dma;
- -
- - qh = kzalloc(sizeof(*qh), GFP_ATOMIC);
- - if (!qh)
- - goto done;
- - qh->hw = (struct fotg210_qh_hw *)
- - dma_pool_zalloc(fotg210->qh_pool, flags, &dma);
- - if (!qh->hw)
- - goto fail;
- - qh->qh_dma = dma;
- - INIT_LIST_HEAD(&qh->qtd_list);
- -
- - /* dummy td enables safe urb queuing */
- - qh->dummy = fotg210_qtd_alloc(fotg210, flags);
- - if (qh->dummy == NULL) {
- - fotg210_dbg(fotg210, "no dummy td\n");
- - goto fail1;
- - }
- -done:
- - return qh;
- -fail1:
- - dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
- -fail:
- - kfree(qh);
- - return NULL;
- -}
- -
- -/* The queue heads and transfer descriptors are managed from pools tied
- - * to each of the "per device" structures.
- - * This is the initialisation and cleanup code.
- - */
- -
- -static void fotg210_mem_cleanup(struct fotg210_hcd *fotg210)
- -{
- - if (fotg210->async)
- - qh_destroy(fotg210, fotg210->async);
- - fotg210->async = NULL;
- -
- - if (fotg210->dummy)
- - qh_destroy(fotg210, fotg210->dummy);
- - fotg210->dummy = NULL;
- -
- - /* DMA consistent memory and pools */
- - dma_pool_destroy(fotg210->qtd_pool);
- - fotg210->qtd_pool = NULL;
- -
- - dma_pool_destroy(fotg210->qh_pool);
- - fotg210->qh_pool = NULL;
- -
- - dma_pool_destroy(fotg210->itd_pool);
- - fotg210->itd_pool = NULL;
- -
- - if (fotg210->periodic)
- - dma_free_coherent(fotg210_to_hcd(fotg210)->self.controller,
- - fotg210->periodic_size * sizeof(u32),
- - fotg210->periodic, fotg210->periodic_dma);
- - fotg210->periodic = NULL;
- -
- - /* shadow periodic table */
- - kfree(fotg210->pshadow);
- - fotg210->pshadow = NULL;
- -}
- -
- -/* remember to add cleanup code (above) if you add anything here */
- -static int fotg210_mem_init(struct fotg210_hcd *fotg210, gfp_t flags)
- -{
- - int i;
- -
- - /* QTDs for control/bulk/intr transfers */
- - fotg210->qtd_pool = dma_pool_create("fotg210_qtd",
- - fotg210_to_hcd(fotg210)->self.controller,
- - sizeof(struct fotg210_qtd),
- - 32 /* byte alignment (for hw parts) */,
- - 4096 /* can't cross 4K */);
- - if (!fotg210->qtd_pool)
- - goto fail;
- -
- - /* QHs for control/bulk/intr transfers */
- - fotg210->qh_pool = dma_pool_create("fotg210_qh",
- - fotg210_to_hcd(fotg210)->self.controller,
- - sizeof(struct fotg210_qh_hw),
- - 32 /* byte alignment (for hw parts) */,
- - 4096 /* can't cross 4K */);
- - if (!fotg210->qh_pool)
- - goto fail;
- -
- - fotg210->async = fotg210_qh_alloc(fotg210, flags);
- - if (!fotg210->async)
- - goto fail;
- -
- - /* ITD for high speed ISO transfers */
- - fotg210->itd_pool = dma_pool_create("fotg210_itd",
- - fotg210_to_hcd(fotg210)->self.controller,
- - sizeof(struct fotg210_itd),
- - 64 /* byte alignment (for hw parts) */,
- - 4096 /* can't cross 4K */);
- - if (!fotg210->itd_pool)
- - goto fail;
- -
- - /* Hardware periodic table */
- - fotg210->periodic =
- - dma_alloc_coherent(fotg210_to_hcd(fotg210)->self.controller,
- - fotg210->periodic_size * sizeof(__le32),
- - &fotg210->periodic_dma, 0);
- - if (fotg210->periodic == NULL)
- - goto fail;
- -
- - for (i = 0; i < fotg210->periodic_size; i++)
- - fotg210->periodic[i] = FOTG210_LIST_END(fotg210);
- -
- - /* software shadow of hardware table */
- - fotg210->pshadow = kcalloc(fotg210->periodic_size, sizeof(void *),
- - flags);
- - if (fotg210->pshadow != NULL)
- - return 0;
- -
- -fail:
- - fotg210_dbg(fotg210, "couldn't init memory\n");
- - fotg210_mem_cleanup(fotg210);
- - return -ENOMEM;
- -}
- -/* EHCI hardware queue manipulation ... the core. QH/QTD manipulation.
- - *
- - * Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd"
- - * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
- - * buffers needed for the larger number). We use one QH per endpoint, queue
- - * multiple urbs (all three types) per endpoint. URBs may need several qtds.
- - *
- - * ISO traffic uses "ISO TD" (itd) records, and (along with
- - * interrupts) needs careful scheduling. Performance improvements can be
- - * an ongoing challenge. That's in "ehci-sched.c".
- - *
- - * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
- - * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
- - * (b) special fields in qh entries or (c) split iso entries. TTs will
- - * buffer low/full speed data so the host collects it at high speed.
- - */
- -
- -/* fill a qtd, returning how much of the buffer we were able to queue up */
- -static int qtd_fill(struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd,
- - dma_addr_t buf, size_t len, int token, int maxpacket)
- -{
- - int i, count;
- - u64 addr = buf;
- -
- - /* one buffer entry per 4K ... first might be short or unaligned */
- - qtd->hw_buf[0] = cpu_to_hc32(fotg210, (u32)addr);
- - qtd->hw_buf_hi[0] = cpu_to_hc32(fotg210, (u32)(addr >> 32));
- - count = 0x1000 - (buf & 0x0fff); /* rest of that page */
- - if (likely(len < count)) /* ... iff needed */
- - count = len;
- - else {
- - buf += 0x1000;
- - buf &= ~0x0fff;
- -
- - /* per-qtd limit: from 16K to 20K (best alignment) */
- - for (i = 1; count < len && i < 5; i++) {
- - addr = buf;
- - qtd->hw_buf[i] = cpu_to_hc32(fotg210, (u32)addr);
- - qtd->hw_buf_hi[i] = cpu_to_hc32(fotg210,
- - (u32)(addr >> 32));
- - buf += 0x1000;
- - if ((count + 0x1000) < len)
- - count += 0x1000;
- - else
- - count = len;
- - }
- -
- - /* short packets may only terminate transfers */
- - if (count != len)
- - count -= (count % maxpacket);
- - }
- - qtd->hw_token = cpu_to_hc32(fotg210, (count << 16) | token);
- - qtd->length = count;
- -
- - return count;
- -}
- -
- -static inline void qh_update(struct fotg210_hcd *fotg210,
- - struct fotg210_qh *qh, struct fotg210_qtd *qtd)
- -{
- - struct fotg210_qh_hw *hw = qh->hw;
- -
- - /* writes to an active overlay are unsafe */
- - BUG_ON(qh->qh_state != QH_STATE_IDLE);
- -
- - hw->hw_qtd_next = QTD_NEXT(fotg210, qtd->qtd_dma);
- - hw->hw_alt_next = FOTG210_LIST_END(fotg210);
- -
- - /* Except for control endpoints, we make hardware maintain data
- - * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
- - * and set the pseudo-toggle in udev. Only usb_clear_halt() will
- - * ever clear it.
- - */
- - if (!(hw->hw_info1 & cpu_to_hc32(fotg210, QH_TOGGLE_CTL))) {
- - unsigned is_out, epnum;
- -
- - is_out = qh->is_out;
- - epnum = (hc32_to_cpup(fotg210, &hw->hw_info1) >> 8) & 0x0f;
- - if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) {
- - hw->hw_token &= ~cpu_to_hc32(fotg210, QTD_TOGGLE);
- - usb_settoggle(qh->dev, epnum, is_out, 1);
- - }
- - }
- -
- - hw->hw_token &= cpu_to_hc32(fotg210, QTD_TOGGLE | QTD_STS_PING);
- -}
- -
- -/* if it weren't for a common silicon quirk (writing the dummy into the qh
- - * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
- - * recovery (including urb dequeue) would need software changes to a QH...
- - */
- -static void qh_refresh(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- -{
- - struct fotg210_qtd *qtd;
- -
- - if (list_empty(&qh->qtd_list))
- - qtd = qh->dummy;
- - else {
- - qtd = list_entry(qh->qtd_list.next,
- - struct fotg210_qtd, qtd_list);
- - /*
- - * first qtd may already be partially processed.
- - * If we come here during unlink, the QH overlay region
- - * might have reference to the just unlinked qtd. The
- - * qtd is updated in qh_completions(). Update the QH
- - * overlay here.
- - */
- - if (cpu_to_hc32(fotg210, qtd->qtd_dma) == qh->hw->hw_current) {
- - qh->hw->hw_qtd_next = qtd->hw_next;
- - qtd = NULL;
- - }
- - }
- -
- - if (qtd)
- - qh_update(fotg210, qh, qtd);
- -}
- -
- -static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
- -
- -static void fotg210_clear_tt_buffer_complete(struct usb_hcd *hcd,
- - struct usb_host_endpoint *ep)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- - struct fotg210_qh *qh = ep->hcpriv;
- - unsigned long flags;
- -
- - spin_lock_irqsave(&fotg210->lock, flags);
- - qh->clearing_tt = 0;
- - if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
- - && fotg210->rh_state == FOTG210_RH_RUNNING)
- - qh_link_async(fotg210, qh);
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- -}
- -
- -static void fotg210_clear_tt_buffer(struct fotg210_hcd *fotg210,
- - struct fotg210_qh *qh, struct urb *urb, u32 token)
- -{
- -
- - /* If an async split transaction gets an error or is unlinked,
- - * the TT buffer may be left in an indeterminate state. We
- - * have to clear the TT buffer.
- - *
- - * Note: this routine is never called for Isochronous transfers.
- - */
- - if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) {
- - struct usb_device *tt = urb->dev->tt->hub;
- -
- - dev_dbg(&tt->dev,
- - "clear tt buffer port %d, a%d ep%d t%08x\n",
- - urb->dev->ttport, urb->dev->devnum,
- - usb_pipeendpoint(urb->pipe), token);
- -
- - if (urb->dev->tt->hub !=
- - fotg210_to_hcd(fotg210)->self.root_hub) {
- - if (usb_hub_clear_tt_buffer(urb) == 0)
- - qh->clearing_tt = 1;
- - }
- - }
- -}
- -
- -static int qtd_copy_status(struct fotg210_hcd *fotg210, struct urb *urb,
- - size_t length, u32 token)
- -{
- - int status = -EINPROGRESS;
- -
- - /* count IN/OUT bytes, not SETUP (even short packets) */
- - if (likely(QTD_PID(token) != 2))
- - urb->actual_length += length - QTD_LENGTH(token);
- -
- - /* don't modify error codes */
- - if (unlikely(urb->unlinked))
- - return status;
- -
- - /* force cleanup after short read; not always an error */
- - if (unlikely(IS_SHORT_READ(token)))
- - status = -EREMOTEIO;
- -
- - /* serious "can't proceed" faults reported by the hardware */
- - if (token & QTD_STS_HALT) {
- - if (token & QTD_STS_BABBLE) {
- - /* FIXME "must" disable babbling device's port too */
- - status = -EOVERFLOW;
- - /* CERR nonzero + halt --> stall */
- - } else if (QTD_CERR(token)) {
- - status = -EPIPE;
- -
- - /* In theory, more than one of the following bits can be set
- - * since they are sticky and the transaction is retried.
- - * Which to test first is rather arbitrary.
- - */
- - } else if (token & QTD_STS_MMF) {
- - /* fs/ls interrupt xfer missed the complete-split */
- - status = -EPROTO;
- - } else if (token & QTD_STS_DBE) {
- - status = (QTD_PID(token) == 1) /* IN ? */
- - ? -ENOSR /* hc couldn't read data */
- - : -ECOMM; /* hc couldn't write data */
- - } else if (token & QTD_STS_XACT) {
- - /* timeout, bad CRC, wrong PID, etc */
- - fotg210_dbg(fotg210, "devpath %s ep%d%s 3strikes\n",
- - urb->dev->devpath,
- - usb_pipeendpoint(urb->pipe),
- - usb_pipein(urb->pipe) ? "in" : "out");
- - status = -EPROTO;
- - } else { /* unknown */
- - status = -EPROTO;
- - }
- -
- - fotg210_dbg(fotg210,
- - "dev%d ep%d%s qtd token %08x --> status %d\n",
- - usb_pipedevice(urb->pipe),
- - usb_pipeendpoint(urb->pipe),
- - usb_pipein(urb->pipe) ? "in" : "out",
- - token, status);
- - }
- -
- - return status;
- -}
- -
- -static void fotg210_urb_done(struct fotg210_hcd *fotg210, struct urb *urb,
- - int status)
- -__releases(fotg210->lock)
- -__acquires(fotg210->lock)
- -{
- - if (likely(urb->hcpriv != NULL)) {
- - struct fotg210_qh *qh = (struct fotg210_qh *) urb->hcpriv;
- -
- - /* S-mask in a QH means it's an interrupt urb */
- - if ((qh->hw->hw_info2 & cpu_to_hc32(fotg210, QH_SMASK)) != 0) {
- -
- - /* ... update hc-wide periodic stats (for usbfs) */
- - fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs--;
- - }
- - }
- -
- - if (unlikely(urb->unlinked)) {
- - INCR(fotg210->stats.unlink);
- - } else {
- - /* report non-error and short read status as zero */
- - if (status == -EINPROGRESS || status == -EREMOTEIO)
- - status = 0;
- - INCR(fotg210->stats.complete);
- - }
- -
- -#ifdef FOTG210_URB_TRACE
- - fotg210_dbg(fotg210,
- - "%s %s urb %p ep%d%s status %d len %d/%d\n",
- - __func__, urb->dev->devpath, urb,
- - usb_pipeendpoint(urb->pipe),
- - usb_pipein(urb->pipe) ? "in" : "out",
- - status,
- - urb->actual_length, urb->transfer_buffer_length);
- -#endif
- -
- - /* complete() can reenter this HCD */
- - usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
- - spin_unlock(&fotg210->lock);
- - usb_hcd_giveback_urb(fotg210_to_hcd(fotg210), urb, status);
- - spin_lock(&fotg210->lock);
- -}
- -
- -static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
- -
- -/* Process and free completed qtds for a qh, returning URBs to drivers.
- - * Chases up to qh->hw_current. Returns number of completions called,
- - * indicating how much "real" work we did.
- - */
- -static unsigned qh_completions(struct fotg210_hcd *fotg210,
- - struct fotg210_qh *qh)
- -{
- - struct fotg210_qtd *last, *end = qh->dummy;
- - struct fotg210_qtd *qtd, *tmp;
- - int last_status;
- - int stopped;
- - unsigned count = 0;
- - u8 state;
- - struct fotg210_qh_hw *hw = qh->hw;
- -
- - if (unlikely(list_empty(&qh->qtd_list)))
- - return count;
- -
- - /* completions (or tasks on other cpus) must never clobber HALT
- - * till we've gone through and cleaned everything up, even when
- - * they add urbs to this qh's queue or mark them for unlinking.
- - *
- - * NOTE: unlinking expects to be done in queue order.
- - *
- - * It's a bug for qh->qh_state to be anything other than
- - * QH_STATE_IDLE, unless our caller is scan_async() or
- - * scan_intr().
- - */
- - state = qh->qh_state;
- - qh->qh_state = QH_STATE_COMPLETING;
- - stopped = (state == QH_STATE_IDLE);
- -
- -rescan:
- - last = NULL;
- - last_status = -EINPROGRESS;
- - qh->needs_rescan = 0;
- -
- - /* remove de-activated QTDs from front of queue.
- - * after faults (including short reads), cleanup this urb
- - * then let the queue advance.
- - * if queue is stopped, handles unlinks.
- - */
- - list_for_each_entry_safe(qtd, tmp, &qh->qtd_list, qtd_list) {
- - struct urb *urb;
- - u32 token = 0;
- -
- - urb = qtd->urb;
- -
- - /* clean up any state from previous QTD ...*/
- - if (last) {
- - if (likely(last->urb != urb)) {
- - fotg210_urb_done(fotg210, last->urb,
- - last_status);
- - count++;
- - last_status = -EINPROGRESS;
- - }
- - fotg210_qtd_free(fotg210, last);
- - last = NULL;
- - }
- -
- - /* ignore urbs submitted during completions we reported */
- - if (qtd == end)
- - break;
- -
- - /* hardware copies qtd out of qh overlay */
- - rmb();
- - token = hc32_to_cpu(fotg210, qtd->hw_token);
- -
- - /* always clean up qtds the hc de-activated */
- -retry_xacterr:
- - if ((token & QTD_STS_ACTIVE) == 0) {
- -
- - /* Report Data Buffer Error: non-fatal but useful */
- - if (token & QTD_STS_DBE)
- - fotg210_dbg(fotg210,
- - "detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n",
- - urb, usb_endpoint_num(&urb->ep->desc),
- - usb_endpoint_dir_in(&urb->ep->desc)
- - ? "in" : "out",
- - urb->transfer_buffer_length, qtd, qh);
- -
- - /* on STALL, error, and short reads this urb must
- - * complete and all its qtds must be recycled.
- - */
- - if ((token & QTD_STS_HALT) != 0) {
- -
- - /* retry transaction errors until we
- - * reach the software xacterr limit
- - */
- - if ((token & QTD_STS_XACT) &&
- - QTD_CERR(token) == 0 &&
- - ++qh->xacterrs < QH_XACTERR_MAX &&
- - !urb->unlinked) {
- - fotg210_dbg(fotg210,
- - "detected XactErr len %zu/%zu retry %d\n",
- - qtd->length - QTD_LENGTH(token),
- - qtd->length,
- - qh->xacterrs);
- -
- - /* reset the token in the qtd and the
- - * qh overlay (which still contains
- - * the qtd) so that we pick up from
- - * where we left off
- - */
- - token &= ~QTD_STS_HALT;
- - token |= QTD_STS_ACTIVE |
- - (FOTG210_TUNE_CERR << 10);
- - qtd->hw_token = cpu_to_hc32(fotg210,
- - token);
- - wmb();
- - hw->hw_token = cpu_to_hc32(fotg210,
- - token);
- - goto retry_xacterr;
- - }
- - stopped = 1;
- -
- - /* magic dummy for some short reads; qh won't advance.
- - * that silicon quirk can kick in with this dummy too.
- - *
- - * other short reads won't stop the queue, including
- - * control transfers (status stage handles that) or
- - * most other single-qtd reads ... the queue stops if
- - * URB_SHORT_NOT_OK was set so the driver submitting
- - * the urbs could clean it up.
- - */
- - } else if (IS_SHORT_READ(token) &&
- - !(qtd->hw_alt_next &
- - FOTG210_LIST_END(fotg210))) {
- - stopped = 1;
- - }
- -
- - /* stop scanning when we reach qtds the hc is using */
- - } else if (likely(!stopped
- - && fotg210->rh_state >= FOTG210_RH_RUNNING)) {
- - break;
- -
- - /* scan the whole queue for unlinks whenever it stops */
- - } else {
- - stopped = 1;
- -
- - /* cancel everything if we halt, suspend, etc */
- - if (fotg210->rh_state < FOTG210_RH_RUNNING)
- - last_status = -ESHUTDOWN;
- -
- - /* this qtd is active; skip it unless a previous qtd
- - * for its urb faulted, or its urb was canceled.
- - */
- - else if (last_status == -EINPROGRESS && !urb->unlinked)
- - continue;
- -
- - /* qh unlinked; token in overlay may be most current */
- - if (state == QH_STATE_IDLE &&
- - cpu_to_hc32(fotg210, qtd->qtd_dma)
- - == hw->hw_current) {
- - token = hc32_to_cpu(fotg210, hw->hw_token);
- -
- - /* An unlink may leave an incomplete
- - * async transaction in the TT buffer.
- - * We have to clear it.
- - */
- - fotg210_clear_tt_buffer(fotg210, qh, urb,
- - token);
- - }
- - }
- -
- - /* unless we already know the urb's status, collect qtd status
- - * and update count of bytes transferred. in common short read
- - * cases with only one data qtd (including control transfers),
- - * queue processing won't halt. but with two or more qtds (for
- - * example, with a 32 KB transfer), when the first qtd gets a
- - * short read the second must be removed by hand.
- - */
- - if (last_status == -EINPROGRESS) {
- - last_status = qtd_copy_status(fotg210, urb,
- - qtd->length, token);
- - if (last_status == -EREMOTEIO &&
- - (qtd->hw_alt_next &
- - FOTG210_LIST_END(fotg210)))
- - last_status = -EINPROGRESS;
- -
- - /* As part of low/full-speed endpoint-halt processing
- - * we must clear the TT buffer (11.17.5).
- - */
- - if (unlikely(last_status != -EINPROGRESS &&
- - last_status != -EREMOTEIO)) {
- - /* The TT's in some hubs malfunction when they
- - * receive this request following a STALL (they
- - * stop sending isochronous packets). Since a
- - * STALL can't leave the TT buffer in a busy
- - * state (if you believe Figures 11-48 - 11-51
- - * in the USB 2.0 spec), we won't clear the TT
- - * buffer in this case. Strictly speaking this
- - * is a violation of the spec.
- - */
- - if (last_status != -EPIPE)
- - fotg210_clear_tt_buffer(fotg210, qh,
- - urb, token);
- - }
- - }
- -
- - /* if we're removing something not at the queue head,
- - * patch the hardware queue pointer.
- - */
- - if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
- - last = list_entry(qtd->qtd_list.prev,
- - struct fotg210_qtd, qtd_list);
- - last->hw_next = qtd->hw_next;
- - }
- -
- - /* remove qtd; it's recycled after possible urb completion */
- - list_del(&qtd->qtd_list);
- - last = qtd;
- -
- - /* reinit the xacterr counter for the next qtd */
- - qh->xacterrs = 0;
- - }
- -
- - /* last urb's completion might still need calling */
- - if (likely(last != NULL)) {
- - fotg210_urb_done(fotg210, last->urb, last_status);
- - count++;
- - fotg210_qtd_free(fotg210, last);
- - }
- -
- - /* Do we need to rescan for URBs dequeued during a giveback? */
- - if (unlikely(qh->needs_rescan)) {
- - /* If the QH is already unlinked, do the rescan now. */
- - if (state == QH_STATE_IDLE)
- - goto rescan;
- -
- - /* Otherwise we have to wait until the QH is fully unlinked.
- - * Our caller will start an unlink if qh->needs_rescan is
- - * set. But if an unlink has already started, nothing needs
- - * to be done.
- - */
- - if (state != QH_STATE_LINKED)
- - qh->needs_rescan = 0;
- - }
- -
- - /* restore original state; caller must unlink or relink */
- - qh->qh_state = state;
- -
- - /* be sure the hardware's done with the qh before refreshing
- - * it after fault cleanup, or recovering from silicon wrongly
- - * overlaying the dummy qtd (which reduces DMA chatter).
- - */
- - if (stopped != 0 || hw->hw_qtd_next == FOTG210_LIST_END(fotg210)) {
- - switch (state) {
- - case QH_STATE_IDLE:
- - qh_refresh(fotg210, qh);
- - break;
- - case QH_STATE_LINKED:
- - /* We won't refresh a QH that's linked (after the HC
- - * stopped the queue). That avoids a race:
- - * - HC reads first part of QH;
- - * - CPU updates that first part and the token;
- - * - HC reads rest of that QH, including token
- - * Result: HC gets an inconsistent image, and then
- - * DMAs to/from the wrong memory (corrupting it).
- - *
- - * That should be rare for interrupt transfers,
- - * except maybe high bandwidth ...
- - */
- -
- - /* Tell the caller to start an unlink */
- - qh->needs_rescan = 1;
- - break;
- - /* otherwise, unlink already started */
- - }
- - }
- -
- - return count;
- -}
- -
- -/* reverse of qh_urb_transaction: free a list of TDs.
- - * used for cleanup after errors, before HC sees an URB's TDs.
- - */
- -static void qtd_list_free(struct fotg210_hcd *fotg210, struct urb *urb,
- - struct list_head *head)
- -{
- - struct fotg210_qtd *qtd, *temp;
- -
- - list_for_each_entry_safe(qtd, temp, head, qtd_list) {
- - list_del(&qtd->qtd_list);
- - fotg210_qtd_free(fotg210, qtd);
- - }
- -}
- -
- -/* create a list of filled qtds for this URB; won't link into qh.
- - */
- -static struct list_head *qh_urb_transaction(struct fotg210_hcd *fotg210,
- - struct urb *urb, struct list_head *head, gfp_t flags)
- -{
- - struct fotg210_qtd *qtd, *qtd_prev;
- - dma_addr_t buf;
- - int len, this_sg_len, maxpacket;
- - int is_input;
- - u32 token;
- - int i;
- - struct scatterlist *sg;
- -
- - /*
- - * URBs map to sequences of QTDs: one logical transaction
- - */
- - qtd = fotg210_qtd_alloc(fotg210, flags);
- - if (unlikely(!qtd))
- - return NULL;
- - list_add_tail(&qtd->qtd_list, head);
- - qtd->urb = urb;
- -
- - token = QTD_STS_ACTIVE;
- - token |= (FOTG210_TUNE_CERR << 10);
- - /* for split transactions, SplitXState initialized to zero */
- -
- - len = urb->transfer_buffer_length;
- - is_input = usb_pipein(urb->pipe);
- - if (usb_pipecontrol(urb->pipe)) {
- - /* SETUP pid */
- - qtd_fill(fotg210, qtd, urb->setup_dma,
- - sizeof(struct usb_ctrlrequest),
- - token | (2 /* "setup" */ << 8), 8);
- -
- - /* ... and always at least one more pid */
- - token ^= QTD_TOGGLE;
- - qtd_prev = qtd;
- - qtd = fotg210_qtd_alloc(fotg210, flags);
- - if (unlikely(!qtd))
- - goto cleanup;
- - qtd->urb = urb;
- - qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
- - list_add_tail(&qtd->qtd_list, head);
- -
- - /* for zero length DATA stages, STATUS is always IN */
- - if (len == 0)
- - token |= (1 /* "in" */ << 8);
- - }
- -
- - /*
- - * data transfer stage: buffer setup
- - */
- - i = urb->num_mapped_sgs;
- - if (len > 0 && i > 0) {
- - sg = urb->sg;
- - buf = sg_dma_address(sg);
- -
- - /* urb->transfer_buffer_length may be smaller than the
- - * size of the scatterlist (or vice versa)
- - */
- - this_sg_len = min_t(int, sg_dma_len(sg), len);
- - } else {
- - sg = NULL;
- - buf = urb->transfer_dma;
- - this_sg_len = len;
- - }
- -
- - if (is_input)
- - token |= (1 /* "in" */ << 8);
- - /* else it's already initted to "out" pid (0 << 8) */
- -
- - maxpacket = usb_maxpacket(urb->dev, urb->pipe);
- -
- - /*
- - * buffer gets wrapped in one or more qtds;
- - * last one may be "short" (including zero len)
- - * and may serve as a control status ack
- - */
- - for (;;) {
- - int this_qtd_len;
- -
- - this_qtd_len = qtd_fill(fotg210, qtd, buf, this_sg_len, token,
- - maxpacket);
- - this_sg_len -= this_qtd_len;
- - len -= this_qtd_len;
- - buf += this_qtd_len;
- -
- - /*
- - * short reads advance to a "magic" dummy instead of the next
- - * qtd ... that forces the queue to stop, for manual cleanup.
- - * (this will usually be overridden later.)
- - */
- - if (is_input)
- - qtd->hw_alt_next = fotg210->async->hw->hw_alt_next;
- -
- - /* qh makes control packets use qtd toggle; maybe switch it */
- - if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
- - token ^= QTD_TOGGLE;
- -
- - if (likely(this_sg_len <= 0)) {
- - if (--i <= 0 || len <= 0)
- - break;
- - sg = sg_next(sg);
- - buf = sg_dma_address(sg);
- - this_sg_len = min_t(int, sg_dma_len(sg), len);
- - }
- -
- - qtd_prev = qtd;
- - qtd = fotg210_qtd_alloc(fotg210, flags);
- - if (unlikely(!qtd))
- - goto cleanup;
- - qtd->urb = urb;
- - qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
- - list_add_tail(&qtd->qtd_list, head);
- - }
- -
- - /*
- - * unless the caller requires manual cleanup after short reads,
- - * have the alt_next mechanism keep the queue running after the
- - * last data qtd (the only one, for control and most other cases).
- - */
- - if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0 ||
- - usb_pipecontrol(urb->pipe)))
- - qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
- -
- - /*
- - * control requests may need a terminating data "status" ack;
- - * other OUT ones may need a terminating short packet
- - * (zero length).
- - */
- - if (likely(urb->transfer_buffer_length != 0)) {
- - int one_more = 0;
- -
- - if (usb_pipecontrol(urb->pipe)) {
- - one_more = 1;
- - token ^= 0x0100; /* "in" <--> "out" */
- - token |= QTD_TOGGLE; /* force DATA1 */
- - } else if (usb_pipeout(urb->pipe)
- - && (urb->transfer_flags & URB_ZERO_PACKET)
- - && !(urb->transfer_buffer_length % maxpacket)) {
- - one_more = 1;
- - }
- - if (one_more) {
- - qtd_prev = qtd;
- - qtd = fotg210_qtd_alloc(fotg210, flags);
- - if (unlikely(!qtd))
- - goto cleanup;
- - qtd->urb = urb;
- - qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
- - list_add_tail(&qtd->qtd_list, head);
- -
- - /* never any data in such packets */
- - qtd_fill(fotg210, qtd, 0, 0, token, 0);
- - }
- - }
- -
- - /* by default, enable interrupt on urb completion */
- - if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
- - qtd->hw_token |= cpu_to_hc32(fotg210, QTD_IOC);
- - return head;
- -
- -cleanup:
- - qtd_list_free(fotg210, urb, head);
- - return NULL;
- -}
- -
- -/* Would be best to create all qh's from config descriptors,
- - * when each interface/altsetting is established. Unlink
- - * any previous qh and cancel its urbs first; endpoints are
- - * implicitly reset then (data toggle too).
- - * That'd mean updating how usbcore talks to HCDs. (2.7?)
- - */
- -
- -
- -/* Each QH holds a qtd list; a QH is used for everything except iso.
- - *
- - * For interrupt urbs, the scheduler must set the microframe scheduling
- - * mask(s) each time the QH gets scheduled. For highspeed, that's
- - * just one microframe in the s-mask. For split interrupt transactions
- - * there are additional complications: c-mask, maybe FSTNs.
- - */
- -static struct fotg210_qh *qh_make(struct fotg210_hcd *fotg210, struct urb *urb,
- - gfp_t flags)
- -{
- - struct fotg210_qh *qh = fotg210_qh_alloc(fotg210, flags);
- - struct usb_host_endpoint *ep;
- - u32 info1 = 0, info2 = 0;
- - int is_input, type;
- - int maxp = 0;
- - int mult;
- - struct usb_tt *tt = urb->dev->tt;
- - struct fotg210_qh_hw *hw;
- -
- - if (!qh)
- - return qh;
- -
- - /*
- - * init endpoint/device data for this QH
- - */
- - info1 |= usb_pipeendpoint(urb->pipe) << 8;
- - info1 |= usb_pipedevice(urb->pipe) << 0;
- -
- - is_input = usb_pipein(urb->pipe);
- - type = usb_pipetype(urb->pipe);
- - ep = usb_pipe_endpoint(urb->dev, urb->pipe);
- - maxp = usb_endpoint_maxp(&ep->desc);
- - mult = usb_endpoint_maxp_mult(&ep->desc);
- -
- - /* 1024 byte maxpacket is a hardware ceiling. High bandwidth
- - * acts like up to 3KB, but is built from smaller packets.
- - */
- - if (maxp > 1024) {
- - fotg210_dbg(fotg210, "bogus qh maxpacket %d\n", maxp);
- - goto done;
- - }
- -
- - /* Compute interrupt scheduling parameters just once, and save.
- - * - allowing for high bandwidth, how many nsec/uframe are used?
- - * - split transactions need a second CSPLIT uframe; same question
- - * - splits also need a schedule gap (for full/low speed I/O)
- - * - qh has a polling interval
- - *
- - * For control/bulk requests, the HC or TT handles these.
- - */
- - if (type == PIPE_INTERRUPT) {
- - qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
- - is_input, 0, mult * maxp));
- - qh->start = NO_FRAME;
- -
- - if (urb->dev->speed == USB_SPEED_HIGH) {
- - qh->c_usecs = 0;
- - qh->gap_uf = 0;
- -
- - qh->period = urb->interval >> 3;
- - if (qh->period == 0 && urb->interval != 1) {
- - /* NOTE interval 2 or 4 uframes could work.
- - * But interval 1 scheduling is simpler, and
- - * includes high bandwidth.
- - */
- - urb->interval = 1;
- - } else if (qh->period > fotg210->periodic_size) {
- - qh->period = fotg210->periodic_size;
- - urb->interval = qh->period << 3;
- - }
- - } else {
- - int think_time;
- -
- - /* gap is f(FS/LS transfer times) */
- - qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed,
- - is_input, 0, maxp) / (125 * 1000);
- -
- - /* FIXME this just approximates SPLIT/CSPLIT times */
- - if (is_input) { /* SPLIT, gap, CSPLIT+DATA */
- - qh->c_usecs = qh->usecs + HS_USECS(0);
- - qh->usecs = HS_USECS(1);
- - } else { /* SPLIT+DATA, gap, CSPLIT */
- - qh->usecs += HS_USECS(1);
- - qh->c_usecs = HS_USECS(0);
- - }
- -
- - think_time = tt ? tt->think_time : 0;
- - qh->tt_usecs = NS_TO_US(think_time +
- - usb_calc_bus_time(urb->dev->speed,
- - is_input, 0, maxp));
- - qh->period = urb->interval;
- - if (qh->period > fotg210->periodic_size) {
- - qh->period = fotg210->periodic_size;
- - urb->interval = qh->period;
- - }
- - }
- - }
- -
- - /* support for tt scheduling, and access to toggles */
- - qh->dev = urb->dev;
- -
- - /* using TT? */
- - switch (urb->dev->speed) {
- - case USB_SPEED_LOW:
- - info1 |= QH_LOW_SPEED;
- - fallthrough;
- -
- - case USB_SPEED_FULL:
- - /* EPS 0 means "full" */
- - if (type != PIPE_INTERRUPT)
- - info1 |= (FOTG210_TUNE_RL_TT << 28);
- - if (type == PIPE_CONTROL) {
- - info1 |= QH_CONTROL_EP; /* for TT */
- - info1 |= QH_TOGGLE_CTL; /* toggle from qtd */
- - }
- - info1 |= maxp << 16;
- -
- - info2 |= (FOTG210_TUNE_MULT_TT << 30);
- -
- - /* Some Freescale processors have an erratum in which the
- - * port number in the queue head was 0..N-1 instead of 1..N.
- - */
- - if (fotg210_has_fsl_portno_bug(fotg210))
- - info2 |= (urb->dev->ttport-1) << 23;
- - else
- - info2 |= urb->dev->ttport << 23;
- -
- - /* set the address of the TT; for TDI's integrated
- - * root hub tt, leave it zeroed.
- - */
- - if (tt && tt->hub != fotg210_to_hcd(fotg210)->self.root_hub)
- - info2 |= tt->hub->devnum << 16;
- -
- - /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */
- -
- - break;
- -
- - case USB_SPEED_HIGH: /* no TT involved */
- - info1 |= QH_HIGH_SPEED;
- - if (type == PIPE_CONTROL) {
- - info1 |= (FOTG210_TUNE_RL_HS << 28);
- - info1 |= 64 << 16; /* usb2 fixed maxpacket */
- - info1 |= QH_TOGGLE_CTL; /* toggle from qtd */
- - info2 |= (FOTG210_TUNE_MULT_HS << 30);
- - } else if (type == PIPE_BULK) {
- - info1 |= (FOTG210_TUNE_RL_HS << 28);
- - /* The USB spec says that high speed bulk endpoints
- - * always use 512 byte maxpacket. But some device
- - * vendors decided to ignore that, and MSFT is happy
- - * to help them do so. So now people expect to use
- - * such nonconformant devices with Linux too; sigh.
- - */
- - info1 |= maxp << 16;
- - info2 |= (FOTG210_TUNE_MULT_HS << 30);
- - } else { /* PIPE_INTERRUPT */
- - info1 |= maxp << 16;
- - info2 |= mult << 30;
- - }
- - break;
- - default:
- - fotg210_dbg(fotg210, "bogus dev %p speed %d\n", urb->dev,
- - urb->dev->speed);
- -done:
- - qh_destroy(fotg210, qh);
- - return NULL;
- - }
- -
- - /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */
- -
- - /* init as live, toggle clear, advance to dummy */
- - qh->qh_state = QH_STATE_IDLE;
- - hw = qh->hw;
- - hw->hw_info1 = cpu_to_hc32(fotg210, info1);
- - hw->hw_info2 = cpu_to_hc32(fotg210, info2);
- - qh->is_out = !is_input;
- - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1);
- - qh_refresh(fotg210, qh);
- - return qh;
- -}
- -
- -static void enable_async(struct fotg210_hcd *fotg210)
- -{
- - if (fotg210->async_count++)
- - return;
- -
- - /* Stop waiting to turn off the async schedule */
- - fotg210->enabled_hrtimer_events &= ~BIT(FOTG210_HRTIMER_DISABLE_ASYNC);
- -
- - /* Don't start the schedule until ASS is 0 */
- - fotg210_poll_ASS(fotg210);
- - turn_on_io_watchdog(fotg210);
- -}
- -
- -static void disable_async(struct fotg210_hcd *fotg210)
- -{
- - if (--fotg210->async_count)
- - return;
- -
- - /* The async schedule and async_unlink list are supposed to be empty */
- - WARN_ON(fotg210->async->qh_next.qh || fotg210->async_unlink);
- -
- - /* Don't turn off the schedule until ASS is 1 */
- - fotg210_poll_ASS(fotg210);
- -}
- -
- -/* move qh (and its qtds) onto async queue; maybe enable queue. */
- -
- -static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- -{
- - __hc32 dma = QH_NEXT(fotg210, qh->qh_dma);
- - struct fotg210_qh *head;
- -
- - /* Don't link a QH if there's a Clear-TT-Buffer pending */
- - if (unlikely(qh->clearing_tt))
- - return;
- -
- - WARN_ON(qh->qh_state != QH_STATE_IDLE);
- -
- - /* clear halt and/or toggle; and maybe recover from silicon quirk */
- - qh_refresh(fotg210, qh);
- -
- - /* splice right after start */
- - head = fotg210->async;
- - qh->qh_next = head->qh_next;
- - qh->hw->hw_next = head->hw->hw_next;
- - wmb();
- -
- - head->qh_next.qh = qh;
- - head->hw->hw_next = dma;
- -
- - qh->xacterrs = 0;
- - qh->qh_state = QH_STATE_LINKED;
- - /* qtd completions reported later by interrupt */
- -
- - enable_async(fotg210);
- -}
- -
- -/* For control/bulk/interrupt, return QH with these TDs appended.
- - * Allocates and initializes the QH if necessary.
- - * Returns null if it can't allocate a QH it needs to.
- - * If the QH has TDs (urbs) already, that's great.
- - */
- -static struct fotg210_qh *qh_append_tds(struct fotg210_hcd *fotg210,
- - struct urb *urb, struct list_head *qtd_list,
- - int epnum, void **ptr)
- -{
- - struct fotg210_qh *qh = NULL;
- - __hc32 qh_addr_mask = cpu_to_hc32(fotg210, 0x7f);
- -
- - qh = (struct fotg210_qh *) *ptr;
- - if (unlikely(qh == NULL)) {
- - /* can't sleep here, we have fotg210->lock... */
- - qh = qh_make(fotg210, urb, GFP_ATOMIC);
- - *ptr = qh;
- - }
- - if (likely(qh != NULL)) {
- - struct fotg210_qtd *qtd;
- -
- - if (unlikely(list_empty(qtd_list)))
- - qtd = NULL;
- - else
- - qtd = list_entry(qtd_list->next, struct fotg210_qtd,
- - qtd_list);
- -
- - /* control qh may need patching ... */
- - if (unlikely(epnum == 0)) {
- - /* usb_reset_device() briefly reverts to address 0 */
- - if (usb_pipedevice(urb->pipe) == 0)
- - qh->hw->hw_info1 &= ~qh_addr_mask;
- - }
- -
- - /* just one way to queue requests: swap with the dummy qtd.
- - * only hc or qh_refresh() ever modify the overlay.
- - */
- - if (likely(qtd != NULL)) {
- - struct fotg210_qtd *dummy;
- - dma_addr_t dma;
- - __hc32 token;
- -
- - /* to avoid racing the HC, use the dummy td instead of
- - * the first td of our list (becomes new dummy). both
- - * tds stay deactivated until we're done, when the
- - * HC is allowed to fetch the old dummy (4.10.2).
- - */
- - token = qtd->hw_token;
- - qtd->hw_token = HALT_BIT(fotg210);
- -
- - dummy = qh->dummy;
- -
- - dma = dummy->qtd_dma;
- - *dummy = *qtd;
- - dummy->qtd_dma = dma;
- -
- - list_del(&qtd->qtd_list);
- - list_add(&dummy->qtd_list, qtd_list);
- - list_splice_tail(qtd_list, &qh->qtd_list);
- -
- - fotg210_qtd_init(fotg210, qtd, qtd->qtd_dma);
- - qh->dummy = qtd;
- -
- - /* hc must see the new dummy at list end */
- - dma = qtd->qtd_dma;
- - qtd = list_entry(qh->qtd_list.prev,
- - struct fotg210_qtd, qtd_list);
- - qtd->hw_next = QTD_NEXT(fotg210, dma);
- -
- - /* let the hc process these next qtds */
- - wmb();
- - dummy->hw_token = token;
- -
- - urb->hcpriv = qh;
- - }
- - }
- - return qh;
- -}
- -
- -static int submit_async(struct fotg210_hcd *fotg210, struct urb *urb,
- - struct list_head *qtd_list, gfp_t mem_flags)
- -{
- - int epnum;
- - unsigned long flags;
- - struct fotg210_qh *qh = NULL;
- - int rc;
- -
- - epnum = urb->ep->desc.bEndpointAddress;
- -
- -#ifdef FOTG210_URB_TRACE
- - {
- - struct fotg210_qtd *qtd;
- -
- - qtd = list_entry(qtd_list->next, struct fotg210_qtd, qtd_list);
- - fotg210_dbg(fotg210,
- - "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
- - __func__, urb->dev->devpath, urb,
- - epnum & 0x0f, (epnum & USB_DIR_IN)
- - ? "in" : "out",
- - urb->transfer_buffer_length,
- - qtd, urb->ep->hcpriv);
- - }
- -#endif
- -
- - spin_lock_irqsave(&fotg210->lock, flags);
- - if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
- - rc = -ESHUTDOWN;
- - goto done;
- - }
- - rc = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
- - if (unlikely(rc))
- - goto done;
- -
- - qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
- - if (unlikely(qh == NULL)) {
- - usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
- - rc = -ENOMEM;
- - goto done;
- - }
- -
- - /* Control/bulk operations through TTs don't need scheduling,
- - * the HC and TT handle it when the TT has a buffer ready.
- - */
- - if (likely(qh->qh_state == QH_STATE_IDLE))
- - qh_link_async(fotg210, qh);
- -done:
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - if (unlikely(qh == NULL))
- - qtd_list_free(fotg210, urb, qtd_list);
- - return rc;
- -}
- -
- -static void single_unlink_async(struct fotg210_hcd *fotg210,
- - struct fotg210_qh *qh)
- -{
- - struct fotg210_qh *prev;
- -
- - /* Add to the end of the list of QHs waiting for the next IAAD */
- - qh->qh_state = QH_STATE_UNLINK;
- - if (fotg210->async_unlink)
- - fotg210->async_unlink_last->unlink_next = qh;
- - else
- - fotg210->async_unlink = qh;
- - fotg210->async_unlink_last = qh;
- -
- - /* Unlink it from the schedule */
- - prev = fotg210->async;
- - while (prev->qh_next.qh != qh)
- - prev = prev->qh_next.qh;
- -
- - prev->hw->hw_next = qh->hw->hw_next;
- - prev->qh_next = qh->qh_next;
- - if (fotg210->qh_scan_next == qh)
- - fotg210->qh_scan_next = qh->qh_next.qh;
- -}
- -
- -static void start_iaa_cycle(struct fotg210_hcd *fotg210, bool nested)
- -{
- - /*
- - * Do nothing if an IAA cycle is already running or
- - * if one will be started shortly.
- - */
- - if (fotg210->async_iaa || fotg210->async_unlinking)
- - return;
- -
- - /* Do all the waiting QHs at once */
- - fotg210->async_iaa = fotg210->async_unlink;
- - fotg210->async_unlink = NULL;
- -
- - /* If the controller isn't running, we don't have to wait for it */
- - if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) {
- - if (!nested) /* Avoid recursion */
- - end_unlink_async(fotg210);
- -
- - /* Otherwise start a new IAA cycle */
- - } else if (likely(fotg210->rh_state == FOTG210_RH_RUNNING)) {
- - /* Make sure the unlinks are all visible to the hardware */
- - wmb();
- -
- - fotg210_writel(fotg210, fotg210->command | CMD_IAAD,
- - &fotg210->regs->command);
- - fotg210_readl(fotg210, &fotg210->regs->command);
- - fotg210_enable_event(fotg210, FOTG210_HRTIMER_IAA_WATCHDOG,
- - true);
- - }
- -}
- -
- -/* the async qh for the qtds being unlinked are now gone from the HC */
- -
- -static void end_unlink_async(struct fotg210_hcd *fotg210)
- -{
- - struct fotg210_qh *qh;
- -
- - /* Process the idle QHs */
- -restart:
- - fotg210->async_unlinking = true;
- - while (fotg210->async_iaa) {
- - qh = fotg210->async_iaa;
- - fotg210->async_iaa = qh->unlink_next;
- - qh->unlink_next = NULL;
- -
- - qh->qh_state = QH_STATE_IDLE;
- - qh->qh_next.qh = NULL;
- -
- - qh_completions(fotg210, qh);
- - if (!list_empty(&qh->qtd_list) &&
- - fotg210->rh_state == FOTG210_RH_RUNNING)
- - qh_link_async(fotg210, qh);
- - disable_async(fotg210);
- - }
- - fotg210->async_unlinking = false;
- -
- - /* Start a new IAA cycle if any QHs are waiting for it */
- - if (fotg210->async_unlink) {
- - start_iaa_cycle(fotg210, true);
- - if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING))
- - goto restart;
- - }
- -}
- -
- -static void unlink_empty_async(struct fotg210_hcd *fotg210)
- -{
- - struct fotg210_qh *qh, *next;
- - bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING);
- - bool check_unlinks_later = false;
- -
- - /* Unlink all the async QHs that have been empty for a timer cycle */
- - next = fotg210->async->qh_next.qh;
- - while (next) {
- - qh = next;
- - next = qh->qh_next.qh;
- -
- - if (list_empty(&qh->qtd_list) &&
- - qh->qh_state == QH_STATE_LINKED) {
- - if (!stopped && qh->unlink_cycle ==
- - fotg210->async_unlink_cycle)
- - check_unlinks_later = true;
- - else
- - single_unlink_async(fotg210, qh);
- - }
- - }
- -
- - /* Start a new IAA cycle if any QHs are waiting for it */
- - if (fotg210->async_unlink)
- - start_iaa_cycle(fotg210, false);
- -
- - /* QHs that haven't been empty for long enough will be handled later */
- - if (check_unlinks_later) {
- - fotg210_enable_event(fotg210, FOTG210_HRTIMER_ASYNC_UNLINKS,
- - true);
- - ++fotg210->async_unlink_cycle;
- - }
- -}
- -
- -/* makes sure the async qh will become idle */
- -/* caller must own fotg210->lock */
- -
- -static void start_unlink_async(struct fotg210_hcd *fotg210,
- - struct fotg210_qh *qh)
- -{
- - /*
- - * If the QH isn't linked then there's nothing we can do
- - * unless we were called during a giveback, in which case
- - * qh_completions() has to deal with it.
- - */
- - if (qh->qh_state != QH_STATE_LINKED) {
- - if (qh->qh_state == QH_STATE_COMPLETING)
- - qh->needs_rescan = 1;
- - return;
- - }
- -
- - single_unlink_async(fotg210, qh);
- - start_iaa_cycle(fotg210, false);
- -}
- -
- -static void scan_async(struct fotg210_hcd *fotg210)
- -{
- - struct fotg210_qh *qh;
- - bool check_unlinks_later = false;
- -
- - fotg210->qh_scan_next = fotg210->async->qh_next.qh;
- - while (fotg210->qh_scan_next) {
- - qh = fotg210->qh_scan_next;
- - fotg210->qh_scan_next = qh->qh_next.qh;
- -rescan:
- - /* clean any finished work for this qh */
- - if (!list_empty(&qh->qtd_list)) {
- - int temp;
- -
- - /*
- - * Unlinks could happen here; completion reporting
- - * drops the lock. That's why fotg210->qh_scan_next
- - * always holds the next qh to scan; if the next qh
- - * gets unlinked then fotg210->qh_scan_next is adjusted
- - * in single_unlink_async().
- - */
- - temp = qh_completions(fotg210, qh);
- - if (qh->needs_rescan) {
- - start_unlink_async(fotg210, qh);
- - } else if (list_empty(&qh->qtd_list)
- - && qh->qh_state == QH_STATE_LINKED) {
- - qh->unlink_cycle = fotg210->async_unlink_cycle;
- - check_unlinks_later = true;
- - } else if (temp != 0)
- - goto rescan;
- - }
- - }
- -
- - /*
- - * Unlink empty entries, reducing DMA usage as well
- - * as HCD schedule-scanning costs. Delay for any qh
- - * we just scanned, there's a not-unusual case that it
- - * doesn't stay idle for long.
- - */
- - if (check_unlinks_later && fotg210->rh_state == FOTG210_RH_RUNNING &&
- - !(fotg210->enabled_hrtimer_events &
- - BIT(FOTG210_HRTIMER_ASYNC_UNLINKS))) {
- - fotg210_enable_event(fotg210,
- - FOTG210_HRTIMER_ASYNC_UNLINKS, true);
- - ++fotg210->async_unlink_cycle;
- - }
- -}
- -/* EHCI scheduled transaction support: interrupt, iso, split iso
- - * These are called "periodic" transactions in the EHCI spec.
- - *
- - * Note that for interrupt transfers, the QH/QTD manipulation is shared
- - * with the "asynchronous" transaction support (control/bulk transfers).
- - * The only real difference is in how interrupt transfers are scheduled.
- - *
- - * For ISO, we make an "iso_stream" head to serve the same role as a QH.
- - * It keeps track of every ITD (or SITD) that's linked, and holds enough
- - * pre-calculated schedule data to make appending to the queue be quick.
- - */
- -static int fotg210_get_frame(struct usb_hcd *hcd);
- -
- -/* periodic_next_shadow - return "next" pointer on shadow list
- - * @periodic: host pointer to qh/itd
- - * @tag: hardware tag for type of this record
- - */
- -static union fotg210_shadow *periodic_next_shadow(struct fotg210_hcd *fotg210,
- - union fotg210_shadow *periodic, __hc32 tag)
- -{
- - switch (hc32_to_cpu(fotg210, tag)) {
- - case Q_TYPE_QH:
- - return &periodic->qh->qh_next;
- - case Q_TYPE_FSTN:
- - return &periodic->fstn->fstn_next;
- - default:
- - return &periodic->itd->itd_next;
- - }
- -}
- -
- -static __hc32 *shadow_next_periodic(struct fotg210_hcd *fotg210,
- - union fotg210_shadow *periodic, __hc32 tag)
- -{
- - switch (hc32_to_cpu(fotg210, tag)) {
- - /* our fotg210_shadow.qh is actually software part */
- - case Q_TYPE_QH:
- - return &periodic->qh->hw->hw_next;
- - /* others are hw parts */
- - default:
- - return periodic->hw_next;
- - }
- -}
- -
- -/* caller must hold fotg210->lock */
- -static void periodic_unlink(struct fotg210_hcd *fotg210, unsigned frame,
- - void *ptr)
- -{
- - union fotg210_shadow *prev_p = &fotg210->pshadow[frame];
- - __hc32 *hw_p = &fotg210->periodic[frame];
- - union fotg210_shadow here = *prev_p;
- -
- - /* find predecessor of "ptr"; hw and shadow lists are in sync */
- - while (here.ptr && here.ptr != ptr) {
- - prev_p = periodic_next_shadow(fotg210, prev_p,
- - Q_NEXT_TYPE(fotg210, *hw_p));
- - hw_p = shadow_next_periodic(fotg210, &here,
- - Q_NEXT_TYPE(fotg210, *hw_p));
- - here = *prev_p;
- - }
- - /* an interrupt entry (at list end) could have been shared */
- - if (!here.ptr)
- - return;
- -
- - /* update shadow and hardware lists ... the old "next" pointers
- - * from ptr may still be in use, the caller updates them.
- - */
- - *prev_p = *periodic_next_shadow(fotg210, &here,
- - Q_NEXT_TYPE(fotg210, *hw_p));
- -
- - *hw_p = *shadow_next_periodic(fotg210, &here,
- - Q_NEXT_TYPE(fotg210, *hw_p));
- -}
- -
- -/* how many of the uframe's 125 usecs are allocated? */
- -static unsigned short periodic_usecs(struct fotg210_hcd *fotg210,
- - unsigned frame, unsigned uframe)
- -{
- - __hc32 *hw_p = &fotg210->periodic[frame];
- - union fotg210_shadow *q = &fotg210->pshadow[frame];
- - unsigned usecs = 0;
- - struct fotg210_qh_hw *hw;
- -
- - while (q->ptr) {
- - switch (hc32_to_cpu(fotg210, Q_NEXT_TYPE(fotg210, *hw_p))) {
- - case Q_TYPE_QH:
- - hw = q->qh->hw;
- - /* is it in the S-mask? */
- - if (hw->hw_info2 & cpu_to_hc32(fotg210, 1 << uframe))
- - usecs += q->qh->usecs;
- - /* ... or C-mask? */
- - if (hw->hw_info2 & cpu_to_hc32(fotg210,
- - 1 << (8 + uframe)))
- - usecs += q->qh->c_usecs;
- - hw_p = &hw->hw_next;
- - q = &q->qh->qh_next;
- - break;
- - /* case Q_TYPE_FSTN: */
- - default:
- - /* for "save place" FSTNs, count the relevant INTR
- - * bandwidth from the previous frame
- - */
- - if (q->fstn->hw_prev != FOTG210_LIST_END(fotg210))
- - fotg210_dbg(fotg210, "ignoring FSTN cost ...\n");
- -
- - hw_p = &q->fstn->hw_next;
- - q = &q->fstn->fstn_next;
- - break;
- - case Q_TYPE_ITD:
- - if (q->itd->hw_transaction[uframe])
- - usecs += q->itd->stream->usecs;
- - hw_p = &q->itd->hw_next;
- - q = &q->itd->itd_next;
- - break;
- - }
- - }
- - if (usecs > fotg210->uframe_periodic_max)
- - fotg210_err(fotg210, "uframe %d sched overrun: %d usecs\n",
- - frame * 8 + uframe, usecs);
- - return usecs;
- -}
- -
- -static int same_tt(struct usb_device *dev1, struct usb_device *dev2)
- -{
- - if (!dev1->tt || !dev2->tt)
- - return 0;
- - if (dev1->tt != dev2->tt)
- - return 0;
- - if (dev1->tt->multi)
- - return dev1->ttport == dev2->ttport;
- - else
- - return 1;
- -}
- -
- -/* return true iff the device's transaction translator is available
- - * for a periodic transfer starting at the specified frame, using
- - * all the uframes in the mask.
- - */
- -static int tt_no_collision(struct fotg210_hcd *fotg210, unsigned period,
- - struct usb_device *dev, unsigned frame, u32 uf_mask)
- -{
- - if (period == 0) /* error */
- - return 0;
- -
- - /* note bandwidth wastage: split never follows csplit
- - * (different dev or endpoint) until the next uframe.
- - * calling convention doesn't make that distinction.
- - */
- - for (; frame < fotg210->periodic_size; frame += period) {
- - union fotg210_shadow here;
- - __hc32 type;
- - struct fotg210_qh_hw *hw;
- -
- - here = fotg210->pshadow[frame];
- - type = Q_NEXT_TYPE(fotg210, fotg210->periodic[frame]);
- - while (here.ptr) {
- - switch (hc32_to_cpu(fotg210, type)) {
- - case Q_TYPE_ITD:
- - type = Q_NEXT_TYPE(fotg210, here.itd->hw_next);
- - here = here.itd->itd_next;
- - continue;
- - case Q_TYPE_QH:
- - hw = here.qh->hw;
- - if (same_tt(dev, here.qh->dev)) {
- - u32 mask;
- -
- - mask = hc32_to_cpu(fotg210,
- - hw->hw_info2);
- - /* "knows" no gap is needed */
- - mask |= mask >> 8;
- - if (mask & uf_mask)
- - break;
- - }
- - type = Q_NEXT_TYPE(fotg210, hw->hw_next);
- - here = here.qh->qh_next;
- - continue;
- - /* case Q_TYPE_FSTN: */
- - default:
- - fotg210_dbg(fotg210,
- - "periodic frame %d bogus type %d\n",
- - frame, type);
- - }
- -
- - /* collision or error */
- - return 0;
- - }
- - }
- -
- - /* no collision */
- - return 1;
- -}
- -
- -static void enable_periodic(struct fotg210_hcd *fotg210)
- -{
- - if (fotg210->periodic_count++)
- - return;
- -
- - /* Stop waiting to turn off the periodic schedule */
- - fotg210->enabled_hrtimer_events &=
- - ~BIT(FOTG210_HRTIMER_DISABLE_PERIODIC);
- -
- - /* Don't start the schedule until PSS is 0 */
- - fotg210_poll_PSS(fotg210);
- - turn_on_io_watchdog(fotg210);
- -}
- -
- -static void disable_periodic(struct fotg210_hcd *fotg210)
- -{
- - if (--fotg210->periodic_count)
- - return;
- -
- - /* Don't turn off the schedule until PSS is 1 */
- - fotg210_poll_PSS(fotg210);
- -}
- -
- -/* periodic schedule slots have iso tds (normal or split) first, then a
- - * sparse tree for active interrupt transfers.
- - *
- - * this just links in a qh; caller guarantees uframe masks are set right.
- - * no FSTN support (yet; fotg210 0.96+)
- - */
- -static void qh_link_periodic(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- -{
- - unsigned i;
- - unsigned period = qh->period;
- -
- - dev_dbg(&qh->dev->dev,
- - "link qh%d-%04x/%p start %d [%d/%d us]\n", period,
- - hc32_to_cpup(fotg210, &qh->hw->hw_info2) &
- - (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs,
- - qh->c_usecs);
- -
- - /* high bandwidth, or otherwise every microframe */
- - if (period == 0)
- - period = 1;
- -
- - for (i = qh->start; i < fotg210->periodic_size; i += period) {
- - union fotg210_shadow *prev = &fotg210->pshadow[i];
- - __hc32 *hw_p = &fotg210->periodic[i];
- - union fotg210_shadow here = *prev;
- - __hc32 type = 0;
- -
- - /* skip the iso nodes at list head */
- - while (here.ptr) {
- - type = Q_NEXT_TYPE(fotg210, *hw_p);
- - if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
- - break;
- - prev = periodic_next_shadow(fotg210, prev, type);
- - hw_p = shadow_next_periodic(fotg210, &here, type);
- - here = *prev;
- - }
- -
- - /* sorting each branch by period (slow-->fast)
- - * enables sharing interior tree nodes
- - */
- - while (here.ptr && qh != here.qh) {
- - if (qh->period > here.qh->period)
- - break;
- - prev = &here.qh->qh_next;
- - hw_p = &here.qh->hw->hw_next;
- - here = *prev;
- - }
- - /* link in this qh, unless some earlier pass did that */
- - if (qh != here.qh) {
- - qh->qh_next = here;
- - if (here.qh)
- - qh->hw->hw_next = *hw_p;
- - wmb();
- - prev->qh = qh;
- - *hw_p = QH_NEXT(fotg210, qh->qh_dma);
- - }
- - }
- - qh->qh_state = QH_STATE_LINKED;
- - qh->xacterrs = 0;
- -
- - /* update per-qh bandwidth for usbfs */
- - fotg210_to_hcd(fotg210)->self.bandwidth_allocated += qh->period
- - ? ((qh->usecs + qh->c_usecs) / qh->period)
- - : (qh->usecs * 8);
- -
- - list_add(&qh->intr_node, &fotg210->intr_qh_list);
- -
- - /* maybe enable periodic schedule processing */
- - ++fotg210->intr_count;
- - enable_periodic(fotg210);
- -}
- -
- -static void qh_unlink_periodic(struct fotg210_hcd *fotg210,
- - struct fotg210_qh *qh)
- -{
- - unsigned i;
- - unsigned period;
- -
- - /*
- - * If qh is for a low/full-speed device, simply unlinking it
- - * could interfere with an ongoing split transaction. To unlink
- - * it safely would require setting the QH_INACTIVATE bit and
- - * waiting at least one frame, as described in EHCI 4.12.2.5.
- - *
- - * We won't bother with any of this. Instead, we assume that the
- - * only reason for unlinking an interrupt QH while the current URB
- - * is still active is to dequeue all the URBs (flush the whole
- - * endpoint queue).
- - *
- - * If rebalancing the periodic schedule is ever implemented, this
- - * approach will no longer be valid.
- - */
- -
- - /* high bandwidth, or otherwise part of every microframe */
- - period = qh->period;
- - if (!period)
- - period = 1;
- -
- - for (i = qh->start; i < fotg210->periodic_size; i += period)
- - periodic_unlink(fotg210, i, qh);
- -
- - /* update per-qh bandwidth for usbfs */
- - fotg210_to_hcd(fotg210)->self.bandwidth_allocated -= qh->period
- - ? ((qh->usecs + qh->c_usecs) / qh->period)
- - : (qh->usecs * 8);
- -
- - dev_dbg(&qh->dev->dev,
- - "unlink qh%d-%04x/%p start %d [%d/%d us]\n",
- - qh->period, hc32_to_cpup(fotg210, &qh->hw->hw_info2) &
- - (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs,
- - qh->c_usecs);
- -
- - /* qh->qh_next still "live" to HC */
- - qh->qh_state = QH_STATE_UNLINK;
- - qh->qh_next.ptr = NULL;
- -
- - if (fotg210->qh_scan_next == qh)
- - fotg210->qh_scan_next = list_entry(qh->intr_node.next,
- - struct fotg210_qh, intr_node);
- - list_del(&qh->intr_node);
- -}
- -
- -static void start_unlink_intr(struct fotg210_hcd *fotg210,
- - struct fotg210_qh *qh)
- -{
- - /* If the QH isn't linked then there's nothing we can do
- - * unless we were called during a giveback, in which case
- - * qh_completions() has to deal with it.
- - */
- - if (qh->qh_state != QH_STATE_LINKED) {
- - if (qh->qh_state == QH_STATE_COMPLETING)
- - qh->needs_rescan = 1;
- - return;
- - }
- -
- - qh_unlink_periodic(fotg210, qh);
- -
- - /* Make sure the unlinks are visible before starting the timer */
- - wmb();
- -
- - /*
- - * The EHCI spec doesn't say how long it takes the controller to
- - * stop accessing an unlinked interrupt QH. The timer delay is
- - * 9 uframes; presumably that will be long enough.
- - */
- - qh->unlink_cycle = fotg210->intr_unlink_cycle;
- -
- - /* New entries go at the end of the intr_unlink list */
- - if (fotg210->intr_unlink)
- - fotg210->intr_unlink_last->unlink_next = qh;
- - else
- - fotg210->intr_unlink = qh;
- - fotg210->intr_unlink_last = qh;
- -
- - if (fotg210->intr_unlinking)
- - ; /* Avoid recursive calls */
- - else if (fotg210->rh_state < FOTG210_RH_RUNNING)
- - fotg210_handle_intr_unlinks(fotg210);
- - else if (fotg210->intr_unlink == qh) {
- - fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
- - true);
- - ++fotg210->intr_unlink_cycle;
- - }
- -}
- -
- -static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- -{
- - struct fotg210_qh_hw *hw = qh->hw;
- - int rc;
- -
- - qh->qh_state = QH_STATE_IDLE;
- - hw->hw_next = FOTG210_LIST_END(fotg210);
- -
- - qh_completions(fotg210, qh);
- -
- - /* reschedule QH iff another request is queued */
- - if (!list_empty(&qh->qtd_list) &&
- - fotg210->rh_state == FOTG210_RH_RUNNING) {
- - rc = qh_schedule(fotg210, qh);
- -
- - /* An error here likely indicates handshake failure
- - * or no space left in the schedule. Neither fault
- - * should happen often ...
- - *
- - * FIXME kill the now-dysfunctional queued urbs
- - */
- - if (rc != 0)
- - fotg210_err(fotg210, "can't reschedule qh %p, err %d\n",
- - qh, rc);
- - }
- -
- - /* maybe turn off periodic schedule */
- - --fotg210->intr_count;
- - disable_periodic(fotg210);
- -}
- -
- -static int check_period(struct fotg210_hcd *fotg210, unsigned frame,
- - unsigned uframe, unsigned period, unsigned usecs)
- -{
- - int claimed;
- -
- - /* complete split running into next frame?
- - * given FSTN support, we could sometimes check...
- - */
- - if (uframe >= 8)
- - return 0;
- -
- - /* convert "usecs we need" to "max already claimed" */
- - usecs = fotg210->uframe_periodic_max - usecs;
- -
- - /* we "know" 2 and 4 uframe intervals were rejected; so
- - * for period 0, check _every_ microframe in the schedule.
- - */
- - if (unlikely(period == 0)) {
- - do {
- - for (uframe = 0; uframe < 7; uframe++) {
- - claimed = periodic_usecs(fotg210, frame,
- - uframe);
- - if (claimed > usecs)
- - return 0;
- - }
- - } while ((frame += 1) < fotg210->periodic_size);
- -
- - /* just check the specified uframe, at that period */
- - } else {
- - do {
- - claimed = periodic_usecs(fotg210, frame, uframe);
- - if (claimed > usecs)
- - return 0;
- - } while ((frame += period) < fotg210->periodic_size);
- - }
- -
- - /* success! */
- - return 1;
- -}
- -
- -static int check_intr_schedule(struct fotg210_hcd *fotg210, unsigned frame,
- - unsigned uframe, const struct fotg210_qh *qh, __hc32 *c_maskp)
- -{
- - int retval = -ENOSPC;
- - u8 mask = 0;
- -
- - if (qh->c_usecs && uframe >= 6) /* FSTN territory? */
- - goto done;
- -
- - if (!check_period(fotg210, frame, uframe, qh->period, qh->usecs))
- - goto done;
- - if (!qh->c_usecs) {
- - retval = 0;
- - *c_maskp = 0;
- - goto done;
- - }
- -
- - /* Make sure this tt's buffer is also available for CSPLITs.
- - * We pessimize a bit; probably the typical full speed case
- - * doesn't need the second CSPLIT.
- - *
- - * NOTE: both SPLIT and CSPLIT could be checked in just
- - * one smart pass...
- - */
- - mask = 0x03 << (uframe + qh->gap_uf);
- - *c_maskp = cpu_to_hc32(fotg210, mask << 8);
- -
- - mask |= 1 << uframe;
- - if (tt_no_collision(fotg210, qh->period, qh->dev, frame, mask)) {
- - if (!check_period(fotg210, frame, uframe + qh->gap_uf + 1,
- - qh->period, qh->c_usecs))
- - goto done;
- - if (!check_period(fotg210, frame, uframe + qh->gap_uf,
- - qh->period, qh->c_usecs))
- - goto done;
- - retval = 0;
- - }
- -done:
- - return retval;
- -}
- -
- -/* "first fit" scheduling policy used the first time through,
- - * or when the previous schedule slot can't be re-used.
- - */
- -static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- -{
- - int status;
- - unsigned uframe;
- - __hc32 c_mask;
- - unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
- - struct fotg210_qh_hw *hw = qh->hw;
- -
- - qh_refresh(fotg210, qh);
- - hw->hw_next = FOTG210_LIST_END(fotg210);
- - frame = qh->start;
- -
- - /* reuse the previous schedule slots, if we can */
- - if (frame < qh->period) {
- - uframe = ffs(hc32_to_cpup(fotg210, &hw->hw_info2) & QH_SMASK);
- - status = check_intr_schedule(fotg210, frame, --uframe,
- - qh, &c_mask);
- - } else {
- - uframe = 0;
- - c_mask = 0;
- - status = -ENOSPC;
- - }
- -
- - /* else scan the schedule to find a group of slots such that all
- - * uframes have enough periodic bandwidth available.
- - */
- - if (status) {
- - /* "normal" case, uframing flexible except with splits */
- - if (qh->period) {
- - int i;
- -
- - for (i = qh->period; status && i > 0; --i) {
- - frame = ++fotg210->random_frame % qh->period;
- - for (uframe = 0; uframe < 8; uframe++) {
- - status = check_intr_schedule(fotg210,
- - frame, uframe, qh,
- - &c_mask);
- - if (status == 0)
- - break;
- - }
- - }
- -
- - /* qh->period == 0 means every uframe */
- - } else {
- - frame = 0;
- - status = check_intr_schedule(fotg210, 0, 0, qh,
- - &c_mask);
- - }
- - if (status)
- - goto done;
- - qh->start = frame;
- -
- - /* reset S-frame and (maybe) C-frame masks */
- - hw->hw_info2 &= cpu_to_hc32(fotg210, ~(QH_CMASK | QH_SMASK));
- - hw->hw_info2 |= qh->period
- - ? cpu_to_hc32(fotg210, 1 << uframe)
- - : cpu_to_hc32(fotg210, QH_SMASK);
- - hw->hw_info2 |= c_mask;
- - } else
- - fotg210_dbg(fotg210, "reused qh %p schedule\n", qh);
- -
- - /* stuff into the periodic schedule */
- - qh_link_periodic(fotg210, qh);
- -done:
- - return status;
- -}
- -
- -static int intr_submit(struct fotg210_hcd *fotg210, struct urb *urb,
- - struct list_head *qtd_list, gfp_t mem_flags)
- -{
- - unsigned epnum;
- - unsigned long flags;
- - struct fotg210_qh *qh;
- - int status;
- - struct list_head empty;
- -
- - /* get endpoint and transfer/schedule data */
- - epnum = urb->ep->desc.bEndpointAddress;
- -
- - spin_lock_irqsave(&fotg210->lock, flags);
- -
- - if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
- - status = -ESHUTDOWN;
- - goto done_not_linked;
- - }
- - status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
- - if (unlikely(status))
- - goto done_not_linked;
- -
- - /* get qh and force any scheduling errors */
- - INIT_LIST_HEAD(&empty);
- - qh = qh_append_tds(fotg210, urb, &empty, epnum, &urb->ep->hcpriv);
- - if (qh == NULL) {
- - status = -ENOMEM;
- - goto done;
- - }
- - if (qh->qh_state == QH_STATE_IDLE) {
- - status = qh_schedule(fotg210, qh);
- - if (status)
- - goto done;
- - }
- -
- - /* then queue the urb's tds to the qh */
- - qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
- - BUG_ON(qh == NULL);
- -
- - /* ... update usbfs periodic stats */
- - fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs++;
- -
- -done:
- - if (unlikely(status))
- - usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
- -done_not_linked:
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - if (status)
- - qtd_list_free(fotg210, urb, qtd_list);
- -
- - return status;
- -}
- -
- -static void scan_intr(struct fotg210_hcd *fotg210)
- -{
- - struct fotg210_qh *qh;
- -
- - list_for_each_entry_safe(qh, fotg210->qh_scan_next,
- - &fotg210->intr_qh_list, intr_node) {
- -rescan:
- - /* clean any finished work for this qh */
- - if (!list_empty(&qh->qtd_list)) {
- - int temp;
- -
- - /*
- - * Unlinks could happen here; completion reporting
- - * drops the lock. That's why fotg210->qh_scan_next
- - * always holds the next qh to scan; if the next qh
- - * gets unlinked then fotg210->qh_scan_next is adjusted
- - * in qh_unlink_periodic().
- - */
- - temp = qh_completions(fotg210, qh);
- - if (unlikely(qh->needs_rescan ||
- - (list_empty(&qh->qtd_list) &&
- - qh->qh_state == QH_STATE_LINKED)))
- - start_unlink_intr(fotg210, qh);
- - else if (temp != 0)
- - goto rescan;
- - }
- - }
- -}
- -
- -/* fotg210_iso_stream ops work with both ITD and SITD */
- -
- -static struct fotg210_iso_stream *iso_stream_alloc(gfp_t mem_flags)
- -{
- - struct fotg210_iso_stream *stream;
- -
- - stream = kzalloc(sizeof(*stream), mem_flags);
- - if (likely(stream != NULL)) {
- - INIT_LIST_HEAD(&stream->td_list);
- - INIT_LIST_HEAD(&stream->free_list);
- - stream->next_uframe = -1;
- - }
- - return stream;
- -}
- -
- -static void iso_stream_init(struct fotg210_hcd *fotg210,
- - struct fotg210_iso_stream *stream, struct usb_device *dev,
- - int pipe, unsigned interval)
- -{
- - u32 buf1;
- - unsigned epnum, maxp;
- - int is_input;
- - long bandwidth;
- - unsigned multi;
- - struct usb_host_endpoint *ep;
- -
- - /*
- - * this might be a "high bandwidth" highspeed endpoint,
- - * as encoded in the ep descriptor's wMaxPacket field
- - */
- - epnum = usb_pipeendpoint(pipe);
- - is_input = usb_pipein(pipe) ? USB_DIR_IN : 0;
- - ep = usb_pipe_endpoint(dev, pipe);
- - maxp = usb_endpoint_maxp(&ep->desc);
- - if (is_input)
- - buf1 = (1 << 11);
- - else
- - buf1 = 0;
- -
- - multi = usb_endpoint_maxp_mult(&ep->desc);
- - buf1 |= maxp;
- - maxp *= multi;
- -
- - stream->buf0 = cpu_to_hc32(fotg210, (epnum << 8) | dev->devnum);
- - stream->buf1 = cpu_to_hc32(fotg210, buf1);
- - stream->buf2 = cpu_to_hc32(fotg210, multi);
- -
- - /* usbfs wants to report the average usecs per frame tied up
- - * when transfers on this endpoint are scheduled ...
- - */
- - if (dev->speed == USB_SPEED_FULL) {
- - interval <<= 3;
- - stream->usecs = NS_TO_US(usb_calc_bus_time(dev->speed,
- - is_input, 1, maxp));
- - stream->usecs /= 8;
- - } else {
- - stream->highspeed = 1;
- - stream->usecs = HS_USECS_ISO(maxp);
- - }
- - bandwidth = stream->usecs * 8;
- - bandwidth /= interval;
- -
- - stream->bandwidth = bandwidth;
- - stream->udev = dev;
- - stream->bEndpointAddress = is_input | epnum;
- - stream->interval = interval;
- - stream->maxp = maxp;
- -}
- -
- -static struct fotg210_iso_stream *iso_stream_find(struct fotg210_hcd *fotg210,
- - struct urb *urb)
- -{
- - unsigned epnum;
- - struct fotg210_iso_stream *stream;
- - struct usb_host_endpoint *ep;
- - unsigned long flags;
- -
- - epnum = usb_pipeendpoint(urb->pipe);
- - if (usb_pipein(urb->pipe))
- - ep = urb->dev->ep_in[epnum];
- - else
- - ep = urb->dev->ep_out[epnum];
- -
- - spin_lock_irqsave(&fotg210->lock, flags);
- - stream = ep->hcpriv;
- -
- - if (unlikely(stream == NULL)) {
- - stream = iso_stream_alloc(GFP_ATOMIC);
- - if (likely(stream != NULL)) {
- - ep->hcpriv = stream;
- - stream->ep = ep;
- - iso_stream_init(fotg210, stream, urb->dev, urb->pipe,
- - urb->interval);
- - }
- -
- - /* if dev->ep[epnum] is a QH, hw is set */
- - } else if (unlikely(stream->hw != NULL)) {
- - fotg210_dbg(fotg210, "dev %s ep%d%s, not iso??\n",
- - urb->dev->devpath, epnum,
- - usb_pipein(urb->pipe) ? "in" : "out");
- - stream = NULL;
- - }
- -
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - return stream;
- -}
- -
- -/* fotg210_iso_sched ops can be ITD-only or SITD-only */
- -
- -static struct fotg210_iso_sched *iso_sched_alloc(unsigned packets,
- - gfp_t mem_flags)
- -{
- - struct fotg210_iso_sched *iso_sched;
- -
- - iso_sched = kzalloc(struct_size(iso_sched, packet, packets), mem_flags);
- - if (likely(iso_sched != NULL))
- - INIT_LIST_HEAD(&iso_sched->td_list);
- -
- - return iso_sched;
- -}
- -
- -static inline void itd_sched_init(struct fotg210_hcd *fotg210,
- - struct fotg210_iso_sched *iso_sched,
- - struct fotg210_iso_stream *stream, struct urb *urb)
- -{
- - unsigned i;
- - dma_addr_t dma = urb->transfer_dma;
- -
- - /* how many uframes are needed for these transfers */
- - iso_sched->span = urb->number_of_packets * stream->interval;
- -
- - /* figure out per-uframe itd fields that we'll need later
- - * when we fit new itds into the schedule.
- - */
- - for (i = 0; i < urb->number_of_packets; i++) {
- - struct fotg210_iso_packet *uframe = &iso_sched->packet[i];
- - unsigned length;
- - dma_addr_t buf;
- - u32 trans;
- -
- - length = urb->iso_frame_desc[i].length;
- - buf = dma + urb->iso_frame_desc[i].offset;
- -
- - trans = FOTG210_ISOC_ACTIVE;
- - trans |= buf & 0x0fff;
- - if (unlikely(((i + 1) == urb->number_of_packets))
- - && !(urb->transfer_flags & URB_NO_INTERRUPT))
- - trans |= FOTG210_ITD_IOC;
- - trans |= length << 16;
- - uframe->transaction = cpu_to_hc32(fotg210, trans);
- -
- - /* might need to cross a buffer page within a uframe */
- - uframe->bufp = (buf & ~(u64)0x0fff);
- - buf += length;
- - if (unlikely((uframe->bufp != (buf & ~(u64)0x0fff))))
- - uframe->cross = 1;
- - }
- -}
- -
- -static void iso_sched_free(struct fotg210_iso_stream *stream,
- - struct fotg210_iso_sched *iso_sched)
- -{
- - if (!iso_sched)
- - return;
- - /* caller must hold fotg210->lock!*/
- - list_splice(&iso_sched->td_list, &stream->free_list);
- - kfree(iso_sched);
- -}
- -
- -static int itd_urb_transaction(struct fotg210_iso_stream *stream,
- - struct fotg210_hcd *fotg210, struct urb *urb, gfp_t mem_flags)
- -{
- - struct fotg210_itd *itd;
- - dma_addr_t itd_dma;
- - int i;
- - unsigned num_itds;
- - struct fotg210_iso_sched *sched;
- - unsigned long flags;
- -
- - sched = iso_sched_alloc(urb->number_of_packets, mem_flags);
- - if (unlikely(sched == NULL))
- - return -ENOMEM;
- -
- - itd_sched_init(fotg210, sched, stream, urb);
- -
- - if (urb->interval < 8)
- - num_itds = 1 + (sched->span + 7) / 8;
- - else
- - num_itds = urb->number_of_packets;
- -
- - /* allocate/init ITDs */
- - spin_lock_irqsave(&fotg210->lock, flags);
- - for (i = 0; i < num_itds; i++) {
- -
- - /*
- - * Use iTDs from the free list, but not iTDs that may
- - * still be in use by the hardware.
- - */
- - if (likely(!list_empty(&stream->free_list))) {
- - itd = list_first_entry(&stream->free_list,
- - struct fotg210_itd, itd_list);
- - if (itd->frame == fotg210->now_frame)
- - goto alloc_itd;
- - list_del(&itd->itd_list);
- - itd_dma = itd->itd_dma;
- - } else {
- -alloc_itd:
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - itd = dma_pool_alloc(fotg210->itd_pool, mem_flags,
- - &itd_dma);
- - spin_lock_irqsave(&fotg210->lock, flags);
- - if (!itd) {
- - iso_sched_free(stream, sched);
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - return -ENOMEM;
- - }
- - }
- -
- - memset(itd, 0, sizeof(*itd));
- - itd->itd_dma = itd_dma;
- - list_add(&itd->itd_list, &sched->td_list);
- - }
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- -
- - /* temporarily store schedule info in hcpriv */
- - urb->hcpriv = sched;
- - urb->error_count = 0;
- - return 0;
- -}
- -
- -static inline int itd_slot_ok(struct fotg210_hcd *fotg210, u32 mod, u32 uframe,
- - u8 usecs, u32 period)
- -{
- - uframe %= period;
- - do {
- - /* can't commit more than uframe_periodic_max usec */
- - if (periodic_usecs(fotg210, uframe >> 3, uframe & 0x7)
- - > (fotg210->uframe_periodic_max - usecs))
- - return 0;
- -
- - /* we know urb->interval is 2^N uframes */
- - uframe += period;
- - } while (uframe < mod);
- - return 1;
- -}
- -
- -/* This scheduler plans almost as far into the future as it has actual
- - * periodic schedule slots. (Affected by TUNE_FLS, which defaults to
- - * "as small as possible" to be cache-friendlier.) That limits the size
- - * transfers you can stream reliably; avoid more than 64 msec per urb.
- - * Also avoid queue depths of less than fotg210's worst irq latency (affected
- - * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter,
- - * and other factors); or more than about 230 msec total (for portability,
- - * given FOTG210_TUNE_FLS and the slop). Or, write a smarter scheduler!
- - */
- -
- -#define SCHEDULE_SLOP 80 /* microframes */
- -
- -static int iso_stream_schedule(struct fotg210_hcd *fotg210, struct urb *urb,
- - struct fotg210_iso_stream *stream)
- -{
- - u32 now, next, start, period, span;
- - int status;
- - unsigned mod = fotg210->periodic_size << 3;
- - struct fotg210_iso_sched *sched = urb->hcpriv;
- -
- - period = urb->interval;
- - span = sched->span;
- -
- - if (span > mod - SCHEDULE_SLOP) {
- - fotg210_dbg(fotg210, "iso request %p too long\n", urb);
- - status = -EFBIG;
- - goto fail;
- - }
- -
- - now = fotg210_read_frame_index(fotg210) & (mod - 1);
- -
- - /* Typical case: reuse current schedule, stream is still active.
- - * Hopefully there are no gaps from the host falling behind
- - * (irq delays etc), but if there are we'll take the next
- - * slot in the schedule, implicitly assuming URB_ISO_ASAP.
- - */
- - if (likely(!list_empty(&stream->td_list))) {
- - u32 excess;
- -
- - /* For high speed devices, allow scheduling within the
- - * isochronous scheduling threshold. For full speed devices
- - * and Intel PCI-based controllers, don't (work around for
- - * Intel ICH9 bug).
- - */
- - if (!stream->highspeed && fotg210->fs_i_thresh)
- - next = now + fotg210->i_thresh;
- - else
- - next = now;
- -
- - /* Fell behind (by up to twice the slop amount)?
- - * We decide based on the time of the last currently-scheduled
- - * slot, not the time of the next available slot.
- - */
- - excess = (stream->next_uframe - period - next) & (mod - 1);
- - if (excess >= mod - 2 * SCHEDULE_SLOP)
- - start = next + excess - mod + period *
- - DIV_ROUND_UP(mod - excess, period);
- - else
- - start = next + excess + period;
- - if (start - now >= mod) {
- - fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
- - urb, start - now - period, period,
- - mod);
- - status = -EFBIG;
- - goto fail;
- - }
- - }
- -
- - /* need to schedule; when's the next (u)frame we could start?
- - * this is bigger than fotg210->i_thresh allows; scheduling itself
- - * isn't free, the slop should handle reasonably slow cpus. it
- - * can also help high bandwidth if the dma and irq loads don't
- - * jump until after the queue is primed.
- - */
- - else {
- - int done = 0;
- -
- - start = SCHEDULE_SLOP + (now & ~0x07);
- -
- - /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */
- -
- - /* find a uframe slot with enough bandwidth.
- - * Early uframes are more precious because full-speed
- - * iso IN transfers can't use late uframes,
- - * and therefore they should be allocated last.
- - */
- - next = start;
- - start += period;
- - do {
- - start--;
- - /* check schedule: enough space? */
- - if (itd_slot_ok(fotg210, mod, start,
- - stream->usecs, period))
- - done = 1;
- - } while (start > next && !done);
- -
- - /* no room in the schedule */
- - if (!done) {
- - fotg210_dbg(fotg210, "iso resched full %p (now %d max %d)\n",
- - urb, now, now + mod);
- - status = -ENOSPC;
- - goto fail;
- - }
- - }
- -
- - /* Tried to schedule too far into the future? */
- - if (unlikely(start - now + span - period >=
- - mod - 2 * SCHEDULE_SLOP)) {
- - fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
- - urb, start - now, span - period,
- - mod - 2 * SCHEDULE_SLOP);
- - status = -EFBIG;
- - goto fail;
- - }
- -
- - stream->next_uframe = start & (mod - 1);
- -
- - /* report high speed start in uframes; full speed, in frames */
- - urb->start_frame = stream->next_uframe;
- - if (!stream->highspeed)
- - urb->start_frame >>= 3;
- -
- - /* Make sure scan_isoc() sees these */
- - if (fotg210->isoc_count == 0)
- - fotg210->next_frame = now >> 3;
- - return 0;
- -
- -fail:
- - iso_sched_free(stream, sched);
- - urb->hcpriv = NULL;
- - return status;
- -}
- -
- -static inline void itd_init(struct fotg210_hcd *fotg210,
- - struct fotg210_iso_stream *stream, struct fotg210_itd *itd)
- -{
- - int i;
- -
- - /* it's been recently zeroed */
- - itd->hw_next = FOTG210_LIST_END(fotg210);
- - itd->hw_bufp[0] = stream->buf0;
- - itd->hw_bufp[1] = stream->buf1;
- - itd->hw_bufp[2] = stream->buf2;
- -
- - for (i = 0; i < 8; i++)
- - itd->index[i] = -1;
- -
- - /* All other fields are filled when scheduling */
- -}
- -
- -static inline void itd_patch(struct fotg210_hcd *fotg210,
- - struct fotg210_itd *itd, struct fotg210_iso_sched *iso_sched,
- - unsigned index, u16 uframe)
- -{
- - struct fotg210_iso_packet *uf = &iso_sched->packet[index];
- - unsigned pg = itd->pg;
- -
- - uframe &= 0x07;
- - itd->index[uframe] = index;
- -
- - itd->hw_transaction[uframe] = uf->transaction;
- - itd->hw_transaction[uframe] |= cpu_to_hc32(fotg210, pg << 12);
- - itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, uf->bufp & ~(u32)0);
- - itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(uf->bufp >> 32));
- -
- - /* iso_frame_desc[].offset must be strictly increasing */
- - if (unlikely(uf->cross)) {
- - u64 bufp = uf->bufp + 4096;
- -
- - itd->pg = ++pg;
- - itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, bufp & ~(u32)0);
- - itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(bufp >> 32));
- - }
- -}
- -
- -static inline void itd_link(struct fotg210_hcd *fotg210, unsigned frame,
- - struct fotg210_itd *itd)
- -{
- - union fotg210_shadow *prev = &fotg210->pshadow[frame];
- - __hc32 *hw_p = &fotg210->periodic[frame];
- - union fotg210_shadow here = *prev;
- - __hc32 type = 0;
- -
- - /* skip any iso nodes which might belong to previous microframes */
- - while (here.ptr) {
- - type = Q_NEXT_TYPE(fotg210, *hw_p);
- - if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
- - break;
- - prev = periodic_next_shadow(fotg210, prev, type);
- - hw_p = shadow_next_periodic(fotg210, &here, type);
- - here = *prev;
- - }
- -
- - itd->itd_next = here;
- - itd->hw_next = *hw_p;
- - prev->itd = itd;
- - itd->frame = frame;
- - wmb();
- - *hw_p = cpu_to_hc32(fotg210, itd->itd_dma | Q_TYPE_ITD);
- -}
- -
- -/* fit urb's itds into the selected schedule slot; activate as needed */
- -static void itd_link_urb(struct fotg210_hcd *fotg210, struct urb *urb,
- - unsigned mod, struct fotg210_iso_stream *stream)
- -{
- - int packet;
- - unsigned next_uframe, uframe, frame;
- - struct fotg210_iso_sched *iso_sched = urb->hcpriv;
- - struct fotg210_itd *itd;
- -
- - next_uframe = stream->next_uframe & (mod - 1);
- -
- - if (unlikely(list_empty(&stream->td_list))) {
- - fotg210_to_hcd(fotg210)->self.bandwidth_allocated
- - += stream->bandwidth;
- - fotg210_dbg(fotg210,
- - "schedule devp %s ep%d%s-iso period %d start %d.%d\n",
- - urb->dev->devpath, stream->bEndpointAddress & 0x0f,
- - (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
- - urb->interval,
- - next_uframe >> 3, next_uframe & 0x7);
- - }
- -
- - /* fill iTDs uframe by uframe */
- - for (packet = 0, itd = NULL; packet < urb->number_of_packets;) {
- - if (itd == NULL) {
- - /* ASSERT: we have all necessary itds */
- -
- - /* ASSERT: no itds for this endpoint in this uframe */
- -
- - itd = list_entry(iso_sched->td_list.next,
- - struct fotg210_itd, itd_list);
- - list_move_tail(&itd->itd_list, &stream->td_list);
- - itd->stream = stream;
- - itd->urb = urb;
- - itd_init(fotg210, stream, itd);
- - }
- -
- - uframe = next_uframe & 0x07;
- - frame = next_uframe >> 3;
- -
- - itd_patch(fotg210, itd, iso_sched, packet, uframe);
- -
- - next_uframe += stream->interval;
- - next_uframe &= mod - 1;
- - packet++;
- -
- - /* link completed itds into the schedule */
- - if (((next_uframe >> 3) != frame)
- - || packet == urb->number_of_packets) {
- - itd_link(fotg210, frame & (fotg210->periodic_size - 1),
- - itd);
- - itd = NULL;
- - }
- - }
- - stream->next_uframe = next_uframe;
- -
- - /* don't need that schedule data any more */
- - iso_sched_free(stream, iso_sched);
- - urb->hcpriv = NULL;
- -
- - ++fotg210->isoc_count;
- - enable_periodic(fotg210);
- -}
- -
- -#define ISO_ERRS (FOTG210_ISOC_BUF_ERR | FOTG210_ISOC_BABBLE |\
- - FOTG210_ISOC_XACTERR)
- -
- -/* Process and recycle a completed ITD. Return true iff its urb completed,
- - * and hence its completion callback probably added things to the hardware
- - * schedule.
- - *
- - * Note that we carefully avoid recycling this descriptor until after any
- - * completion callback runs, so that it won't be reused quickly. That is,
- - * assuming (a) no more than two urbs per frame on this endpoint, and also
- - * (b) only this endpoint's completions submit URBs. It seems some silicon
- - * corrupts things if you reuse completed descriptors very quickly...
- - */
- -static bool itd_complete(struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
- -{
- - struct urb *urb = itd->urb;
- - struct usb_iso_packet_descriptor *desc;
- - u32 t;
- - unsigned uframe;
- - int urb_index = -1;
- - struct fotg210_iso_stream *stream = itd->stream;
- - struct usb_device *dev;
- - bool retval = false;
- -
- - /* for each uframe with a packet */
- - for (uframe = 0; uframe < 8; uframe++) {
- - if (likely(itd->index[uframe] == -1))
- - continue;
- - urb_index = itd->index[uframe];
- - desc = &urb->iso_frame_desc[urb_index];
- -
- - t = hc32_to_cpup(fotg210, &itd->hw_transaction[uframe]);
- - itd->hw_transaction[uframe] = 0;
- -
- - /* report transfer status */
- - if (unlikely(t & ISO_ERRS)) {
- - urb->error_count++;
- - if (t & FOTG210_ISOC_BUF_ERR)
- - desc->status = usb_pipein(urb->pipe)
- - ? -ENOSR /* hc couldn't read */
- - : -ECOMM; /* hc couldn't write */
- - else if (t & FOTG210_ISOC_BABBLE)
- - desc->status = -EOVERFLOW;
- - else /* (t & FOTG210_ISOC_XACTERR) */
- - desc->status = -EPROTO;
- -
- - /* HC need not update length with this error */
- - if (!(t & FOTG210_ISOC_BABBLE)) {
- - desc->actual_length = FOTG210_ITD_LENGTH(t);
- - urb->actual_length += desc->actual_length;
- - }
- - } else if (likely((t & FOTG210_ISOC_ACTIVE) == 0)) {
- - desc->status = 0;
- - desc->actual_length = FOTG210_ITD_LENGTH(t);
- - urb->actual_length += desc->actual_length;
- - } else {
- - /* URB was too late */
- - desc->status = -EXDEV;
- - }
- - }
- -
- - /* handle completion now? */
- - if (likely((urb_index + 1) != urb->number_of_packets))
- - goto done;
- -
- - /* ASSERT: it's really the last itd for this urb
- - * list_for_each_entry (itd, &stream->td_list, itd_list)
- - * BUG_ON (itd->urb == urb);
- - */
- -
- - /* give urb back to the driver; completion often (re)submits */
- - dev = urb->dev;
- - fotg210_urb_done(fotg210, urb, 0);
- - retval = true;
- - urb = NULL;
- -
- - --fotg210->isoc_count;
- - disable_periodic(fotg210);
- -
- - if (unlikely(list_is_singular(&stream->td_list))) {
- - fotg210_to_hcd(fotg210)->self.bandwidth_allocated
- - -= stream->bandwidth;
- - fotg210_dbg(fotg210,
- - "deschedule devp %s ep%d%s-iso\n",
- - dev->devpath, stream->bEndpointAddress & 0x0f,
- - (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
- - }
- -
- -done:
- - itd->urb = NULL;
- -
- - /* Add to the end of the free list for later reuse */
- - list_move_tail(&itd->itd_list, &stream->free_list);
- -
- - /* Recycle the iTDs when the pipeline is empty (ep no longer in use) */
- - if (list_empty(&stream->td_list)) {
- - list_splice_tail_init(&stream->free_list,
- - &fotg210->cached_itd_list);
- - start_free_itds(fotg210);
- - }
- -
- - return retval;
- -}
- -
- -static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb,
- - gfp_t mem_flags)
- -{
- - int status = -EINVAL;
- - unsigned long flags;
- - struct fotg210_iso_stream *stream;
- -
- - /* Get iso_stream head */
- - stream = iso_stream_find(fotg210, urb);
- - if (unlikely(stream == NULL)) {
- - fotg210_dbg(fotg210, "can't get iso stream\n");
- - return -ENOMEM;
- - }
- - if (unlikely(urb->interval != stream->interval &&
- - fotg210_port_speed(fotg210, 0) ==
- - USB_PORT_STAT_HIGH_SPEED)) {
- - fotg210_dbg(fotg210, "can't change iso interval %d --> %d\n",
- - stream->interval, urb->interval);
- - goto done;
- - }
- -
- -#ifdef FOTG210_URB_TRACE
- - fotg210_dbg(fotg210,
- - "%s %s urb %p ep%d%s len %d, %d pkts %d uframes[%p]\n",
- - __func__, urb->dev->devpath, urb,
- - usb_pipeendpoint(urb->pipe),
- - usb_pipein(urb->pipe) ? "in" : "out",
- - urb->transfer_buffer_length,
- - urb->number_of_packets, urb->interval,
- - stream);
- -#endif
- -
- - /* allocate ITDs w/o locking anything */
- - status = itd_urb_transaction(stream, fotg210, urb, mem_flags);
- - if (unlikely(status < 0)) {
- - fotg210_dbg(fotg210, "can't init itds\n");
- - goto done;
- - }
- -
- - /* schedule ... need to lock */
- - spin_lock_irqsave(&fotg210->lock, flags);
- - if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
- - status = -ESHUTDOWN;
- - goto done_not_linked;
- - }
- - status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
- - if (unlikely(status))
- - goto done_not_linked;
- - status = iso_stream_schedule(fotg210, urb, stream);
- - if (likely(status == 0))
- - itd_link_urb(fotg210, urb, fotg210->periodic_size << 3, stream);
- - else
- - usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
- -done_not_linked:
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- -done:
- - return status;
- -}
- -
- -static inline int scan_frame_queue(struct fotg210_hcd *fotg210, unsigned frame,
- - unsigned now_frame, bool live)
- -{
- - unsigned uf;
- - bool modified;
- - union fotg210_shadow q, *q_p;
- - __hc32 type, *hw_p;
- -
- - /* scan each element in frame's queue for completions */
- - q_p = &fotg210->pshadow[frame];
- - hw_p = &fotg210->periodic[frame];
- - q.ptr = q_p->ptr;
- - type = Q_NEXT_TYPE(fotg210, *hw_p);
- - modified = false;
- -
- - while (q.ptr) {
- - switch (hc32_to_cpu(fotg210, type)) {
- - case Q_TYPE_ITD:
- - /* If this ITD is still active, leave it for
- - * later processing ... check the next entry.
- - * No need to check for activity unless the
- - * frame is current.
- - */
- - if (frame == now_frame && live) {
- - rmb();
- - for (uf = 0; uf < 8; uf++) {
- - if (q.itd->hw_transaction[uf] &
- - ITD_ACTIVE(fotg210))
- - break;
- - }
- - if (uf < 8) {
- - q_p = &q.itd->itd_next;
- - hw_p = &q.itd->hw_next;
- - type = Q_NEXT_TYPE(fotg210,
- - q.itd->hw_next);
- - q = *q_p;
- - break;
- - }
- - }
- -
- - /* Take finished ITDs out of the schedule
- - * and process them: recycle, maybe report
- - * URB completion. HC won't cache the
- - * pointer for much longer, if at all.
- - */
- - *q_p = q.itd->itd_next;
- - *hw_p = q.itd->hw_next;
- - type = Q_NEXT_TYPE(fotg210, q.itd->hw_next);
- - wmb();
- - modified = itd_complete(fotg210, q.itd);
- - q = *q_p;
- - break;
- - default:
- - fotg210_dbg(fotg210, "corrupt type %d frame %d shadow %p\n",
- - type, frame, q.ptr);
- - fallthrough;
- - case Q_TYPE_QH:
- - case Q_TYPE_FSTN:
- - /* End of the iTDs and siTDs */
- - q.ptr = NULL;
- - break;
- - }
- -
- - /* assume completion callbacks modify the queue */
- - if (unlikely(modified && fotg210->isoc_count > 0))
- - return -EINVAL;
- - }
- - return 0;
- -}
- -
- -static void scan_isoc(struct fotg210_hcd *fotg210)
- -{
- - unsigned uf, now_frame, frame, ret;
- - unsigned fmask = fotg210->periodic_size - 1;
- - bool live;
- -
- - /*
- - * When running, scan from last scan point up to "now"
- - * else clean up by scanning everything that's left.
- - * Touches as few pages as possible: cache-friendly.
- - */
- - if (fotg210->rh_state >= FOTG210_RH_RUNNING) {
- - uf = fotg210_read_frame_index(fotg210);
- - now_frame = (uf >> 3) & fmask;
- - live = true;
- - } else {
- - now_frame = (fotg210->next_frame - 1) & fmask;
- - live = false;
- - }
- - fotg210->now_frame = now_frame;
- -
- - frame = fotg210->next_frame;
- - for (;;) {
- - ret = 1;
- - while (ret != 0)
- - ret = scan_frame_queue(fotg210, frame,
- - now_frame, live);
- -
- - /* Stop when we have reached the current frame */
- - if (frame == now_frame)
- - break;
- - frame = (frame + 1) & fmask;
- - }
- - fotg210->next_frame = now_frame;
- -}
- -
- -/* Display / Set uframe_periodic_max
- - */
- -static ssize_t uframe_periodic_max_show(struct device *dev,
- - struct device_attribute *attr, char *buf)
- -{
- - struct fotg210_hcd *fotg210;
- - int n;
- -
- - fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
- - n = scnprintf(buf, PAGE_SIZE, "%d\n", fotg210->uframe_periodic_max);
- - return n;
- -}
- -
- -
- -static ssize_t uframe_periodic_max_store(struct device *dev,
- - struct device_attribute *attr, const char *buf, size_t count)
- -{
- - struct fotg210_hcd *fotg210;
- - unsigned uframe_periodic_max;
- - unsigned frame, uframe;
- - unsigned short allocated_max;
- - unsigned long flags;
- - ssize_t ret;
- -
- - fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
- - if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
- - return -EINVAL;
- -
- - if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
- - fotg210_info(fotg210, "rejecting invalid request for uframe_periodic_max=%u\n",
- - uframe_periodic_max);
- - return -EINVAL;
- - }
- -
- - ret = -EINVAL;
- -
- - /*
- - * lock, so that our checking does not race with possible periodic
- - * bandwidth allocation through submitting new urbs.
- - */
- - spin_lock_irqsave(&fotg210->lock, flags);
- -
- - /*
- - * for request to decrease max periodic bandwidth, we have to check
- - * every microframe in the schedule to see whether the decrease is
- - * possible.
- - */
- - if (uframe_periodic_max < fotg210->uframe_periodic_max) {
- - allocated_max = 0;
- -
- - for (frame = 0; frame < fotg210->periodic_size; ++frame)
- - for (uframe = 0; uframe < 7; ++uframe)
- - allocated_max = max(allocated_max,
- - periodic_usecs(fotg210, frame,
- - uframe));
- -
- - if (allocated_max > uframe_periodic_max) {
- - fotg210_info(fotg210,
- - "cannot decrease uframe_periodic_max because periodic bandwidth is already allocated (%u > %u)\n",
- - allocated_max, uframe_periodic_max);
- - goto out_unlock;
- - }
- - }
- -
- - /* increasing is always ok */
- -
- - fotg210_info(fotg210,
- - "setting max periodic bandwidth to %u%% (== %u usec/uframe)\n",
- - 100 * uframe_periodic_max/125, uframe_periodic_max);
- -
- - if (uframe_periodic_max != 100)
- - fotg210_warn(fotg210, "max periodic bandwidth set is non-standard\n");
- -
- - fotg210->uframe_periodic_max = uframe_periodic_max;
- - ret = count;
- -
- -out_unlock:
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - return ret;
- -}
- -
- -static DEVICE_ATTR_RW(uframe_periodic_max);
- -
- -static inline int create_sysfs_files(struct fotg210_hcd *fotg210)
- -{
- - struct device *controller = fotg210_to_hcd(fotg210)->self.controller;
- -
- - return device_create_file(controller, &dev_attr_uframe_periodic_max);
- -}
- -
- -static inline void remove_sysfs_files(struct fotg210_hcd *fotg210)
- -{
- - struct device *controller = fotg210_to_hcd(fotg210)->self.controller;
- -
- - device_remove_file(controller, &dev_attr_uframe_periodic_max);
- -}
- -/* On some systems, leaving remote wakeup enabled prevents system shutdown.
- - * The firmware seems to think that powering off is a wakeup event!
- - * This routine turns off remote wakeup and everything else, on all ports.
- - */
- -static void fotg210_turn_off_all_ports(struct fotg210_hcd *fotg210)
- -{
- - u32 __iomem *status_reg = &fotg210->regs->port_status;
- -
- - fotg210_writel(fotg210, PORT_RWC_BITS, status_reg);
- -}
- -
- -/* Halt HC, turn off all ports, and let the BIOS use the companion controllers.
- - * Must be called with interrupts enabled and the lock not held.
- - */
- -static void fotg210_silence_controller(struct fotg210_hcd *fotg210)
- -{
- - fotg210_halt(fotg210);
- -
- - spin_lock_irq(&fotg210->lock);
- - fotg210->rh_state = FOTG210_RH_HALTED;
- - fotg210_turn_off_all_ports(fotg210);
- - spin_unlock_irq(&fotg210->lock);
- -}
- -
- -/* fotg210_shutdown kick in for silicon on any bus (not just pci, etc).
- - * This forcibly disables dma and IRQs, helping kexec and other cases
- - * where the next system software may expect clean state.
- - */
- -static void fotg210_shutdown(struct usb_hcd *hcd)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- -
- - spin_lock_irq(&fotg210->lock);
- - fotg210->shutdown = true;
- - fotg210->rh_state = FOTG210_RH_STOPPING;
- - fotg210->enabled_hrtimer_events = 0;
- - spin_unlock_irq(&fotg210->lock);
- -
- - fotg210_silence_controller(fotg210);
- -
- - hrtimer_cancel(&fotg210->hrtimer);
- -}
- -
- -/* fotg210_work is called from some interrupts, timers, and so on.
- - * it calls driver completion functions, after dropping fotg210->lock.
- - */
- -static void fotg210_work(struct fotg210_hcd *fotg210)
- -{
- - /* another CPU may drop fotg210->lock during a schedule scan while
- - * it reports urb completions. this flag guards against bogus
- - * attempts at re-entrant schedule scanning.
- - */
- - if (fotg210->scanning) {
- - fotg210->need_rescan = true;
- - return;
- - }
- - fotg210->scanning = true;
- -
- -rescan:
- - fotg210->need_rescan = false;
- - if (fotg210->async_count)
- - scan_async(fotg210);
- - if (fotg210->intr_count > 0)
- - scan_intr(fotg210);
- - if (fotg210->isoc_count > 0)
- - scan_isoc(fotg210);
- - if (fotg210->need_rescan)
- - goto rescan;
- - fotg210->scanning = false;
- -
- - /* the IO watchdog guards against hardware or driver bugs that
- - * misplace IRQs, and should let us run completely without IRQs.
- - * such lossage has been observed on both VT6202 and VT8235.
- - */
- - turn_on_io_watchdog(fotg210);
- -}
- -
- -/* Called when the fotg210_hcd module is removed.
- - */
- -static void fotg210_stop(struct usb_hcd *hcd)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- -
- - fotg210_dbg(fotg210, "stop\n");
- -
- - /* no more interrupts ... */
- -
- - spin_lock_irq(&fotg210->lock);
- - fotg210->enabled_hrtimer_events = 0;
- - spin_unlock_irq(&fotg210->lock);
- -
- - fotg210_quiesce(fotg210);
- - fotg210_silence_controller(fotg210);
- - fotg210_reset(fotg210);
- -
- - hrtimer_cancel(&fotg210->hrtimer);
- - remove_sysfs_files(fotg210);
- - remove_debug_files(fotg210);
- -
- - /* root hub is shut down separately (first, when possible) */
- - spin_lock_irq(&fotg210->lock);
- - end_free_itds(fotg210);
- - spin_unlock_irq(&fotg210->lock);
- - fotg210_mem_cleanup(fotg210);
- -
- -#ifdef FOTG210_STATS
- - fotg210_dbg(fotg210, "irq normal %ld err %ld iaa %ld (lost %ld)\n",
- - fotg210->stats.normal, fotg210->stats.error,
- - fotg210->stats.iaa, fotg210->stats.lost_iaa);
- - fotg210_dbg(fotg210, "complete %ld unlink %ld\n",
- - fotg210->stats.complete, fotg210->stats.unlink);
- -#endif
- -
- - dbg_status(fotg210, "fotg210_stop completed",
- - fotg210_readl(fotg210, &fotg210->regs->status));
- -}
- -
- -/* one-time init, only for memory state */
- -static int hcd_fotg210_init(struct usb_hcd *hcd)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- - u32 temp;
- - int retval;
- - u32 hcc_params;
- - struct fotg210_qh_hw *hw;
- -
- - spin_lock_init(&fotg210->lock);
- -
- - /*
- - * keep io watchdog by default, those good HCDs could turn off it later
- - */
- - fotg210->need_io_watchdog = 1;
- -
- - hrtimer_init(&fotg210->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
- - fotg210->hrtimer.function = fotg210_hrtimer_func;
- - fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
- -
- - hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
- -
- - /*
- - * by default set standard 80% (== 100 usec/uframe) max periodic
- - * bandwidth as required by USB 2.0
- - */
- - fotg210->uframe_periodic_max = 100;
- -
- - /*
- - * hw default: 1K periodic list heads, one per frame.
- - * periodic_size can shrink by USBCMD update if hcc_params allows.
- - */
- - fotg210->periodic_size = DEFAULT_I_TDPS;
- - INIT_LIST_HEAD(&fotg210->intr_qh_list);
- - INIT_LIST_HEAD(&fotg210->cached_itd_list);
- -
- - if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
- - /* periodic schedule size can be smaller than default */
- - switch (FOTG210_TUNE_FLS) {
- - case 0:
- - fotg210->periodic_size = 1024;
- - break;
- - case 1:
- - fotg210->periodic_size = 512;
- - break;
- - case 2:
- - fotg210->periodic_size = 256;
- - break;
- - default:
- - BUG();
- - }
- - }
- - retval = fotg210_mem_init(fotg210, GFP_KERNEL);
- - if (retval < 0)
- - return retval;
- -
- - /* controllers may cache some of the periodic schedule ... */
- - fotg210->i_thresh = 2;
- -
- - /*
- - * dedicate a qh for the async ring head, since we couldn't unlink
- - * a 'real' qh without stopping the async schedule [4.8]. use it
- - * as the 'reclamation list head' too.
- - * its dummy is used in hw_alt_next of many tds, to prevent the qh
- - * from automatically advancing to the next td after short reads.
- - */
- - fotg210->async->qh_next.qh = NULL;
- - hw = fotg210->async->hw;
- - hw->hw_next = QH_NEXT(fotg210, fotg210->async->qh_dma);
- - hw->hw_info1 = cpu_to_hc32(fotg210, QH_HEAD);
- - hw->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
- - hw->hw_qtd_next = FOTG210_LIST_END(fotg210);
- - fotg210->async->qh_state = QH_STATE_LINKED;
- - hw->hw_alt_next = QTD_NEXT(fotg210, fotg210->async->dummy->qtd_dma);
- -
- - /* clear interrupt enables, set irq latency */
- - if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
- - log2_irq_thresh = 0;
- - temp = 1 << (16 + log2_irq_thresh);
- - if (HCC_CANPARK(hcc_params)) {
- - /* HW default park == 3, on hardware that supports it (like
- - * NVidia and ALI silicon), maximizes throughput on the async
- - * schedule by avoiding QH fetches between transfers.
- - *
- - * With fast usb storage devices and NForce2, "park" seems to
- - * make problems: throughput reduction (!), data errors...
- - */
- - if (park) {
- - park = min_t(unsigned, park, 3);
- - temp |= CMD_PARK;
- - temp |= park << 8;
- - }
- - fotg210_dbg(fotg210, "park %d\n", park);
- - }
- - if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
- - /* periodic schedule size can be smaller than default */
- - temp &= ~(3 << 2);
- - temp |= (FOTG210_TUNE_FLS << 2);
- - }
- - fotg210->command = temp;
- -
- - /* Accept arbitrarily long scatter-gather lists */
- - if (!hcd->localmem_pool)
- - hcd->self.sg_tablesize = ~0;
- - return 0;
- -}
- -
- -/* start HC running; it's halted, hcd_fotg210_init() has been run (once) */
- -static int fotg210_run(struct usb_hcd *hcd)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- - u32 temp;
- -
- - hcd->uses_new_polling = 1;
- -
- - /* EHCI spec section 4.1 */
- -
- - fotg210_writel(fotg210, fotg210->periodic_dma,
- - &fotg210->regs->frame_list);
- - fotg210_writel(fotg210, (u32)fotg210->async->qh_dma,
- - &fotg210->regs->async_next);
- -
- - /*
- - * hcc_params controls whether fotg210->regs->segment must (!!!)
- - * be used; it constrains QH/ITD/SITD and QTD locations.
- - * dma_pool consistent memory always uses segment zero.
- - * streaming mappings for I/O buffers, like dma_map_single(),
- - * can return segments above 4GB, if the device allows.
- - *
- - * NOTE: the dma mask is visible through dev->dma_mask, so
- - * drivers can pass this info along ... like NETIF_F_HIGHDMA,
- - * Scsi_Host.highmem_io, and so forth. It's readonly to all
- - * host side drivers though.
- - */
- - fotg210_readl(fotg210, &fotg210->caps->hcc_params);
- -
- - /*
- - * Philips, Intel, and maybe others need CMD_RUN before the
- - * root hub will detect new devices (why?); NEC doesn't
- - */
- - fotg210->command &= ~(CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
- - fotg210->command |= CMD_RUN;
- - fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
- - dbg_cmd(fotg210, "init", fotg210->command);
- -
- - /*
- - * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
- - * are explicitly handed to companion controller(s), so no TT is
- - * involved with the root hub. (Except where one is integrated,
- - * and there's no companion controller unless maybe for USB OTG.)
- - *
- - * Turning on the CF flag will transfer ownership of all ports
- - * from the companions to the EHCI controller. If any of the
- - * companions are in the middle of a port reset at the time, it
- - * could cause trouble. Write-locking ehci_cf_port_reset_rwsem
- - * guarantees that no resets are in progress. After we set CF,
- - * a short delay lets the hardware catch up; new resets shouldn't
- - * be started before the port switching actions could complete.
- - */
- - down_write(&ehci_cf_port_reset_rwsem);
- - fotg210->rh_state = FOTG210_RH_RUNNING;
- - /* unblock posted writes */
- - fotg210_readl(fotg210, &fotg210->regs->command);
- - usleep_range(5000, 10000);
- - up_write(&ehci_cf_port_reset_rwsem);
- - fotg210->last_periodic_enable = ktime_get_real();
- -
- - temp = HC_VERSION(fotg210,
- - fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
- - fotg210_info(fotg210,
- - "USB %x.%x started, EHCI %x.%02x\n",
- - ((fotg210->sbrn & 0xf0) >> 4), (fotg210->sbrn & 0x0f),
- - temp >> 8, temp & 0xff);
- -
- - fotg210_writel(fotg210, INTR_MASK,
- - &fotg210->regs->intr_enable); /* Turn On Interrupts */
- -
- - /* GRR this is run-once init(), being done every time the HC starts.
- - * So long as they're part of class devices, we can't do it init()
- - * since the class device isn't created that early.
- - */
- - create_debug_files(fotg210);
- - create_sysfs_files(fotg210);
- -
- - return 0;
- -}
- -
- -static int fotg210_setup(struct usb_hcd *hcd)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- - int retval;
- -
- - fotg210->regs = (void __iomem *)fotg210->caps +
- - HC_LENGTH(fotg210,
- - fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
- - dbg_hcs_params(fotg210, "reset");
- - dbg_hcc_params(fotg210, "reset");
- -
- - /* cache this readonly data; minimize chip reads */
- - fotg210->hcs_params = fotg210_readl(fotg210,
- - &fotg210->caps->hcs_params);
- -
- - fotg210->sbrn = HCD_USB2;
- -
- - /* data structure init */
- - retval = hcd_fotg210_init(hcd);
- - if (retval)
- - return retval;
- -
- - retval = fotg210_halt(fotg210);
- - if (retval)
- - return retval;
- -
- - fotg210_reset(fotg210);
- -
- - return 0;
- -}
- -
- -static irqreturn_t fotg210_irq(struct usb_hcd *hcd)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- - u32 status, masked_status, pcd_status = 0, cmd;
- - int bh;
- -
- - spin_lock(&fotg210->lock);
- -
- - status = fotg210_readl(fotg210, &fotg210->regs->status);
- -
- - /* e.g. cardbus physical eject */
- - if (status == ~(u32) 0) {
- - fotg210_dbg(fotg210, "device removed\n");
- - goto dead;
- - }
- -
- - /*
- - * We don't use STS_FLR, but some controllers don't like it to
- - * remain on, so mask it out along with the other status bits.
- - */
- - masked_status = status & (INTR_MASK | STS_FLR);
- -
- - /* Shared IRQ? */
- - if (!masked_status ||
- - unlikely(fotg210->rh_state == FOTG210_RH_HALTED)) {
- - spin_unlock(&fotg210->lock);
- - return IRQ_NONE;
- - }
- -
- - /* clear (just) interrupts */
- - fotg210_writel(fotg210, masked_status, &fotg210->regs->status);
- - cmd = fotg210_readl(fotg210, &fotg210->regs->command);
- - bh = 0;
- -
- - /* unrequested/ignored: Frame List Rollover */
- - dbg_status(fotg210, "irq", status);
- -
- - /* INT, ERR, and IAA interrupt rates can be throttled */
- -
- - /* normal [4.15.1.2] or error [4.15.1.1] completion */
- - if (likely((status & (STS_INT|STS_ERR)) != 0)) {
- - if (likely((status & STS_ERR) == 0))
- - INCR(fotg210->stats.normal);
- - else
- - INCR(fotg210->stats.error);
- - bh = 1;
- - }
- -
- - /* complete the unlinking of some qh [4.15.2.3] */
- - if (status & STS_IAA) {
- -
- - /* Turn off the IAA watchdog */
- - fotg210->enabled_hrtimer_events &=
- - ~BIT(FOTG210_HRTIMER_IAA_WATCHDOG);
- -
- - /*
- - * Mild optimization: Allow another IAAD to reset the
- - * hrtimer, if one occurs before the next expiration.
- - * In theory we could always cancel the hrtimer, but
- - * tests show that about half the time it will be reset
- - * for some other event anyway.
- - */
- - if (fotg210->next_hrtimer_event == FOTG210_HRTIMER_IAA_WATCHDOG)
- - ++fotg210->next_hrtimer_event;
- -
- - /* guard against (alleged) silicon errata */
- - if (cmd & CMD_IAAD)
- - fotg210_dbg(fotg210, "IAA with IAAD still set?\n");
- - if (fotg210->async_iaa) {
- - INCR(fotg210->stats.iaa);
- - end_unlink_async(fotg210);
- - } else
- - fotg210_dbg(fotg210, "IAA with nothing unlinked?\n");
- - }
- -
- - /* remote wakeup [4.3.1] */
- - if (status & STS_PCD) {
- - int pstatus;
- - u32 __iomem *status_reg = &fotg210->regs->port_status;
- -
- - /* kick root hub later */
- - pcd_status = status;
- -
- - /* resume root hub? */
- - if (fotg210->rh_state == FOTG210_RH_SUSPENDED)
- - usb_hcd_resume_root_hub(hcd);
- -
- - pstatus = fotg210_readl(fotg210, status_reg);
- -
- - if (test_bit(0, &fotg210->suspended_ports) &&
- - ((pstatus & PORT_RESUME) ||
- - !(pstatus & PORT_SUSPEND)) &&
- - (pstatus & PORT_PE) &&
- - fotg210->reset_done[0] == 0) {
- -
- - /* start 20 msec resume signaling from this port,
- - * and make hub_wq collect PORT_STAT_C_SUSPEND to
- - * stop that signaling. Use 5 ms extra for safety,
- - * like usb_port_resume() does.
- - */
- - fotg210->reset_done[0] = jiffies + msecs_to_jiffies(25);
- - set_bit(0, &fotg210->resuming_ports);
- - fotg210_dbg(fotg210, "port 1 remote wakeup\n");
- - mod_timer(&hcd->rh_timer, fotg210->reset_done[0]);
- - }
- - }
- -
- - /* PCI errors [4.15.2.4] */
- - if (unlikely((status & STS_FATAL) != 0)) {
- - fotg210_err(fotg210, "fatal error\n");
- - dbg_cmd(fotg210, "fatal", cmd);
- - dbg_status(fotg210, "fatal", status);
- -dead:
- - usb_hc_died(hcd);
- -
- - /* Don't let the controller do anything more */
- - fotg210->shutdown = true;
- - fotg210->rh_state = FOTG210_RH_STOPPING;
- - fotg210->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE);
- - fotg210_writel(fotg210, fotg210->command,
- - &fotg210->regs->command);
- - fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
- - fotg210_handle_controller_death(fotg210);
- -
- - /* Handle completions when the controller stops */
- - bh = 0;
- - }
- -
- - if (bh)
- - fotg210_work(fotg210);
- - spin_unlock(&fotg210->lock);
- - if (pcd_status)
- - usb_hcd_poll_rh_status(hcd);
- - return IRQ_HANDLED;
- -}
- -
- -/* non-error returns are a promise to giveback() the urb later
- - * we drop ownership so next owner (or urb unlink) can get it
- - *
- - * urb + dev is in hcd.self.controller.urb_list
- - * we're queueing TDs onto software and hardware lists
- - *
- - * hcd-specific init for hcpriv hasn't been done yet
- - *
- - * NOTE: control, bulk, and interrupt share the same code to append TDs
- - * to a (possibly active) QH, and the same QH scanning code.
- - */
- -static int fotg210_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
- - gfp_t mem_flags)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- - struct list_head qtd_list;
- -
- - INIT_LIST_HEAD(&qtd_list);
- -
- - switch (usb_pipetype(urb->pipe)) {
- - case PIPE_CONTROL:
- - /* qh_completions() code doesn't handle all the fault cases
- - * in multi-TD control transfers. Even 1KB is rare anyway.
- - */
- - if (urb->transfer_buffer_length > (16 * 1024))
- - return -EMSGSIZE;
- - fallthrough;
- - /* case PIPE_BULK: */
- - default:
- - if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
- - return -ENOMEM;
- - return submit_async(fotg210, urb, &qtd_list, mem_flags);
- -
- - case PIPE_INTERRUPT:
- - if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
- - return -ENOMEM;
- - return intr_submit(fotg210, urb, &qtd_list, mem_flags);
- -
- - case PIPE_ISOCHRONOUS:
- - return itd_submit(fotg210, urb, mem_flags);
- - }
- -}
- -
- -/* remove from hardware lists
- - * completions normally happen asynchronously
- - */
- -
- -static int fotg210_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- - struct fotg210_qh *qh;
- - unsigned long flags;
- - int rc;
- -
- - spin_lock_irqsave(&fotg210->lock, flags);
- - rc = usb_hcd_check_unlink_urb(hcd, urb, status);
- - if (rc)
- - goto done;
- -
- - switch (usb_pipetype(urb->pipe)) {
- - /* case PIPE_CONTROL: */
- - /* case PIPE_BULK:*/
- - default:
- - qh = (struct fotg210_qh *) urb->hcpriv;
- - if (!qh)
- - break;
- - switch (qh->qh_state) {
- - case QH_STATE_LINKED:
- - case QH_STATE_COMPLETING:
- - start_unlink_async(fotg210, qh);
- - break;
- - case QH_STATE_UNLINK:
- - case QH_STATE_UNLINK_WAIT:
- - /* already started */
- - break;
- - case QH_STATE_IDLE:
- - /* QH might be waiting for a Clear-TT-Buffer */
- - qh_completions(fotg210, qh);
- - break;
- - }
- - break;
- -
- - case PIPE_INTERRUPT:
- - qh = (struct fotg210_qh *) urb->hcpriv;
- - if (!qh)
- - break;
- - switch (qh->qh_state) {
- - case QH_STATE_LINKED:
- - case QH_STATE_COMPLETING:
- - start_unlink_intr(fotg210, qh);
- - break;
- - case QH_STATE_IDLE:
- - qh_completions(fotg210, qh);
- - break;
- - default:
- - fotg210_dbg(fotg210, "bogus qh %p state %d\n",
- - qh, qh->qh_state);
- - goto done;
- - }
- - break;
- -
- - case PIPE_ISOCHRONOUS:
- - /* itd... */
- -
- - /* wait till next completion, do it then. */
- - /* completion irqs can wait up to 1024 msec, */
- - break;
- - }
- -done:
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - return rc;
- -}
- -
- -/* bulk qh holds the data toggle */
- -
- -static void fotg210_endpoint_disable(struct usb_hcd *hcd,
- - struct usb_host_endpoint *ep)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- - unsigned long flags;
- - struct fotg210_qh *qh, *tmp;
- -
- - /* ASSERT: any requests/urbs are being unlinked */
- - /* ASSERT: nobody can be submitting urbs for this any more */
- -
- -rescan:
- - spin_lock_irqsave(&fotg210->lock, flags);
- - qh = ep->hcpriv;
- - if (!qh)
- - goto done;
- -
- - /* endpoints can be iso streams. for now, we don't
- - * accelerate iso completions ... so spin a while.
- - */
- - if (qh->hw == NULL) {
- - struct fotg210_iso_stream *stream = ep->hcpriv;
- -
- - if (!list_empty(&stream->td_list))
- - goto idle_timeout;
- -
- - /* BUG_ON(!list_empty(&stream->free_list)); */
- - kfree(stream);
- - goto done;
- - }
- -
- - if (fotg210->rh_state < FOTG210_RH_RUNNING)
- - qh->qh_state = QH_STATE_IDLE;
- - switch (qh->qh_state) {
- - case QH_STATE_LINKED:
- - case QH_STATE_COMPLETING:
- - for (tmp = fotg210->async->qh_next.qh;
- - tmp && tmp != qh;
- - tmp = tmp->qh_next.qh)
- - continue;
- - /* periodic qh self-unlinks on empty, and a COMPLETING qh
- - * may already be unlinked.
- - */
- - if (tmp)
- - start_unlink_async(fotg210, qh);
- - fallthrough;
- - case QH_STATE_UNLINK: /* wait for hw to finish? */
- - case QH_STATE_UNLINK_WAIT:
- -idle_timeout:
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- - schedule_timeout_uninterruptible(1);
- - goto rescan;
- - case QH_STATE_IDLE: /* fully unlinked */
- - if (qh->clearing_tt)
- - goto idle_timeout;
- - if (list_empty(&qh->qtd_list)) {
- - qh_destroy(fotg210, qh);
- - break;
- - }
- - fallthrough;
- - default:
- - /* caller was supposed to have unlinked any requests;
- - * that's not our job. just leak this memory.
- - */
- - fotg210_err(fotg210, "qh %p (#%02x) state %d%s\n",
- - qh, ep->desc.bEndpointAddress, qh->qh_state,
- - list_empty(&qh->qtd_list) ? "" : "(has tds)");
- - break;
- - }
- -done:
- - ep->hcpriv = NULL;
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- -}
- -
- -static void fotg210_endpoint_reset(struct usb_hcd *hcd,
- - struct usb_host_endpoint *ep)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- - struct fotg210_qh *qh;
- - int eptype = usb_endpoint_type(&ep->desc);
- - int epnum = usb_endpoint_num(&ep->desc);
- - int is_out = usb_endpoint_dir_out(&ep->desc);
- - unsigned long flags;
- -
- - if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
- - return;
- -
- - spin_lock_irqsave(&fotg210->lock, flags);
- - qh = ep->hcpriv;
- -
- - /* For Bulk and Interrupt endpoints we maintain the toggle state
- - * in the hardware; the toggle bits in udev aren't used at all.
- - * When an endpoint is reset by usb_clear_halt() we must reset
- - * the toggle bit in the QH.
- - */
- - if (qh) {
- - usb_settoggle(qh->dev, epnum, is_out, 0);
- - if (!list_empty(&qh->qtd_list)) {
- - WARN_ONCE(1, "clear_halt for a busy endpoint\n");
- - } else if (qh->qh_state == QH_STATE_LINKED ||
- - qh->qh_state == QH_STATE_COMPLETING) {
- -
- - /* The toggle value in the QH can't be updated
- - * while the QH is active. Unlink it now;
- - * re-linking will call qh_refresh().
- - */
- - if (eptype == USB_ENDPOINT_XFER_BULK)
- - start_unlink_async(fotg210, qh);
- - else
- - start_unlink_intr(fotg210, qh);
- - }
- - }
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- -}
- -
- -static int fotg210_get_frame(struct usb_hcd *hcd)
- -{
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- -
- - return (fotg210_read_frame_index(fotg210) >> 3) %
- - fotg210->periodic_size;
- -}
- -
- -/* The EHCI in ChipIdea HDRC cannot be a separate module or device,
- - * because its registers (and irq) are shared between host/gadget/otg
- - * functions and in order to facilitate role switching we cannot
- - * give the fotg210 driver exclusive access to those.
- - */
- -MODULE_DESCRIPTION(DRIVER_DESC);
- -MODULE_AUTHOR(DRIVER_AUTHOR);
- -MODULE_LICENSE("GPL");
- -
- -static const struct hc_driver fotg210_fotg210_hc_driver = {
- - .description = hcd_name,
- - .product_desc = "Faraday USB2.0 Host Controller",
- - .hcd_priv_size = sizeof(struct fotg210_hcd),
- -
- - /*
- - * generic hardware linkage
- - */
- - .irq = fotg210_irq,
- - .flags = HCD_MEMORY | HCD_DMA | HCD_USB2,
- -
- - /*
- - * basic lifecycle operations
- - */
- - .reset = hcd_fotg210_init,
- - .start = fotg210_run,
- - .stop = fotg210_stop,
- - .shutdown = fotg210_shutdown,
- -
- - /*
- - * managing i/o requests and associated device resources
- - */
- - .urb_enqueue = fotg210_urb_enqueue,
- - .urb_dequeue = fotg210_urb_dequeue,
- - .endpoint_disable = fotg210_endpoint_disable,
- - .endpoint_reset = fotg210_endpoint_reset,
- -
- - /*
- - * scheduling support
- - */
- - .get_frame_number = fotg210_get_frame,
- -
- - /*
- - * root hub support
- - */
- - .hub_status_data = fotg210_hub_status_data,
- - .hub_control = fotg210_hub_control,
- - .bus_suspend = fotg210_bus_suspend,
- - .bus_resume = fotg210_bus_resume,
- -
- - .relinquish_port = fotg210_relinquish_port,
- - .port_handed_over = fotg210_port_handed_over,
- -
- - .clear_tt_buffer_complete = fotg210_clear_tt_buffer_complete,
- -};
- -
- -static void fotg210_init(struct fotg210_hcd *fotg210)
- -{
- - u32 value;
- -
- - iowrite32(GMIR_MDEV_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY,
- - &fotg210->regs->gmir);
- -
- - value = ioread32(&fotg210->regs->otgcsr);
- - value &= ~OTGCSR_A_BUS_DROP;
- - value |= OTGCSR_A_BUS_REQ;
- - iowrite32(value, &fotg210->regs->otgcsr);
- -}
- -
- -/*
- - * fotg210_hcd_probe - initialize faraday FOTG210 HCDs
- - *
- - * Allocates basic resources for this USB host controller, and
- - * then invokes the start() method for the HCD associated with it
- - * through the hotplug entry's driver_data.
- - */
- -static int fotg210_hcd_probe(struct platform_device *pdev)
- -{
- - struct device *dev = &pdev->dev;
- - struct usb_hcd *hcd;
- - struct resource *res;
- - int irq;
- - int retval;
- - struct fotg210_hcd *fotg210;
- -
- - if (usb_disabled())
- - return -ENODEV;
- -
- - pdev->dev.power.power_state = PMSG_ON;
- -
- - irq = platform_get_irq(pdev, 0);
- - if (irq < 0)
- - return irq;
- -
- - hcd = usb_create_hcd(&fotg210_fotg210_hc_driver, dev,
- - dev_name(dev));
- - if (!hcd) {
- - dev_err(dev, "failed to create hcd\n");
- - retval = -ENOMEM;
- - goto fail_create_hcd;
- - }
- -
- - hcd->has_tt = 1;
- -
- - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- - hcd->regs = devm_ioremap_resource(&pdev->dev, res);
- - if (IS_ERR(hcd->regs)) {
- - retval = PTR_ERR(hcd->regs);
- - goto failed_put_hcd;
- - }
- -
- - hcd->rsrc_start = res->start;
- - hcd->rsrc_len = resource_size(res);
- -
- - fotg210 = hcd_to_fotg210(hcd);
- -
- - fotg210->caps = hcd->regs;
- -
- - /* It's OK not to supply this clock */
- - fotg210->pclk = clk_get(dev, "PCLK");
- - if (!IS_ERR(fotg210->pclk)) {
- - retval = clk_prepare_enable(fotg210->pclk);
- - if (retval) {
- - dev_err(dev, "failed to enable PCLK\n");
- - goto failed_put_hcd;
- - }
- - } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) {
- - /*
- - * Percolate deferrals, for anything else,
- - * just live without the clocking.
- - */
- - retval = PTR_ERR(fotg210->pclk);
- - goto failed_dis_clk;
- - }
- -
- - retval = fotg210_setup(hcd);
- - if (retval)
- - goto failed_dis_clk;
- -
- - fotg210_init(fotg210);
- -
- - retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
- - if (retval) {
- - dev_err(dev, "failed to add hcd with err %d\n", retval);
- - goto failed_dis_clk;
- - }
- - device_wakeup_enable(hcd->self.controller);
- - platform_set_drvdata(pdev, hcd);
- -
- - return retval;
- -
- -failed_dis_clk:
- - if (!IS_ERR(fotg210->pclk)) {
- - clk_disable_unprepare(fotg210->pclk);
- - clk_put(fotg210->pclk);
- - }
- -failed_put_hcd:
- - usb_put_hcd(hcd);
- -fail_create_hcd:
- - dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval);
- - return retval;
- -}
- -
- -/*
- - * fotg210_hcd_remove - shutdown processing for EHCI HCDs
- - * @dev: USB Host Controller being removed
- - *
- - */
- -static int fotg210_hcd_remove(struct platform_device *pdev)
- -{
- - struct usb_hcd *hcd = platform_get_drvdata(pdev);
- - struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- -
- - if (!IS_ERR(fotg210->pclk)) {
- - clk_disable_unprepare(fotg210->pclk);
- - clk_put(fotg210->pclk);
- - }
- -
- - usb_remove_hcd(hcd);
- - usb_put_hcd(hcd);
- -
- - return 0;
- -}
- -
- -#ifdef CONFIG_OF
- -static const struct of_device_id fotg210_of_match[] = {
- - { .compatible = "faraday,fotg210" },
- - {},
- -};
- -MODULE_DEVICE_TABLE(of, fotg210_of_match);
- -#endif
- -
- -static struct platform_driver fotg210_hcd_driver = {
- - .driver = {
- - .name = "fotg210-hcd",
- - .of_match_table = of_match_ptr(fotg210_of_match),
- - },
- - .probe = fotg210_hcd_probe,
- - .remove = fotg210_hcd_remove,
- -};
- -
- -static int __init fotg210_hcd_init(void)
- -{
- - int retval = 0;
- -
- - if (usb_disabled())
- - return -ENODEV;
- -
- - set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
- - if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
- - test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
- - pr_warn("Warning! fotg210_hcd should always be loaded before uhci_hcd and ohci_hcd, not after\n");
- -
- - pr_debug("%s: block sizes: qh %zd qtd %zd itd %zd\n",
- - hcd_name, sizeof(struct fotg210_qh),
- - sizeof(struct fotg210_qtd),
- - sizeof(struct fotg210_itd));
- -
- - fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root);
- -
- - retval = platform_driver_register(&fotg210_hcd_driver);
- - if (retval < 0)
- - goto clean;
- - return retval;
- -
- -clean:
- - debugfs_remove(fotg210_debug_root);
- - fotg210_debug_root = NULL;
- -
- - clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
- - return retval;
- -}
- -module_init(fotg210_hcd_init);
- -
- -static void __exit fotg210_hcd_cleanup(void)
- -{
- - platform_driver_unregister(&fotg210_hcd_driver);
- - debugfs_remove(fotg210_debug_root);
- - clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
- -}
- -module_exit(fotg210_hcd_cleanup);
- --- /dev/null
- +++ b/drivers/usb/fotg210/fotg210-hcd.c
- @@ -0,0 +1,5727 @@
- +// SPDX-License-Identifier: GPL-2.0+
- +/* Faraday FOTG210 EHCI-like driver
- + *
- + * Copyright (c) 2013 Faraday Technology Corporation
- + *
- + * Author: Yuan-Hsin Chen <[email protected]>
- + * Feng-Hsin Chiang <[email protected]>
- + * Po-Yu Chuang <[email protected]>
- + *
- + * Most of code borrowed from the Linux-3.7 EHCI driver
- + */
- +#include <linux/module.h>
- +#include <linux/of.h>
- +#include <linux/device.h>
- +#include <linux/dmapool.h>
- +#include <linux/kernel.h>
- +#include <linux/delay.h>
- +#include <linux/ioport.h>
- +#include <linux/sched.h>
- +#include <linux/vmalloc.h>
- +#include <linux/errno.h>
- +#include <linux/init.h>
- +#include <linux/hrtimer.h>
- +#include <linux/list.h>
- +#include <linux/interrupt.h>
- +#include <linux/usb.h>
- +#include <linux/usb/hcd.h>
- +#include <linux/moduleparam.h>
- +#include <linux/dma-mapping.h>
- +#include <linux/debugfs.h>
- +#include <linux/slab.h>
- +#include <linux/uaccess.h>
- +#include <linux/platform_device.h>
- +#include <linux/io.h>
- +#include <linux/iopoll.h>
- +#include <linux/clk.h>
- +
- +#include <asm/byteorder.h>
- +#include <asm/irq.h>
- +#include <asm/unaligned.h>
- +
- +#define DRIVER_AUTHOR "Yuan-Hsin Chen"
- +#define DRIVER_DESC "FOTG210 Host Controller (EHCI) Driver"
- +static const char hcd_name[] = "fotg210_hcd";
- +
- +#undef FOTG210_URB_TRACE
- +#define FOTG210_STATS
- +
- +/* magic numbers that can affect system performance */
- +#define FOTG210_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
- +#define FOTG210_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
- +#define FOTG210_TUNE_RL_TT 0
- +#define FOTG210_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
- +#define FOTG210_TUNE_MULT_TT 1
- +
- +/* Some drivers think it's safe to schedule isochronous transfers more than 256
- + * ms into the future (partly as a result of an old bug in the scheduling
- + * code). In an attempt to avoid trouble, we will use a minimum scheduling
- + * length of 512 frames instead of 256.
- + */
- +#define FOTG210_TUNE_FLS 1 /* (medium) 512-frame schedule */
- +
- +/* Initial IRQ latency: faster than hw default */
- +static int log2_irq_thresh; /* 0 to 6 */
- +module_param(log2_irq_thresh, int, S_IRUGO);
- +MODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
- +
- +/* initial park setting: slower than hw default */
- +static unsigned park;
- +module_param(park, uint, S_IRUGO);
- +MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets");
- +
- +/* for link power management(LPM) feature */
- +static unsigned int hird;
- +module_param(hird, int, S_IRUGO);
- +MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
- +
- +#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
- +
- +#include "fotg210-hcd.h"
- +
- +#define fotg210_dbg(fotg210, fmt, args...) \
- + dev_dbg(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
- +#define fotg210_err(fotg210, fmt, args...) \
- + dev_err(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
- +#define fotg210_info(fotg210, fmt, args...) \
- + dev_info(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
- +#define fotg210_warn(fotg210, fmt, args...) \
- + dev_warn(fotg210_to_hcd(fotg210)->self.controller, fmt, ## args)
- +
- +/* check the values in the HCSPARAMS register (host controller _Structural_
- + * parameters) see EHCI spec, Table 2-4 for each value
- + */
- +static void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label)
- +{
- + u32 params = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
- +
- + fotg210_dbg(fotg210, "%s hcs_params 0x%x ports=%d\n", label, params,
- + HCS_N_PORTS(params));
- +}
- +
- +/* check the values in the HCCPARAMS register (host controller _Capability_
- + * parameters) see EHCI Spec, Table 2-5 for each value
- + */
- +static void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label)
- +{
- + u32 params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
- +
- + fotg210_dbg(fotg210, "%s hcc_params %04x uframes %s%s\n", label,
- + params,
- + HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
- + HCC_CANPARK(params) ? " park" : "");
- +}
- +
- +static void __maybe_unused
- +dbg_qtd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd)
- +{
- + fotg210_dbg(fotg210, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
- + hc32_to_cpup(fotg210, &qtd->hw_next),
- + hc32_to_cpup(fotg210, &qtd->hw_alt_next),
- + hc32_to_cpup(fotg210, &qtd->hw_token),
- + hc32_to_cpup(fotg210, &qtd->hw_buf[0]));
- + if (qtd->hw_buf[1])
- + fotg210_dbg(fotg210, " p1=%08x p2=%08x p3=%08x p4=%08x\n",
- + hc32_to_cpup(fotg210, &qtd->hw_buf[1]),
- + hc32_to_cpup(fotg210, &qtd->hw_buf[2]),
- + hc32_to_cpup(fotg210, &qtd->hw_buf[3]),
- + hc32_to_cpup(fotg210, &qtd->hw_buf[4]));
- +}
- +
- +static void __maybe_unused
- +dbg_qh(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- +{
- + struct fotg210_qh_hw *hw = qh->hw;
- +
- + fotg210_dbg(fotg210, "%s qh %p n%08x info %x %x qtd %x\n", label, qh,
- + hw->hw_next, hw->hw_info1, hw->hw_info2,
- + hw->hw_current);
- +
- + dbg_qtd("overlay", fotg210, (struct fotg210_qtd *) &hw->hw_qtd_next);
- +}
- +
- +static void __maybe_unused
- +dbg_itd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
- +{
- + fotg210_dbg(fotg210, "%s[%d] itd %p, next %08x, urb %p\n", label,
- + itd->frame, itd, hc32_to_cpu(fotg210, itd->hw_next),
- + itd->urb);
- +
- + fotg210_dbg(fotg210,
- + " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
- + hc32_to_cpu(fotg210, itd->hw_transaction[0]),
- + hc32_to_cpu(fotg210, itd->hw_transaction[1]),
- + hc32_to_cpu(fotg210, itd->hw_transaction[2]),
- + hc32_to_cpu(fotg210, itd->hw_transaction[3]),
- + hc32_to_cpu(fotg210, itd->hw_transaction[4]),
- + hc32_to_cpu(fotg210, itd->hw_transaction[5]),
- + hc32_to_cpu(fotg210, itd->hw_transaction[6]),
- + hc32_to_cpu(fotg210, itd->hw_transaction[7]));
- +
- + fotg210_dbg(fotg210,
- + " buf: %08x %08x %08x %08x %08x %08x %08x\n",
- + hc32_to_cpu(fotg210, itd->hw_bufp[0]),
- + hc32_to_cpu(fotg210, itd->hw_bufp[1]),
- + hc32_to_cpu(fotg210, itd->hw_bufp[2]),
- + hc32_to_cpu(fotg210, itd->hw_bufp[3]),
- + hc32_to_cpu(fotg210, itd->hw_bufp[4]),
- + hc32_to_cpu(fotg210, itd->hw_bufp[5]),
- + hc32_to_cpu(fotg210, itd->hw_bufp[6]));
- +
- + fotg210_dbg(fotg210, " index: %d %d %d %d %d %d %d %d\n",
- + itd->index[0], itd->index[1], itd->index[2],
- + itd->index[3], itd->index[4], itd->index[5],
- + itd->index[6], itd->index[7]);
- +}
- +
- +static int __maybe_unused
- +dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
- +{
- + return scnprintf(buf, len, "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
- + label, label[0] ? " " : "", status,
- + (status & STS_ASS) ? " Async" : "",
- + (status & STS_PSS) ? " Periodic" : "",
- + (status & STS_RECL) ? " Recl" : "",
- + (status & STS_HALT) ? " Halt" : "",
- + (status & STS_IAA) ? " IAA" : "",
- + (status & STS_FATAL) ? " FATAL" : "",
- + (status & STS_FLR) ? " FLR" : "",
- + (status & STS_PCD) ? " PCD" : "",
- + (status & STS_ERR) ? " ERR" : "",
- + (status & STS_INT) ? " INT" : "");
- +}
- +
- +static int __maybe_unused
- +dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
- +{
- + return scnprintf(buf, len, "%s%sintrenable %02x%s%s%s%s%s%s",
- + label, label[0] ? " " : "", enable,
- + (enable & STS_IAA) ? " IAA" : "",
- + (enable & STS_FATAL) ? " FATAL" : "",
- + (enable & STS_FLR) ? " FLR" : "",
- + (enable & STS_PCD) ? " PCD" : "",
- + (enable & STS_ERR) ? " ERR" : "",
- + (enable & STS_INT) ? " INT" : "");
- +}
- +
- +static const char *const fls_strings[] = { "1024", "512", "256", "??" };
- +
- +static int dbg_command_buf(char *buf, unsigned len, const char *label,
- + u32 command)
- +{
- + return scnprintf(buf, len,
- + "%s%scommand %07x %s=%d ithresh=%d%s%s%s period=%s%s %s",
- + label, label[0] ? " " : "", command,
- + (command & CMD_PARK) ? " park" : "(park)",
- + CMD_PARK_CNT(command),
- + (command >> 16) & 0x3f,
- + (command & CMD_IAAD) ? " IAAD" : "",
- + (command & CMD_ASE) ? " Async" : "",
- + (command & CMD_PSE) ? " Periodic" : "",
- + fls_strings[(command >> 2) & 0x3],
- + (command & CMD_RESET) ? " Reset" : "",
- + (command & CMD_RUN) ? "RUN" : "HALT");
- +}
- +
- +static char *dbg_port_buf(char *buf, unsigned len, const char *label, int port,
- + u32 status)
- +{
- + char *sig;
- +
- + /* signaling state */
- + switch (status & (3 << 10)) {
- + case 0 << 10:
- + sig = "se0";
- + break;
- + case 1 << 10:
- + sig = "k";
- + break; /* low speed */
- + case 2 << 10:
- + sig = "j";
- + break;
- + default:
- + sig = "?";
- + break;
- + }
- +
- + scnprintf(buf, len, "%s%sport:%d status %06x %d sig=%s%s%s%s%s%s%s%s",
- + label, label[0] ? " " : "", port, status,
- + status >> 25, /*device address */
- + sig,
- + (status & PORT_RESET) ? " RESET" : "",
- + (status & PORT_SUSPEND) ? " SUSPEND" : "",
- + (status & PORT_RESUME) ? " RESUME" : "",
- + (status & PORT_PEC) ? " PEC" : "",
- + (status & PORT_PE) ? " PE" : "",
- + (status & PORT_CSC) ? " CSC" : "",
- + (status & PORT_CONNECT) ? " CONNECT" : "");
- +
- + return buf;
- +}
- +
- +/* functions have the "wrong" filename when they're output... */
- +#define dbg_status(fotg210, label, status) { \
- + char _buf[80]; \
- + dbg_status_buf(_buf, sizeof(_buf), label, status); \
- + fotg210_dbg(fotg210, "%s\n", _buf); \
- +}
- +
- +#define dbg_cmd(fotg210, label, command) { \
- + char _buf[80]; \
- + dbg_command_buf(_buf, sizeof(_buf), label, command); \
- + fotg210_dbg(fotg210, "%s\n", _buf); \
- +}
- +
- +#define dbg_port(fotg210, label, port, status) { \
- + char _buf[80]; \
- + fotg210_dbg(fotg210, "%s\n", \
- + dbg_port_buf(_buf, sizeof(_buf), label, port, status));\
- +}
- +
- +/* troubleshooting help: expose state in debugfs */
- +static int debug_async_open(struct inode *, struct file *);
- +static int debug_periodic_open(struct inode *, struct file *);
- +static int debug_registers_open(struct inode *, struct file *);
- +static int debug_async_open(struct inode *, struct file *);
- +
- +static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
- +static int debug_close(struct inode *, struct file *);
- +
- +static const struct file_operations debug_async_fops = {
- + .owner = THIS_MODULE,
- + .open = debug_async_open,
- + .read = debug_output,
- + .release = debug_close,
- + .llseek = default_llseek,
- +};
- +static const struct file_operations debug_periodic_fops = {
- + .owner = THIS_MODULE,
- + .open = debug_periodic_open,
- + .read = debug_output,
- + .release = debug_close,
- + .llseek = default_llseek,
- +};
- +static const struct file_operations debug_registers_fops = {
- + .owner = THIS_MODULE,
- + .open = debug_registers_open,
- + .read = debug_output,
- + .release = debug_close,
- + .llseek = default_llseek,
- +};
- +
- +static struct dentry *fotg210_debug_root;
- +
- +struct debug_buffer {
- + ssize_t (*fill_func)(struct debug_buffer *); /* fill method */
- + struct usb_bus *bus;
- + struct mutex mutex; /* protect filling of buffer */
- + size_t count; /* number of characters filled into buffer */
- + char *output_buf;
- + size_t alloc_size;
- +};
- +
- +static inline char speed_char(u32 scratch)
- +{
- + switch (scratch & (3 << 12)) {
- + case QH_FULL_SPEED:
- + return 'f';
- +
- + case QH_LOW_SPEED:
- + return 'l';
- +
- + case QH_HIGH_SPEED:
- + return 'h';
- +
- + default:
- + return '?';
- + }
- +}
- +
- +static inline char token_mark(struct fotg210_hcd *fotg210, __hc32 token)
- +{
- + __u32 v = hc32_to_cpu(fotg210, token);
- +
- + if (v & QTD_STS_ACTIVE)
- + return '*';
- + if (v & QTD_STS_HALT)
- + return '-';
- + if (!IS_SHORT_READ(v))
- + return ' ';
- + /* tries to advance through hw_alt_next */
- + return '/';
- +}
- +
- +static void qh_lines(struct fotg210_hcd *fotg210, struct fotg210_qh *qh,
- + char **nextp, unsigned *sizep)
- +{
- + u32 scratch;
- + u32 hw_curr;
- + struct fotg210_qtd *td;
- + unsigned temp;
- + unsigned size = *sizep;
- + char *next = *nextp;
- + char mark;
- + __le32 list_end = FOTG210_LIST_END(fotg210);
- + struct fotg210_qh_hw *hw = qh->hw;
- +
- + if (hw->hw_qtd_next == list_end) /* NEC does this */
- + mark = '@';
- + else
- + mark = token_mark(fotg210, hw->hw_token);
- + if (mark == '/') { /* qh_alt_next controls qh advance? */
- + if ((hw->hw_alt_next & QTD_MASK(fotg210)) ==
- + fotg210->async->hw->hw_alt_next)
- + mark = '#'; /* blocked */
- + else if (hw->hw_alt_next == list_end)
- + mark = '.'; /* use hw_qtd_next */
- + /* else alt_next points to some other qtd */
- + }
- + scratch = hc32_to_cpup(fotg210, &hw->hw_info1);
- + hw_curr = (mark == '*') ? hc32_to_cpup(fotg210, &hw->hw_current) : 0;
- + temp = scnprintf(next, size,
- + "qh/%p dev%d %cs ep%d %08x %08x(%08x%c %s nak%d)",
- + qh, scratch & 0x007f,
- + speed_char(scratch),
- + (scratch >> 8) & 0x000f,
- + scratch, hc32_to_cpup(fotg210, &hw->hw_info2),
- + hc32_to_cpup(fotg210, &hw->hw_token), mark,
- + (cpu_to_hc32(fotg210, QTD_TOGGLE) & hw->hw_token)
- + ? "data1" : "data0",
- + (hc32_to_cpup(fotg210, &hw->hw_alt_next) >> 1) & 0x0f);
- + size -= temp;
- + next += temp;
- +
- + /* hc may be modifying the list as we read it ... */
- + list_for_each_entry(td, &qh->qtd_list, qtd_list) {
- + scratch = hc32_to_cpup(fotg210, &td->hw_token);
- + mark = ' ';
- + if (hw_curr == td->qtd_dma)
- + mark = '*';
- + else if (hw->hw_qtd_next == cpu_to_hc32(fotg210, td->qtd_dma))
- + mark = '+';
- + else if (QTD_LENGTH(scratch)) {
- + if (td->hw_alt_next == fotg210->async->hw->hw_alt_next)
- + mark = '#';
- + else if (td->hw_alt_next != list_end)
- + mark = '/';
- + }
- + temp = snprintf(next, size,
- + "\n\t%p%c%s len=%d %08x urb %p",
- + td, mark, ({ char *tmp;
- + switch ((scratch>>8)&0x03) {
- + case 0:
- + tmp = "out";
- + break;
- + case 1:
- + tmp = "in";
- + break;
- + case 2:
- + tmp = "setup";
- + break;
- + default:
- + tmp = "?";
- + break;
- + } tmp; }),
- + (scratch >> 16) & 0x7fff,
- + scratch,
- + td->urb);
- + if (size < temp)
- + temp = size;
- + size -= temp;
- + next += temp;
- + if (temp == size)
- + goto done;
- + }
- +
- + temp = snprintf(next, size, "\n");
- + if (size < temp)
- + temp = size;
- +
- + size -= temp;
- + next += temp;
- +
- +done:
- + *sizep = size;
- + *nextp = next;
- +}
- +
- +static ssize_t fill_async_buffer(struct debug_buffer *buf)
- +{
- + struct usb_hcd *hcd;
- + struct fotg210_hcd *fotg210;
- + unsigned long flags;
- + unsigned temp, size;
- + char *next;
- + struct fotg210_qh *qh;
- +
- + hcd = bus_to_hcd(buf->bus);
- + fotg210 = hcd_to_fotg210(hcd);
- + next = buf->output_buf;
- + size = buf->alloc_size;
- +
- + *next = 0;
- +
- + /* dumps a snapshot of the async schedule.
- + * usually empty except for long-term bulk reads, or head.
- + * one QH per line, and TDs we know about
- + */
- + spin_lock_irqsave(&fotg210->lock, flags);
- + for (qh = fotg210->async->qh_next.qh; size > 0 && qh;
- + qh = qh->qh_next.qh)
- + qh_lines(fotg210, qh, &next, &size);
- + if (fotg210->async_unlink && size > 0) {
- + temp = scnprintf(next, size, "\nunlink =\n");
- + size -= temp;
- + next += temp;
- +
- + for (qh = fotg210->async_unlink; size > 0 && qh;
- + qh = qh->unlink_next)
- + qh_lines(fotg210, qh, &next, &size);
- + }
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- +
- + return strlen(buf->output_buf);
- +}
- +
- +/* count tds, get ep direction */
- +static unsigned output_buf_tds_dir(char *buf, struct fotg210_hcd *fotg210,
- + struct fotg210_qh_hw *hw, struct fotg210_qh *qh, unsigned size)
- +{
- + u32 scratch = hc32_to_cpup(fotg210, &hw->hw_info1);
- + struct fotg210_qtd *qtd;
- + char *type = "";
- + unsigned temp = 0;
- +
- + /* count tds, get ep direction */
- + list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
- + temp++;
- + switch ((hc32_to_cpu(fotg210, qtd->hw_token) >> 8) & 0x03) {
- + case 0:
- + type = "out";
- + continue;
- + case 1:
- + type = "in";
- + continue;
- + }
- + }
- +
- + return scnprintf(buf, size, "(%c%d ep%d%s [%d/%d] q%d p%d)",
- + speed_char(scratch), scratch & 0x007f,
- + (scratch >> 8) & 0x000f, type, qh->usecs,
- + qh->c_usecs, temp, (scratch >> 16) & 0x7ff);
- +}
- +
- +#define DBG_SCHED_LIMIT 64
- +static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
- +{
- + struct usb_hcd *hcd;
- + struct fotg210_hcd *fotg210;
- + unsigned long flags;
- + union fotg210_shadow p, *seen;
- + unsigned temp, size, seen_count;
- + char *next;
- + unsigned i;
- + __hc32 tag;
- +
- + seen = kmalloc_array(DBG_SCHED_LIMIT, sizeof(*seen), GFP_ATOMIC);
- + if (!seen)
- + return 0;
- +
- + seen_count = 0;
- +
- + hcd = bus_to_hcd(buf->bus);
- + fotg210 = hcd_to_fotg210(hcd);
- + next = buf->output_buf;
- + size = buf->alloc_size;
- +
- + temp = scnprintf(next, size, "size = %d\n", fotg210->periodic_size);
- + size -= temp;
- + next += temp;
- +
- + /* dump a snapshot of the periodic schedule.
- + * iso changes, interrupt usually doesn't.
- + */
- + spin_lock_irqsave(&fotg210->lock, flags);
- + for (i = 0; i < fotg210->periodic_size; i++) {
- + p = fotg210->pshadow[i];
- + if (likely(!p.ptr))
- + continue;
- +
- + tag = Q_NEXT_TYPE(fotg210, fotg210->periodic[i]);
- +
- + temp = scnprintf(next, size, "%4d: ", i);
- + size -= temp;
- + next += temp;
- +
- + do {
- + struct fotg210_qh_hw *hw;
- +
- + switch (hc32_to_cpu(fotg210, tag)) {
- + case Q_TYPE_QH:
- + hw = p.qh->hw;
- + temp = scnprintf(next, size, " qh%d-%04x/%p",
- + p.qh->period,
- + hc32_to_cpup(fotg210,
- + &hw->hw_info2)
- + /* uframe masks */
- + & (QH_CMASK | QH_SMASK),
- + p.qh);
- + size -= temp;
- + next += temp;
- + /* don't repeat what follows this qh */
- + for (temp = 0; temp < seen_count; temp++) {
- + if (seen[temp].ptr != p.ptr)
- + continue;
- + if (p.qh->qh_next.ptr) {
- + temp = scnprintf(next, size,
- + " ...");
- + size -= temp;
- + next += temp;
- + }
- + break;
- + }
- + /* show more info the first time around */
- + if (temp == seen_count) {
- + temp = output_buf_tds_dir(next,
- + fotg210, hw,
- + p.qh, size);
- +
- + if (seen_count < DBG_SCHED_LIMIT)
- + seen[seen_count++].qh = p.qh;
- + } else
- + temp = 0;
- + tag = Q_NEXT_TYPE(fotg210, hw->hw_next);
- + p = p.qh->qh_next;
- + break;
- + case Q_TYPE_FSTN:
- + temp = scnprintf(next, size,
- + " fstn-%8x/%p",
- + p.fstn->hw_prev, p.fstn);
- + tag = Q_NEXT_TYPE(fotg210, p.fstn->hw_next);
- + p = p.fstn->fstn_next;
- + break;
- + case Q_TYPE_ITD:
- + temp = scnprintf(next, size,
- + " itd/%p", p.itd);
- + tag = Q_NEXT_TYPE(fotg210, p.itd->hw_next);
- + p = p.itd->itd_next;
- + break;
- + }
- + size -= temp;
- + next += temp;
- + } while (p.ptr);
- +
- + temp = scnprintf(next, size, "\n");
- + size -= temp;
- + next += temp;
- + }
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + kfree(seen);
- +
- + return buf->alloc_size - size;
- +}
- +#undef DBG_SCHED_LIMIT
- +
- +static const char *rh_state_string(struct fotg210_hcd *fotg210)
- +{
- + switch (fotg210->rh_state) {
- + case FOTG210_RH_HALTED:
- + return "halted";
- + case FOTG210_RH_SUSPENDED:
- + return "suspended";
- + case FOTG210_RH_RUNNING:
- + return "running";
- + case FOTG210_RH_STOPPING:
- + return "stopping";
- + }
- + return "?";
- +}
- +
- +static ssize_t fill_registers_buffer(struct debug_buffer *buf)
- +{
- + struct usb_hcd *hcd;
- + struct fotg210_hcd *fotg210;
- + unsigned long flags;
- + unsigned temp, size, i;
- + char *next, scratch[80];
- + static const char fmt[] = "%*s\n";
- + static const char label[] = "";
- +
- + hcd = bus_to_hcd(buf->bus);
- + fotg210 = hcd_to_fotg210(hcd);
- + next = buf->output_buf;
- + size = buf->alloc_size;
- +
- + spin_lock_irqsave(&fotg210->lock, flags);
- +
- + if (!HCD_HW_ACCESSIBLE(hcd)) {
- + size = scnprintf(next, size,
- + "bus %s, device %s\n"
- + "%s\n"
- + "SUSPENDED(no register access)\n",
- + hcd->self.controller->bus->name,
- + dev_name(hcd->self.controller),
- + hcd->product_desc);
- + goto done;
- + }
- +
- + /* Capability Registers */
- + i = HC_VERSION(fotg210, fotg210_readl(fotg210,
- + &fotg210->caps->hc_capbase));
- + temp = scnprintf(next, size,
- + "bus %s, device %s\n"
- + "%s\n"
- + "EHCI %x.%02x, rh state %s\n",
- + hcd->self.controller->bus->name,
- + dev_name(hcd->self.controller),
- + hcd->product_desc,
- + i >> 8, i & 0x0ff, rh_state_string(fotg210));
- + size -= temp;
- + next += temp;
- +
- + /* FIXME interpret both types of params */
- + i = fotg210_readl(fotg210, &fotg210->caps->hcs_params);
- + temp = scnprintf(next, size, "structural params 0x%08x\n", i);
- + size -= temp;
- + next += temp;
- +
- + i = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
- + temp = scnprintf(next, size, "capability params 0x%08x\n", i);
- + size -= temp;
- + next += temp;
- +
- + /* Operational Registers */
- + temp = dbg_status_buf(scratch, sizeof(scratch), label,
- + fotg210_readl(fotg210, &fotg210->regs->status));
- + temp = scnprintf(next, size, fmt, temp, scratch);
- + size -= temp;
- + next += temp;
- +
- + temp = dbg_command_buf(scratch, sizeof(scratch), label,
- + fotg210_readl(fotg210, &fotg210->regs->command));
- + temp = scnprintf(next, size, fmt, temp, scratch);
- + size -= temp;
- + next += temp;
- +
- + temp = dbg_intr_buf(scratch, sizeof(scratch), label,
- + fotg210_readl(fotg210, &fotg210->regs->intr_enable));
- + temp = scnprintf(next, size, fmt, temp, scratch);
- + size -= temp;
- + next += temp;
- +
- + temp = scnprintf(next, size, "uframe %04x\n",
- + fotg210_read_frame_index(fotg210));
- + size -= temp;
- + next += temp;
- +
- + if (fotg210->async_unlink) {
- + temp = scnprintf(next, size, "async unlink qh %p\n",
- + fotg210->async_unlink);
- + size -= temp;
- + next += temp;
- + }
- +
- +#ifdef FOTG210_STATS
- + temp = scnprintf(next, size,
- + "irq normal %ld err %ld iaa %ld(lost %ld)\n",
- + fotg210->stats.normal, fotg210->stats.error,
- + fotg210->stats.iaa, fotg210->stats.lost_iaa);
- + size -= temp;
- + next += temp;
- +
- + temp = scnprintf(next, size, "complete %ld unlink %ld\n",
- + fotg210->stats.complete, fotg210->stats.unlink);
- + size -= temp;
- + next += temp;
- +#endif
- +
- +done:
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- +
- + return buf->alloc_size - size;
- +}
- +
- +static struct debug_buffer
- +*alloc_buffer(struct usb_bus *bus, ssize_t (*fill_func)(struct debug_buffer *))
- +{
- + struct debug_buffer *buf;
- +
- + buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
- +
- + if (buf) {
- + buf->bus = bus;
- + buf->fill_func = fill_func;
- + mutex_init(&buf->mutex);
- + buf->alloc_size = PAGE_SIZE;
- + }
- +
- + return buf;
- +}
- +
- +static int fill_buffer(struct debug_buffer *buf)
- +{
- + int ret = 0;
- +
- + if (!buf->output_buf)
- + buf->output_buf = vmalloc(buf->alloc_size);
- +
- + if (!buf->output_buf) {
- + ret = -ENOMEM;
- + goto out;
- + }
- +
- + ret = buf->fill_func(buf);
- +
- + if (ret >= 0) {
- + buf->count = ret;
- + ret = 0;
- + }
- +
- +out:
- + return ret;
- +}
- +
- +static ssize_t debug_output(struct file *file, char __user *user_buf,
- + size_t len, loff_t *offset)
- +{
- + struct debug_buffer *buf = file->private_data;
- + int ret = 0;
- +
- + mutex_lock(&buf->mutex);
- + if (buf->count == 0) {
- + ret = fill_buffer(buf);
- + if (ret != 0) {
- + mutex_unlock(&buf->mutex);
- + goto out;
- + }
- + }
- + mutex_unlock(&buf->mutex);
- +
- + ret = simple_read_from_buffer(user_buf, len, offset,
- + buf->output_buf, buf->count);
- +
- +out:
- + return ret;
- +
- +}
- +
- +static int debug_close(struct inode *inode, struct file *file)
- +{
- + struct debug_buffer *buf = file->private_data;
- +
- + if (buf) {
- + vfree(buf->output_buf);
- + kfree(buf);
- + }
- +
- + return 0;
- +}
- +static int debug_async_open(struct inode *inode, struct file *file)
- +{
- + file->private_data = alloc_buffer(inode->i_private, fill_async_buffer);
- +
- + return file->private_data ? 0 : -ENOMEM;
- +}
- +
- +static int debug_periodic_open(struct inode *inode, struct file *file)
- +{
- + struct debug_buffer *buf;
- +
- + buf = alloc_buffer(inode->i_private, fill_periodic_buffer);
- + if (!buf)
- + return -ENOMEM;
- +
- + buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE;
- + file->private_data = buf;
- + return 0;
- +}
- +
- +static int debug_registers_open(struct inode *inode, struct file *file)
- +{
- + file->private_data = alloc_buffer(inode->i_private,
- + fill_registers_buffer);
- +
- + return file->private_data ? 0 : -ENOMEM;
- +}
- +
- +static inline void create_debug_files(struct fotg210_hcd *fotg210)
- +{
- + struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
- + struct dentry *root;
- +
- + root = debugfs_create_dir(bus->bus_name, fotg210_debug_root);
- +
- + debugfs_create_file("async", S_IRUGO, root, bus, &debug_async_fops);
- + debugfs_create_file("periodic", S_IRUGO, root, bus,
- + &debug_periodic_fops);
- + debugfs_create_file("registers", S_IRUGO, root, bus,
- + &debug_registers_fops);
- +}
- +
- +static inline void remove_debug_files(struct fotg210_hcd *fotg210)
- +{
- + struct usb_bus *bus = &fotg210_to_hcd(fotg210)->self;
- +
- + debugfs_lookup_and_remove(bus->bus_name, fotg210_debug_root);
- +}
- +
- +/* handshake - spin reading hc until handshake completes or fails
- + * @ptr: address of hc register to be read
- + * @mask: bits to look at in result of read
- + * @done: value of those bits when handshake succeeds
- + * @usec: timeout in microseconds
- + *
- + * Returns negative errno, or zero on success
- + *
- + * Success happens when the "mask" bits have the specified value (hardware
- + * handshake done). There are two failure modes: "usec" have passed (major
- + * hardware flakeout), or the register reads as all-ones (hardware removed).
- + *
- + * That last failure should_only happen in cases like physical cardbus eject
- + * before driver shutdown. But it also seems to be caused by bugs in cardbus
- + * bridge shutdown: shutting down the bridge before the devices using it.
- + */
- +static int handshake(struct fotg210_hcd *fotg210, void __iomem *ptr,
- + u32 mask, u32 done, int usec)
- +{
- + u32 result;
- + int ret;
- +
- + ret = readl_poll_timeout_atomic(ptr, result,
- + ((result & mask) == done ||
- + result == U32_MAX), 1, usec);
- + if (result == U32_MAX) /* card removed */
- + return -ENODEV;
- +
- + return ret;
- +}
- +
- +/* Force HC to halt state from unknown (EHCI spec section 2.3).
- + * Must be called with interrupts enabled and the lock not held.
- + */
- +static int fotg210_halt(struct fotg210_hcd *fotg210)
- +{
- + u32 temp;
- +
- + spin_lock_irq(&fotg210->lock);
- +
- + /* disable any irqs left enabled by previous code */
- + fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
- +
- + /*
- + * This routine gets called during probe before fotg210->command
- + * has been initialized, so we can't rely on its value.
- + */
- + fotg210->command &= ~CMD_RUN;
- + temp = fotg210_readl(fotg210, &fotg210->regs->command);
- + temp &= ~(CMD_RUN | CMD_IAAD);
- + fotg210_writel(fotg210, temp, &fotg210->regs->command);
- +
- + spin_unlock_irq(&fotg210->lock);
- + synchronize_irq(fotg210_to_hcd(fotg210)->irq);
- +
- + return handshake(fotg210, &fotg210->regs->status,
- + STS_HALT, STS_HALT, 16 * 125);
- +}
- +
- +/* Reset a non-running (STS_HALT == 1) controller.
- + * Must be called with interrupts enabled and the lock not held.
- + */
- +static int fotg210_reset(struct fotg210_hcd *fotg210)
- +{
- + int retval;
- + u32 command = fotg210_readl(fotg210, &fotg210->regs->command);
- +
- + /* If the EHCI debug controller is active, special care must be
- + * taken before and after a host controller reset
- + */
- + if (fotg210->debug && !dbgp_reset_prep(fotg210_to_hcd(fotg210)))
- + fotg210->debug = NULL;
- +
- + command |= CMD_RESET;
- + dbg_cmd(fotg210, "reset", command);
- + fotg210_writel(fotg210, command, &fotg210->regs->command);
- + fotg210->rh_state = FOTG210_RH_HALTED;
- + fotg210->next_statechange = jiffies;
- + retval = handshake(fotg210, &fotg210->regs->command,
- + CMD_RESET, 0, 250 * 1000);
- +
- + if (retval)
- + return retval;
- +
- + if (fotg210->debug)
- + dbgp_external_startup(fotg210_to_hcd(fotg210));
- +
- + fotg210->port_c_suspend = fotg210->suspended_ports =
- + fotg210->resuming_ports = 0;
- + return retval;
- +}
- +
- +/* Idle the controller (turn off the schedules).
- + * Must be called with interrupts enabled and the lock not held.
- + */
- +static void fotg210_quiesce(struct fotg210_hcd *fotg210)
- +{
- + u32 temp;
- +
- + if (fotg210->rh_state != FOTG210_RH_RUNNING)
- + return;
- +
- + /* wait for any schedule enables/disables to take effect */
- + temp = (fotg210->command << 10) & (STS_ASS | STS_PSS);
- + handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, temp,
- + 16 * 125);
- +
- + /* then disable anything that's still active */
- + spin_lock_irq(&fotg210->lock);
- + fotg210->command &= ~(CMD_ASE | CMD_PSE);
- + fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
- + spin_unlock_irq(&fotg210->lock);
- +
- + /* hardware can take 16 microframes to turn off ... */
- + handshake(fotg210, &fotg210->regs->status, STS_ASS | STS_PSS, 0,
- + 16 * 125);
- +}
- +
- +static void end_unlink_async(struct fotg210_hcd *fotg210);
- +static void unlink_empty_async(struct fotg210_hcd *fotg210);
- +static void fotg210_work(struct fotg210_hcd *fotg210);
- +static void start_unlink_intr(struct fotg210_hcd *fotg210,
- + struct fotg210_qh *qh);
- +static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
- +
- +/* Set a bit in the USBCMD register */
- +static void fotg210_set_command_bit(struct fotg210_hcd *fotg210, u32 bit)
- +{
- + fotg210->command |= bit;
- + fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
- +
- + /* unblock posted write */
- + fotg210_readl(fotg210, &fotg210->regs->command);
- +}
- +
- +/* Clear a bit in the USBCMD register */
- +static void fotg210_clear_command_bit(struct fotg210_hcd *fotg210, u32 bit)
- +{
- + fotg210->command &= ~bit;
- + fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
- +
- + /* unblock posted write */
- + fotg210_readl(fotg210, &fotg210->regs->command);
- +}
- +
- +/* EHCI timer support... Now using hrtimers.
- + *
- + * Lots of different events are triggered from fotg210->hrtimer. Whenever
- + * the timer routine runs, it checks each possible event; events that are
- + * currently enabled and whose expiration time has passed get handled.
- + * The set of enabled events is stored as a collection of bitflags in
- + * fotg210->enabled_hrtimer_events, and they are numbered in order of
- + * increasing delay values (ranging between 1 ms and 100 ms).
- + *
- + * Rather than implementing a sorted list or tree of all pending events,
- + * we keep track only of the lowest-numbered pending event, in
- + * fotg210->next_hrtimer_event. Whenever fotg210->hrtimer gets restarted, its
- + * expiration time is set to the timeout value for this event.
- + *
- + * As a result, events might not get handled right away; the actual delay
- + * could be anywhere up to twice the requested delay. This doesn't
- + * matter, because none of the events are especially time-critical. The
- + * ones that matter most all have a delay of 1 ms, so they will be
- + * handled after 2 ms at most, which is okay. In addition to this, we
- + * allow for an expiration range of 1 ms.
- + */
- +
- +/* Delay lengths for the hrtimer event types.
- + * Keep this list sorted by delay length, in the same order as
- + * the event types indexed by enum fotg210_hrtimer_event in fotg210.h.
- + */
- +static unsigned event_delays_ns[] = {
- + 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_ASS */
- + 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_PSS */
- + 1 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_POLL_DEAD */
- + 1125 * NSEC_PER_USEC, /* FOTG210_HRTIMER_UNLINK_INTR */
- + 2 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_FREE_ITDS */
- + 6 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_ASYNC_UNLINKS */
- + 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IAA_WATCHDOG */
- + 10 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_PERIODIC */
- + 15 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_DISABLE_ASYNC */
- + 100 * NSEC_PER_MSEC, /* FOTG210_HRTIMER_IO_WATCHDOG */
- +};
- +
- +/* Enable a pending hrtimer event */
- +static void fotg210_enable_event(struct fotg210_hcd *fotg210, unsigned event,
- + bool resched)
- +{
- + ktime_t *timeout = &fotg210->hr_timeouts[event];
- +
- + if (resched)
- + *timeout = ktime_add(ktime_get(), event_delays_ns[event]);
- + fotg210->enabled_hrtimer_events |= (1 << event);
- +
- + /* Track only the lowest-numbered pending event */
- + if (event < fotg210->next_hrtimer_event) {
- + fotg210->next_hrtimer_event = event;
- + hrtimer_start_range_ns(&fotg210->hrtimer, *timeout,
- + NSEC_PER_MSEC, HRTIMER_MODE_ABS);
- + }
- +}
- +
- +
- +/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */
- +static void fotg210_poll_ASS(struct fotg210_hcd *fotg210)
- +{
- + unsigned actual, want;
- +
- + /* Don't enable anything if the controller isn't running (e.g., died) */
- + if (fotg210->rh_state != FOTG210_RH_RUNNING)
- + return;
- +
- + want = (fotg210->command & CMD_ASE) ? STS_ASS : 0;
- + actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_ASS;
- +
- + if (want != actual) {
- +
- + /* Poll again later, but give up after about 20 ms */
- + if (fotg210->ASS_poll_count++ < 20) {
- + fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_ASS,
- + true);
- + return;
- + }
- + fotg210_dbg(fotg210, "Waited too long for the async schedule status (%x/%x), giving up\n",
- + want, actual);
- + }
- + fotg210->ASS_poll_count = 0;
- +
- + /* The status is up-to-date; restart or stop the schedule as needed */
- + if (want == 0) { /* Stopped */
- + if (fotg210->async_count > 0)
- + fotg210_set_command_bit(fotg210, CMD_ASE);
- +
- + } else { /* Running */
- + if (fotg210->async_count == 0) {
- +
- + /* Turn off the schedule after a while */
- + fotg210_enable_event(fotg210,
- + FOTG210_HRTIMER_DISABLE_ASYNC,
- + true);
- + }
- + }
- +}
- +
- +/* Turn off the async schedule after a brief delay */
- +static void fotg210_disable_ASE(struct fotg210_hcd *fotg210)
- +{
- + fotg210_clear_command_bit(fotg210, CMD_ASE);
- +}
- +
- +
- +/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
- +static void fotg210_poll_PSS(struct fotg210_hcd *fotg210)
- +{
- + unsigned actual, want;
- +
- + /* Don't do anything if the controller isn't running (e.g., died) */
- + if (fotg210->rh_state != FOTG210_RH_RUNNING)
- + return;
- +
- + want = (fotg210->command & CMD_PSE) ? STS_PSS : 0;
- + actual = fotg210_readl(fotg210, &fotg210->regs->status) & STS_PSS;
- +
- + if (want != actual) {
- +
- + /* Poll again later, but give up after about 20 ms */
- + if (fotg210->PSS_poll_count++ < 20) {
- + fotg210_enable_event(fotg210, FOTG210_HRTIMER_POLL_PSS,
- + true);
- + return;
- + }
- + fotg210_dbg(fotg210, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
- + want, actual);
- + }
- + fotg210->PSS_poll_count = 0;
- +
- + /* The status is up-to-date; restart or stop the schedule as needed */
- + if (want == 0) { /* Stopped */
- + if (fotg210->periodic_count > 0)
- + fotg210_set_command_bit(fotg210, CMD_PSE);
- +
- + } else { /* Running */
- + if (fotg210->periodic_count == 0) {
- +
- + /* Turn off the schedule after a while */
- + fotg210_enable_event(fotg210,
- + FOTG210_HRTIMER_DISABLE_PERIODIC,
- + true);
- + }
- + }
- +}
- +
- +/* Turn off the periodic schedule after a brief delay */
- +static void fotg210_disable_PSE(struct fotg210_hcd *fotg210)
- +{
- + fotg210_clear_command_bit(fotg210, CMD_PSE);
- +}
- +
- +
- +/* Poll the STS_HALT status bit; see when a dead controller stops */
- +static void fotg210_handle_controller_death(struct fotg210_hcd *fotg210)
- +{
- + if (!(fotg210_readl(fotg210, &fotg210->regs->status) & STS_HALT)) {
- +
- + /* Give up after a few milliseconds */
- + if (fotg210->died_poll_count++ < 5) {
- + /* Try again later */
- + fotg210_enable_event(fotg210,
- + FOTG210_HRTIMER_POLL_DEAD, true);
- + return;
- + }
- + fotg210_warn(fotg210, "Waited too long for the controller to stop, giving up\n");
- + }
- +
- + /* Clean up the mess */
- + fotg210->rh_state = FOTG210_RH_HALTED;
- + fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
- + fotg210_work(fotg210);
- + end_unlink_async(fotg210);
- +
- + /* Not in process context, so don't try to reset the controller */
- +}
- +
- +
- +/* Handle unlinked interrupt QHs once they are gone from the hardware */
- +static void fotg210_handle_intr_unlinks(struct fotg210_hcd *fotg210)
- +{
- + bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING);
- +
- + /*
- + * Process all the QHs on the intr_unlink list that were added
- + * before the current unlink cycle began. The list is in
- + * temporal order, so stop when we reach the first entry in the
- + * current cycle. But if the root hub isn't running then
- + * process all the QHs on the list.
- + */
- + fotg210->intr_unlinking = true;
- + while (fotg210->intr_unlink) {
- + struct fotg210_qh *qh = fotg210->intr_unlink;
- +
- + if (!stopped && qh->unlink_cycle == fotg210->intr_unlink_cycle)
- + break;
- + fotg210->intr_unlink = qh->unlink_next;
- + qh->unlink_next = NULL;
- + end_unlink_intr(fotg210, qh);
- + }
- +
- + /* Handle remaining entries later */
- + if (fotg210->intr_unlink) {
- + fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
- + true);
- + ++fotg210->intr_unlink_cycle;
- + }
- + fotg210->intr_unlinking = false;
- +}
- +
- +
- +/* Start another free-iTDs/siTDs cycle */
- +static void start_free_itds(struct fotg210_hcd *fotg210)
- +{
- + if (!(fotg210->enabled_hrtimer_events &
- + BIT(FOTG210_HRTIMER_FREE_ITDS))) {
- + fotg210->last_itd_to_free = list_entry(
- + fotg210->cached_itd_list.prev,
- + struct fotg210_itd, itd_list);
- + fotg210_enable_event(fotg210, FOTG210_HRTIMER_FREE_ITDS, true);
- + }
- +}
- +
- +/* Wait for controller to stop using old iTDs and siTDs */
- +static void end_free_itds(struct fotg210_hcd *fotg210)
- +{
- + struct fotg210_itd *itd, *n;
- +
- + if (fotg210->rh_state < FOTG210_RH_RUNNING)
- + fotg210->last_itd_to_free = NULL;
- +
- + list_for_each_entry_safe(itd, n, &fotg210->cached_itd_list, itd_list) {
- + list_del(&itd->itd_list);
- + dma_pool_free(fotg210->itd_pool, itd, itd->itd_dma);
- + if (itd == fotg210->last_itd_to_free)
- + break;
- + }
- +
- + if (!list_empty(&fotg210->cached_itd_list))
- + start_free_itds(fotg210);
- +}
- +
- +
- +/* Handle lost (or very late) IAA interrupts */
- +static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210)
- +{
- + if (fotg210->rh_state != FOTG210_RH_RUNNING)
- + return;
- +
- + /*
- + * Lost IAA irqs wedge things badly; seen first with a vt8235.
- + * So we need this watchdog, but must protect it against both
- + * (a) SMP races against real IAA firing and retriggering, and
- + * (b) clean HC shutdown, when IAA watchdog was pending.
- + */
- + if (fotg210->async_iaa) {
- + u32 cmd, status;
- +
- + /* If we get here, IAA is *REALLY* late. It's barely
- + * conceivable that the system is so busy that CMD_IAAD
- + * is still legitimately set, so let's be sure it's
- + * clear before we read STS_IAA. (The HC should clear
- + * CMD_IAAD when it sets STS_IAA.)
- + */
- + cmd = fotg210_readl(fotg210, &fotg210->regs->command);
- +
- + /*
- + * If IAA is set here it either legitimately triggered
- + * after the watchdog timer expired (_way_ late, so we'll
- + * still count it as lost) ... or a silicon erratum:
- + * - VIA seems to set IAA without triggering the IRQ;
- + * - IAAD potentially cleared without setting IAA.
- + */
- + status = fotg210_readl(fotg210, &fotg210->regs->status);
- + if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
- + INCR(fotg210->stats.lost_iaa);
- + fotg210_writel(fotg210, STS_IAA,
- + &fotg210->regs->status);
- + }
- +
- + fotg210_dbg(fotg210, "IAA watchdog: status %x cmd %x\n",
- + status, cmd);
- + end_unlink_async(fotg210);
- + }
- +}
- +
- +
- +/* Enable the I/O watchdog, if appropriate */
- +static void turn_on_io_watchdog(struct fotg210_hcd *fotg210)
- +{
- + /* Not needed if the controller isn't running or it's already enabled */
- + if (fotg210->rh_state != FOTG210_RH_RUNNING ||
- + (fotg210->enabled_hrtimer_events &
- + BIT(FOTG210_HRTIMER_IO_WATCHDOG)))
- + return;
- +
- + /*
- + * Isochronous transfers always need the watchdog.
- + * For other sorts we use it only if the flag is set.
- + */
- + if (fotg210->isoc_count > 0 || (fotg210->need_io_watchdog &&
- + fotg210->async_count + fotg210->intr_count > 0))
- + fotg210_enable_event(fotg210, FOTG210_HRTIMER_IO_WATCHDOG,
- + true);
- +}
- +
- +
- +/* Handler functions for the hrtimer event types.
- + * Keep this array in the same order as the event types indexed by
- + * enum fotg210_hrtimer_event in fotg210.h.
- + */
- +static void (*event_handlers[])(struct fotg210_hcd *) = {
- + fotg210_poll_ASS, /* FOTG210_HRTIMER_POLL_ASS */
- + fotg210_poll_PSS, /* FOTG210_HRTIMER_POLL_PSS */
- + fotg210_handle_controller_death, /* FOTG210_HRTIMER_POLL_DEAD */
- + fotg210_handle_intr_unlinks, /* FOTG210_HRTIMER_UNLINK_INTR */
- + end_free_itds, /* FOTG210_HRTIMER_FREE_ITDS */
- + unlink_empty_async, /* FOTG210_HRTIMER_ASYNC_UNLINKS */
- + fotg210_iaa_watchdog, /* FOTG210_HRTIMER_IAA_WATCHDOG */
- + fotg210_disable_PSE, /* FOTG210_HRTIMER_DISABLE_PERIODIC */
- + fotg210_disable_ASE, /* FOTG210_HRTIMER_DISABLE_ASYNC */
- + fotg210_work, /* FOTG210_HRTIMER_IO_WATCHDOG */
- +};
- +
- +static enum hrtimer_restart fotg210_hrtimer_func(struct hrtimer *t)
- +{
- + struct fotg210_hcd *fotg210 =
- + container_of(t, struct fotg210_hcd, hrtimer);
- + ktime_t now;
- + unsigned long events;
- + unsigned long flags;
- + unsigned e;
- +
- + spin_lock_irqsave(&fotg210->lock, flags);
- +
- + events = fotg210->enabled_hrtimer_events;
- + fotg210->enabled_hrtimer_events = 0;
- + fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
- +
- + /*
- + * Check each pending event. If its time has expired, handle
- + * the event; otherwise re-enable it.
- + */
- + now = ktime_get();
- + for_each_set_bit(e, &events, FOTG210_HRTIMER_NUM_EVENTS) {
- + if (ktime_compare(now, fotg210->hr_timeouts[e]) >= 0)
- + event_handlers[e](fotg210);
- + else
- + fotg210_enable_event(fotg210, e, false);
- + }
- +
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + return HRTIMER_NORESTART;
- +}
- +
- +#define fotg210_bus_suspend NULL
- +#define fotg210_bus_resume NULL
- +
- +static int check_reset_complete(struct fotg210_hcd *fotg210, int index,
- + u32 __iomem *status_reg, int port_status)
- +{
- + if (!(port_status & PORT_CONNECT))
- + return port_status;
- +
- + /* if reset finished and it's still not enabled -- handoff */
- + if (!(port_status & PORT_PE))
- + /* with integrated TT, there's nobody to hand it to! */
- + fotg210_dbg(fotg210, "Failed to enable port %d on root hub TT\n",
- + index + 1);
- + else
- + fotg210_dbg(fotg210, "port %d reset complete, port enabled\n",
- + index + 1);
- +
- + return port_status;
- +}
- +
- +
- +/* build "status change" packet (one or two bytes) from HC registers */
- +
- +static int fotg210_hub_status_data(struct usb_hcd *hcd, char *buf)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- + u32 temp, status;
- + u32 mask;
- + int retval = 1;
- + unsigned long flags;
- +
- + /* init status to no-changes */
- + buf[0] = 0;
- +
- + /* Inform the core about resumes-in-progress by returning
- + * a non-zero value even if there are no status changes.
- + */
- + status = fotg210->resuming_ports;
- +
- + mask = PORT_CSC | PORT_PEC;
- + /* PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND */
- +
- + /* no hub change reports (bit 0) for now (power, ...) */
- +
- + /* port N changes (bit N)? */
- + spin_lock_irqsave(&fotg210->lock, flags);
- +
- + temp = fotg210_readl(fotg210, &fotg210->regs->port_status);
- +
- + /*
- + * Return status information even for ports with OWNER set.
- + * Otherwise hub_wq wouldn't see the disconnect event when a
- + * high-speed device is switched over to the companion
- + * controller by the user.
- + */
- +
- + if ((temp & mask) != 0 || test_bit(0, &fotg210->port_c_suspend) ||
- + (fotg210->reset_done[0] &&
- + time_after_eq(jiffies, fotg210->reset_done[0]))) {
- + buf[0] |= 1 << 1;
- + status = STS_PCD;
- + }
- + /* FIXME autosuspend idle root hubs */
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + return status ? retval : 0;
- +}
- +
- +static void fotg210_hub_descriptor(struct fotg210_hcd *fotg210,
- + struct usb_hub_descriptor *desc)
- +{
- + int ports = HCS_N_PORTS(fotg210->hcs_params);
- + u16 temp;
- +
- + desc->bDescriptorType = USB_DT_HUB;
- + desc->bPwrOn2PwrGood = 10; /* fotg210 1.0, 2.3.9 says 20ms max */
- + desc->bHubContrCurrent = 0;
- +
- + desc->bNbrPorts = ports;
- + temp = 1 + (ports / 8);
- + desc->bDescLength = 7 + 2 * temp;
- +
- + /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
- + memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
- + memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
- +
- + temp = HUB_CHAR_INDV_PORT_OCPM; /* per-port overcurrent reporting */
- + temp |= HUB_CHAR_NO_LPSM; /* no power switching */
- + desc->wHubCharacteristics = cpu_to_le16(temp);
- +}
- +
- +static int fotg210_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
- + u16 wIndex, char *buf, u16 wLength)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- + int ports = HCS_N_PORTS(fotg210->hcs_params);
- + u32 __iomem *status_reg = &fotg210->regs->port_status;
- + u32 temp, temp1, status;
- + unsigned long flags;
- + int retval = 0;
- + unsigned selector;
- +
- + /*
- + * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
- + * HCS_INDICATOR may say we can change LEDs to off/amber/green.
- + * (track current state ourselves) ... blink for diagnostics,
- + * power, "this is the one", etc. EHCI spec supports this.
- + */
- +
- + spin_lock_irqsave(&fotg210->lock, flags);
- + switch (typeReq) {
- + case ClearHubFeature:
- + switch (wValue) {
- + case C_HUB_LOCAL_POWER:
- + case C_HUB_OVER_CURRENT:
- + /* no hub-wide feature/status flags */
- + break;
- + default:
- + goto error;
- + }
- + break;
- + case ClearPortFeature:
- + if (!wIndex || wIndex > ports)
- + goto error;
- + wIndex--;
- + temp = fotg210_readl(fotg210, status_reg);
- + temp &= ~PORT_RWC_BITS;
- +
- + /*
- + * Even if OWNER is set, so the port is owned by the
- + * companion controller, hub_wq needs to be able to clear
- + * the port-change status bits (especially
- + * USB_PORT_STAT_C_CONNECTION).
- + */
- +
- + switch (wValue) {
- + case USB_PORT_FEAT_ENABLE:
- + fotg210_writel(fotg210, temp & ~PORT_PE, status_reg);
- + break;
- + case USB_PORT_FEAT_C_ENABLE:
- + fotg210_writel(fotg210, temp | PORT_PEC, status_reg);
- + break;
- + case USB_PORT_FEAT_SUSPEND:
- + if (temp & PORT_RESET)
- + goto error;
- + if (!(temp & PORT_SUSPEND))
- + break;
- + if ((temp & PORT_PE) == 0)
- + goto error;
- +
- + /* resume signaling for 20 msec */
- + fotg210_writel(fotg210, temp | PORT_RESUME, status_reg);
- + fotg210->reset_done[wIndex] = jiffies
- + + msecs_to_jiffies(USB_RESUME_TIMEOUT);
- + break;
- + case USB_PORT_FEAT_C_SUSPEND:
- + clear_bit(wIndex, &fotg210->port_c_suspend);
- + break;
- + case USB_PORT_FEAT_C_CONNECTION:
- + fotg210_writel(fotg210, temp | PORT_CSC, status_reg);
- + break;
- + case USB_PORT_FEAT_C_OVER_CURRENT:
- + fotg210_writel(fotg210, temp | OTGISR_OVC,
- + &fotg210->regs->otgisr);
- + break;
- + case USB_PORT_FEAT_C_RESET:
- + /* GetPortStatus clears reset */
- + break;
- + default:
- + goto error;
- + }
- + fotg210_readl(fotg210, &fotg210->regs->command);
- + break;
- + case GetHubDescriptor:
- + fotg210_hub_descriptor(fotg210, (struct usb_hub_descriptor *)
- + buf);
- + break;
- + case GetHubStatus:
- + /* no hub-wide feature/status flags */
- + memset(buf, 0, 4);
- + /*cpu_to_le32s ((u32 *) buf); */
- + break;
- + case GetPortStatus:
- + if (!wIndex || wIndex > ports)
- + goto error;
- + wIndex--;
- + status = 0;
- + temp = fotg210_readl(fotg210, status_reg);
- +
- + /* wPortChange bits */
- + if (temp & PORT_CSC)
- + status |= USB_PORT_STAT_C_CONNECTION << 16;
- + if (temp & PORT_PEC)
- + status |= USB_PORT_STAT_C_ENABLE << 16;
- +
- + temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
- + if (temp1 & OTGISR_OVC)
- + status |= USB_PORT_STAT_C_OVERCURRENT << 16;
- +
- + /* whoever resumes must GetPortStatus to complete it!! */
- + if (temp & PORT_RESUME) {
- +
- + /* Remote Wakeup received? */
- + if (!fotg210->reset_done[wIndex]) {
- + /* resume signaling for 20 msec */
- + fotg210->reset_done[wIndex] = jiffies
- + + msecs_to_jiffies(20);
- + /* check the port again */
- + mod_timer(&fotg210_to_hcd(fotg210)->rh_timer,
- + fotg210->reset_done[wIndex]);
- + }
- +
- + /* resume completed? */
- + else if (time_after_eq(jiffies,
- + fotg210->reset_done[wIndex])) {
- + clear_bit(wIndex, &fotg210->suspended_ports);
- + set_bit(wIndex, &fotg210->port_c_suspend);
- + fotg210->reset_done[wIndex] = 0;
- +
- + /* stop resume signaling */
- + temp = fotg210_readl(fotg210, status_reg);
- + fotg210_writel(fotg210, temp &
- + ~(PORT_RWC_BITS | PORT_RESUME),
- + status_reg);
- + clear_bit(wIndex, &fotg210->resuming_ports);
- + retval = handshake(fotg210, status_reg,
- + PORT_RESUME, 0, 2000);/* 2ms */
- + if (retval != 0) {
- + fotg210_err(fotg210,
- + "port %d resume error %d\n",
- + wIndex + 1, retval);
- + goto error;
- + }
- + temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
- + }
- + }
- +
- + /* whoever resets must GetPortStatus to complete it!! */
- + if ((temp & PORT_RESET) && time_after_eq(jiffies,
- + fotg210->reset_done[wIndex])) {
- + status |= USB_PORT_STAT_C_RESET << 16;
- + fotg210->reset_done[wIndex] = 0;
- + clear_bit(wIndex, &fotg210->resuming_ports);
- +
- + /* force reset to complete */
- + fotg210_writel(fotg210,
- + temp & ~(PORT_RWC_BITS | PORT_RESET),
- + status_reg);
- + /* REVISIT: some hardware needs 550+ usec to clear
- + * this bit; seems too long to spin routinely...
- + */
- + retval = handshake(fotg210, status_reg,
- + PORT_RESET, 0, 1000);
- + if (retval != 0) {
- + fotg210_err(fotg210, "port %d reset error %d\n",
- + wIndex + 1, retval);
- + goto error;
- + }
- +
- + /* see what we found out */
- + temp = check_reset_complete(fotg210, wIndex, status_reg,
- + fotg210_readl(fotg210, status_reg));
- +
- + /* restart schedule */
- + fotg210->command |= CMD_RUN;
- + fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
- + }
- +
- + if (!(temp & (PORT_RESUME|PORT_RESET))) {
- + fotg210->reset_done[wIndex] = 0;
- + clear_bit(wIndex, &fotg210->resuming_ports);
- + }
- +
- + /* transfer dedicated ports to the companion hc */
- + if ((temp & PORT_CONNECT) &&
- + test_bit(wIndex, &fotg210->companion_ports)) {
- + temp &= ~PORT_RWC_BITS;
- + fotg210_writel(fotg210, temp, status_reg);
- + fotg210_dbg(fotg210, "port %d --> companion\n",
- + wIndex + 1);
- + temp = fotg210_readl(fotg210, status_reg);
- + }
- +
- + /*
- + * Even if OWNER is set, there's no harm letting hub_wq
- + * see the wPortStatus values (they should all be 0 except
- + * for PORT_POWER anyway).
- + */
- +
- + if (temp & PORT_CONNECT) {
- + status |= USB_PORT_STAT_CONNECTION;
- + status |= fotg210_port_speed(fotg210, temp);
- + }
- + if (temp & PORT_PE)
- + status |= USB_PORT_STAT_ENABLE;
- +
- + /* maybe the port was unsuspended without our knowledge */
- + if (temp & (PORT_SUSPEND|PORT_RESUME)) {
- + status |= USB_PORT_STAT_SUSPEND;
- + } else if (test_bit(wIndex, &fotg210->suspended_ports)) {
- + clear_bit(wIndex, &fotg210->suspended_ports);
- + clear_bit(wIndex, &fotg210->resuming_ports);
- + fotg210->reset_done[wIndex] = 0;
- + if (temp & PORT_PE)
- + set_bit(wIndex, &fotg210->port_c_suspend);
- + }
- +
- + temp1 = fotg210_readl(fotg210, &fotg210->regs->otgisr);
- + if (temp1 & OTGISR_OVC)
- + status |= USB_PORT_STAT_OVERCURRENT;
- + if (temp & PORT_RESET)
- + status |= USB_PORT_STAT_RESET;
- + if (test_bit(wIndex, &fotg210->port_c_suspend))
- + status |= USB_PORT_STAT_C_SUSPEND << 16;
- +
- + if (status & ~0xffff) /* only if wPortChange is interesting */
- + dbg_port(fotg210, "GetStatus", wIndex + 1, temp);
- + put_unaligned_le32(status, buf);
- + break;
- + case SetHubFeature:
- + switch (wValue) {
- + case C_HUB_LOCAL_POWER:
- + case C_HUB_OVER_CURRENT:
- + /* no hub-wide feature/status flags */
- + break;
- + default:
- + goto error;
- + }
- + break;
- + case SetPortFeature:
- + selector = wIndex >> 8;
- + wIndex &= 0xff;
- +
- + if (!wIndex || wIndex > ports)
- + goto error;
- + wIndex--;
- + temp = fotg210_readl(fotg210, status_reg);
- + temp &= ~PORT_RWC_BITS;
- + switch (wValue) {
- + case USB_PORT_FEAT_SUSPEND:
- + if ((temp & PORT_PE) == 0
- + || (temp & PORT_RESET) != 0)
- + goto error;
- +
- + /* After above check the port must be connected.
- + * Set appropriate bit thus could put phy into low power
- + * mode if we have hostpc feature
- + */
- + fotg210_writel(fotg210, temp | PORT_SUSPEND,
- + status_reg);
- + set_bit(wIndex, &fotg210->suspended_ports);
- + break;
- + case USB_PORT_FEAT_RESET:
- + if (temp & PORT_RESUME)
- + goto error;
- + /* line status bits may report this as low speed,
- + * which can be fine if this root hub has a
- + * transaction translator built in.
- + */
- + fotg210_dbg(fotg210, "port %d reset\n", wIndex + 1);
- + temp |= PORT_RESET;
- + temp &= ~PORT_PE;
- +
- + /*
- + * caller must wait, then call GetPortStatus
- + * usb 2.0 spec says 50 ms resets on root
- + */
- + fotg210->reset_done[wIndex] = jiffies
- + + msecs_to_jiffies(50);
- + fotg210_writel(fotg210, temp, status_reg);
- + break;
- +
- + /* For downstream facing ports (these): one hub port is put
- + * into test mode according to USB2 11.24.2.13, then the hub
- + * must be reset (which for root hub now means rmmod+modprobe,
- + * or else system reboot). See EHCI 2.3.9 and 4.14 for info
- + * about the EHCI-specific stuff.
- + */
- + case USB_PORT_FEAT_TEST:
- + if (!selector || selector > 5)
- + goto error;
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + fotg210_quiesce(fotg210);
- + spin_lock_irqsave(&fotg210->lock, flags);
- +
- + /* Put all enabled ports into suspend */
- + temp = fotg210_readl(fotg210, status_reg) &
- + ~PORT_RWC_BITS;
- + if (temp & PORT_PE)
- + fotg210_writel(fotg210, temp | PORT_SUSPEND,
- + status_reg);
- +
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + fotg210_halt(fotg210);
- + spin_lock_irqsave(&fotg210->lock, flags);
- +
- + temp = fotg210_readl(fotg210, status_reg);
- + temp |= selector << 16;
- + fotg210_writel(fotg210, temp, status_reg);
- + break;
- +
- + default:
- + goto error;
- + }
- + fotg210_readl(fotg210, &fotg210->regs->command);
- + break;
- +
- + default:
- +error:
- + /* "stall" on error */
- + retval = -EPIPE;
- + }
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + return retval;
- +}
- +
- +static void __maybe_unused fotg210_relinquish_port(struct usb_hcd *hcd,
- + int portnum)
- +{
- + return;
- +}
- +
- +static int __maybe_unused fotg210_port_handed_over(struct usb_hcd *hcd,
- + int portnum)
- +{
- + return 0;
- +}
- +
- +/* There's basically three types of memory:
- + * - data used only by the HCD ... kmalloc is fine
- + * - async and periodic schedules, shared by HC and HCD ... these
- + * need to use dma_pool or dma_alloc_coherent
- + * - driver buffers, read/written by HC ... single shot DMA mapped
- + *
- + * There's also "register" data (e.g. PCI or SOC), which is memory mapped.
- + * No memory seen by this driver is pageable.
- + */
- +
- +/* Allocate the key transfer structures from the previously allocated pool */
- +static inline void fotg210_qtd_init(struct fotg210_hcd *fotg210,
- + struct fotg210_qtd *qtd, dma_addr_t dma)
- +{
- + memset(qtd, 0, sizeof(*qtd));
- + qtd->qtd_dma = dma;
- + qtd->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
- + qtd->hw_next = FOTG210_LIST_END(fotg210);
- + qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
- + INIT_LIST_HEAD(&qtd->qtd_list);
- +}
- +
- +static struct fotg210_qtd *fotg210_qtd_alloc(struct fotg210_hcd *fotg210,
- + gfp_t flags)
- +{
- + struct fotg210_qtd *qtd;
- + dma_addr_t dma;
- +
- + qtd = dma_pool_alloc(fotg210->qtd_pool, flags, &dma);
- + if (qtd != NULL)
- + fotg210_qtd_init(fotg210, qtd, dma);
- +
- + return qtd;
- +}
- +
- +static inline void fotg210_qtd_free(struct fotg210_hcd *fotg210,
- + struct fotg210_qtd *qtd)
- +{
- + dma_pool_free(fotg210->qtd_pool, qtd, qtd->qtd_dma);
- +}
- +
- +
- +static void qh_destroy(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- +{
- + /* clean qtds first, and know this is not linked */
- + if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) {
- + fotg210_dbg(fotg210, "unused qh not empty!\n");
- + BUG();
- + }
- + if (qh->dummy)
- + fotg210_qtd_free(fotg210, qh->dummy);
- + dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
- + kfree(qh);
- +}
- +
- +static struct fotg210_qh *fotg210_qh_alloc(struct fotg210_hcd *fotg210,
- + gfp_t flags)
- +{
- + struct fotg210_qh *qh;
- + dma_addr_t dma;
- +
- + qh = kzalloc(sizeof(*qh), GFP_ATOMIC);
- + if (!qh)
- + goto done;
- + qh->hw = (struct fotg210_qh_hw *)
- + dma_pool_zalloc(fotg210->qh_pool, flags, &dma);
- + if (!qh->hw)
- + goto fail;
- + qh->qh_dma = dma;
- + INIT_LIST_HEAD(&qh->qtd_list);
- +
- + /* dummy td enables safe urb queuing */
- + qh->dummy = fotg210_qtd_alloc(fotg210, flags);
- + if (qh->dummy == NULL) {
- + fotg210_dbg(fotg210, "no dummy td\n");
- + goto fail1;
- + }
- +done:
- + return qh;
- +fail1:
- + dma_pool_free(fotg210->qh_pool, qh->hw, qh->qh_dma);
- +fail:
- + kfree(qh);
- + return NULL;
- +}
- +
- +/* The queue heads and transfer descriptors are managed from pools tied
- + * to each of the "per device" structures.
- + * This is the initialisation and cleanup code.
- + */
- +
- +static void fotg210_mem_cleanup(struct fotg210_hcd *fotg210)
- +{
- + if (fotg210->async)
- + qh_destroy(fotg210, fotg210->async);
- + fotg210->async = NULL;
- +
- + if (fotg210->dummy)
- + qh_destroy(fotg210, fotg210->dummy);
- + fotg210->dummy = NULL;
- +
- + /* DMA consistent memory and pools */
- + dma_pool_destroy(fotg210->qtd_pool);
- + fotg210->qtd_pool = NULL;
- +
- + dma_pool_destroy(fotg210->qh_pool);
- + fotg210->qh_pool = NULL;
- +
- + dma_pool_destroy(fotg210->itd_pool);
- + fotg210->itd_pool = NULL;
- +
- + if (fotg210->periodic)
- + dma_free_coherent(fotg210_to_hcd(fotg210)->self.controller,
- + fotg210->periodic_size * sizeof(u32),
- + fotg210->periodic, fotg210->periodic_dma);
- + fotg210->periodic = NULL;
- +
- + /* shadow periodic table */
- + kfree(fotg210->pshadow);
- + fotg210->pshadow = NULL;
- +}
- +
- +/* remember to add cleanup code (above) if you add anything here */
- +static int fotg210_mem_init(struct fotg210_hcd *fotg210, gfp_t flags)
- +{
- + int i;
- +
- + /* QTDs for control/bulk/intr transfers */
- + fotg210->qtd_pool = dma_pool_create("fotg210_qtd",
- + fotg210_to_hcd(fotg210)->self.controller,
- + sizeof(struct fotg210_qtd),
- + 32 /* byte alignment (for hw parts) */,
- + 4096 /* can't cross 4K */);
- + if (!fotg210->qtd_pool)
- + goto fail;
- +
- + /* QHs for control/bulk/intr transfers */
- + fotg210->qh_pool = dma_pool_create("fotg210_qh",
- + fotg210_to_hcd(fotg210)->self.controller,
- + sizeof(struct fotg210_qh_hw),
- + 32 /* byte alignment (for hw parts) */,
- + 4096 /* can't cross 4K */);
- + if (!fotg210->qh_pool)
- + goto fail;
- +
- + fotg210->async = fotg210_qh_alloc(fotg210, flags);
- + if (!fotg210->async)
- + goto fail;
- +
- + /* ITD for high speed ISO transfers */
- + fotg210->itd_pool = dma_pool_create("fotg210_itd",
- + fotg210_to_hcd(fotg210)->self.controller,
- + sizeof(struct fotg210_itd),
- + 64 /* byte alignment (for hw parts) */,
- + 4096 /* can't cross 4K */);
- + if (!fotg210->itd_pool)
- + goto fail;
- +
- + /* Hardware periodic table */
- + fotg210->periodic =
- + dma_alloc_coherent(fotg210_to_hcd(fotg210)->self.controller,
- + fotg210->periodic_size * sizeof(__le32),
- + &fotg210->periodic_dma, 0);
- + if (fotg210->periodic == NULL)
- + goto fail;
- +
- + for (i = 0; i < fotg210->periodic_size; i++)
- + fotg210->periodic[i] = FOTG210_LIST_END(fotg210);
- +
- + /* software shadow of hardware table */
- + fotg210->pshadow = kcalloc(fotg210->periodic_size, sizeof(void *),
- + flags);
- + if (fotg210->pshadow != NULL)
- + return 0;
- +
- +fail:
- + fotg210_dbg(fotg210, "couldn't init memory\n");
- + fotg210_mem_cleanup(fotg210);
- + return -ENOMEM;
- +}
- +/* EHCI hardware queue manipulation ... the core. QH/QTD manipulation.
- + *
- + * Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd"
- + * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
- + * buffers needed for the larger number). We use one QH per endpoint, queue
- + * multiple urbs (all three types) per endpoint. URBs may need several qtds.
- + *
- + * ISO traffic uses "ISO TD" (itd) records, and (along with
- + * interrupts) needs careful scheduling. Performance improvements can be
- + * an ongoing challenge. That's in "ehci-sched.c".
- + *
- + * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
- + * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
- + * (b) special fields in qh entries or (c) split iso entries. TTs will
- + * buffer low/full speed data so the host collects it at high speed.
- + */
- +
- +/* fill a qtd, returning how much of the buffer we were able to queue up */
- +static int qtd_fill(struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd,
- + dma_addr_t buf, size_t len, int token, int maxpacket)
- +{
- + int i, count;
- + u64 addr = buf;
- +
- + /* one buffer entry per 4K ... first might be short or unaligned */
- + qtd->hw_buf[0] = cpu_to_hc32(fotg210, (u32)addr);
- + qtd->hw_buf_hi[0] = cpu_to_hc32(fotg210, (u32)(addr >> 32));
- + count = 0x1000 - (buf & 0x0fff); /* rest of that page */
- + if (likely(len < count)) /* ... iff needed */
- + count = len;
- + else {
- + buf += 0x1000;
- + buf &= ~0x0fff;
- +
- + /* per-qtd limit: from 16K to 20K (best alignment) */
- + for (i = 1; count < len && i < 5; i++) {
- + addr = buf;
- + qtd->hw_buf[i] = cpu_to_hc32(fotg210, (u32)addr);
- + qtd->hw_buf_hi[i] = cpu_to_hc32(fotg210,
- + (u32)(addr >> 32));
- + buf += 0x1000;
- + if ((count + 0x1000) < len)
- + count += 0x1000;
- + else
- + count = len;
- + }
- +
- + /* short packets may only terminate transfers */
- + if (count != len)
- + count -= (count % maxpacket);
- + }
- + qtd->hw_token = cpu_to_hc32(fotg210, (count << 16) | token);
- + qtd->length = count;
- +
- + return count;
- +}
- +
- +static inline void qh_update(struct fotg210_hcd *fotg210,
- + struct fotg210_qh *qh, struct fotg210_qtd *qtd)
- +{
- + struct fotg210_qh_hw *hw = qh->hw;
- +
- + /* writes to an active overlay are unsafe */
- + BUG_ON(qh->qh_state != QH_STATE_IDLE);
- +
- + hw->hw_qtd_next = QTD_NEXT(fotg210, qtd->qtd_dma);
- + hw->hw_alt_next = FOTG210_LIST_END(fotg210);
- +
- + /* Except for control endpoints, we make hardware maintain data
- + * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
- + * and set the pseudo-toggle in udev. Only usb_clear_halt() will
- + * ever clear it.
- + */
- + if (!(hw->hw_info1 & cpu_to_hc32(fotg210, QH_TOGGLE_CTL))) {
- + unsigned is_out, epnum;
- +
- + is_out = qh->is_out;
- + epnum = (hc32_to_cpup(fotg210, &hw->hw_info1) >> 8) & 0x0f;
- + if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) {
- + hw->hw_token &= ~cpu_to_hc32(fotg210, QTD_TOGGLE);
- + usb_settoggle(qh->dev, epnum, is_out, 1);
- + }
- + }
- +
- + hw->hw_token &= cpu_to_hc32(fotg210, QTD_TOGGLE | QTD_STS_PING);
- +}
- +
- +/* if it weren't for a common silicon quirk (writing the dummy into the qh
- + * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
- + * recovery (including urb dequeue) would need software changes to a QH...
- + */
- +static void qh_refresh(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- +{
- + struct fotg210_qtd *qtd;
- +
- + if (list_empty(&qh->qtd_list))
- + qtd = qh->dummy;
- + else {
- + qtd = list_entry(qh->qtd_list.next,
- + struct fotg210_qtd, qtd_list);
- + /*
- + * first qtd may already be partially processed.
- + * If we come here during unlink, the QH overlay region
- + * might have reference to the just unlinked qtd. The
- + * qtd is updated in qh_completions(). Update the QH
- + * overlay here.
- + */
- + if (cpu_to_hc32(fotg210, qtd->qtd_dma) == qh->hw->hw_current) {
- + qh->hw->hw_qtd_next = qtd->hw_next;
- + qtd = NULL;
- + }
- + }
- +
- + if (qtd)
- + qh_update(fotg210, qh, qtd);
- +}
- +
- +static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
- +
- +static void fotg210_clear_tt_buffer_complete(struct usb_hcd *hcd,
- + struct usb_host_endpoint *ep)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- + struct fotg210_qh *qh = ep->hcpriv;
- + unsigned long flags;
- +
- + spin_lock_irqsave(&fotg210->lock, flags);
- + qh->clearing_tt = 0;
- + if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
- + && fotg210->rh_state == FOTG210_RH_RUNNING)
- + qh_link_async(fotg210, qh);
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- +}
- +
- +static void fotg210_clear_tt_buffer(struct fotg210_hcd *fotg210,
- + struct fotg210_qh *qh, struct urb *urb, u32 token)
- +{
- +
- + /* If an async split transaction gets an error or is unlinked,
- + * the TT buffer may be left in an indeterminate state. We
- + * have to clear the TT buffer.
- + *
- + * Note: this routine is never called for Isochronous transfers.
- + */
- + if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) {
- + struct usb_device *tt = urb->dev->tt->hub;
- +
- + dev_dbg(&tt->dev,
- + "clear tt buffer port %d, a%d ep%d t%08x\n",
- + urb->dev->ttport, urb->dev->devnum,
- + usb_pipeendpoint(urb->pipe), token);
- +
- + if (urb->dev->tt->hub !=
- + fotg210_to_hcd(fotg210)->self.root_hub) {
- + if (usb_hub_clear_tt_buffer(urb) == 0)
- + qh->clearing_tt = 1;
- + }
- + }
- +}
- +
- +static int qtd_copy_status(struct fotg210_hcd *fotg210, struct urb *urb,
- + size_t length, u32 token)
- +{
- + int status = -EINPROGRESS;
- +
- + /* count IN/OUT bytes, not SETUP (even short packets) */
- + if (likely(QTD_PID(token) != 2))
- + urb->actual_length += length - QTD_LENGTH(token);
- +
- + /* don't modify error codes */
- + if (unlikely(urb->unlinked))
- + return status;
- +
- + /* force cleanup after short read; not always an error */
- + if (unlikely(IS_SHORT_READ(token)))
- + status = -EREMOTEIO;
- +
- + /* serious "can't proceed" faults reported by the hardware */
- + if (token & QTD_STS_HALT) {
- + if (token & QTD_STS_BABBLE) {
- + /* FIXME "must" disable babbling device's port too */
- + status = -EOVERFLOW;
- + /* CERR nonzero + halt --> stall */
- + } else if (QTD_CERR(token)) {
- + status = -EPIPE;
- +
- + /* In theory, more than one of the following bits can be set
- + * since they are sticky and the transaction is retried.
- + * Which to test first is rather arbitrary.
- + */
- + } else if (token & QTD_STS_MMF) {
- + /* fs/ls interrupt xfer missed the complete-split */
- + status = -EPROTO;
- + } else if (token & QTD_STS_DBE) {
- + status = (QTD_PID(token) == 1) /* IN ? */
- + ? -ENOSR /* hc couldn't read data */
- + : -ECOMM; /* hc couldn't write data */
- + } else if (token & QTD_STS_XACT) {
- + /* timeout, bad CRC, wrong PID, etc */
- + fotg210_dbg(fotg210, "devpath %s ep%d%s 3strikes\n",
- + urb->dev->devpath,
- + usb_pipeendpoint(urb->pipe),
- + usb_pipein(urb->pipe) ? "in" : "out");
- + status = -EPROTO;
- + } else { /* unknown */
- + status = -EPROTO;
- + }
- +
- + fotg210_dbg(fotg210,
- + "dev%d ep%d%s qtd token %08x --> status %d\n",
- + usb_pipedevice(urb->pipe),
- + usb_pipeendpoint(urb->pipe),
- + usb_pipein(urb->pipe) ? "in" : "out",
- + token, status);
- + }
- +
- + return status;
- +}
- +
- +static void fotg210_urb_done(struct fotg210_hcd *fotg210, struct urb *urb,
- + int status)
- +__releases(fotg210->lock)
- +__acquires(fotg210->lock)
- +{
- + if (likely(urb->hcpriv != NULL)) {
- + struct fotg210_qh *qh = (struct fotg210_qh *) urb->hcpriv;
- +
- + /* S-mask in a QH means it's an interrupt urb */
- + if ((qh->hw->hw_info2 & cpu_to_hc32(fotg210, QH_SMASK)) != 0) {
- +
- + /* ... update hc-wide periodic stats (for usbfs) */
- + fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs--;
- + }
- + }
- +
- + if (unlikely(urb->unlinked)) {
- + INCR(fotg210->stats.unlink);
- + } else {
- + /* report non-error and short read status as zero */
- + if (status == -EINPROGRESS || status == -EREMOTEIO)
- + status = 0;
- + INCR(fotg210->stats.complete);
- + }
- +
- +#ifdef FOTG210_URB_TRACE
- + fotg210_dbg(fotg210,
- + "%s %s urb %p ep%d%s status %d len %d/%d\n",
- + __func__, urb->dev->devpath, urb,
- + usb_pipeendpoint(urb->pipe),
- + usb_pipein(urb->pipe) ? "in" : "out",
- + status,
- + urb->actual_length, urb->transfer_buffer_length);
- +#endif
- +
- + /* complete() can reenter this HCD */
- + usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
- + spin_unlock(&fotg210->lock);
- + usb_hcd_giveback_urb(fotg210_to_hcd(fotg210), urb, status);
- + spin_lock(&fotg210->lock);
- +}
- +
- +static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh);
- +
- +/* Process and free completed qtds for a qh, returning URBs to drivers.
- + * Chases up to qh->hw_current. Returns number of completions called,
- + * indicating how much "real" work we did.
- + */
- +static unsigned qh_completions(struct fotg210_hcd *fotg210,
- + struct fotg210_qh *qh)
- +{
- + struct fotg210_qtd *last, *end = qh->dummy;
- + struct fotg210_qtd *qtd, *tmp;
- + int last_status;
- + int stopped;
- + unsigned count = 0;
- + u8 state;
- + struct fotg210_qh_hw *hw = qh->hw;
- +
- + if (unlikely(list_empty(&qh->qtd_list)))
- + return count;
- +
- + /* completions (or tasks on other cpus) must never clobber HALT
- + * till we've gone through and cleaned everything up, even when
- + * they add urbs to this qh's queue or mark them for unlinking.
- + *
- + * NOTE: unlinking expects to be done in queue order.
- + *
- + * It's a bug for qh->qh_state to be anything other than
- + * QH_STATE_IDLE, unless our caller is scan_async() or
- + * scan_intr().
- + */
- + state = qh->qh_state;
- + qh->qh_state = QH_STATE_COMPLETING;
- + stopped = (state == QH_STATE_IDLE);
- +
- +rescan:
- + last = NULL;
- + last_status = -EINPROGRESS;
- + qh->needs_rescan = 0;
- +
- + /* remove de-activated QTDs from front of queue.
- + * after faults (including short reads), cleanup this urb
- + * then let the queue advance.
- + * if queue is stopped, handles unlinks.
- + */
- + list_for_each_entry_safe(qtd, tmp, &qh->qtd_list, qtd_list) {
- + struct urb *urb;
- + u32 token = 0;
- +
- + urb = qtd->urb;
- +
- + /* clean up any state from previous QTD ...*/
- + if (last) {
- + if (likely(last->urb != urb)) {
- + fotg210_urb_done(fotg210, last->urb,
- + last_status);
- + count++;
- + last_status = -EINPROGRESS;
- + }
- + fotg210_qtd_free(fotg210, last);
- + last = NULL;
- + }
- +
- + /* ignore urbs submitted during completions we reported */
- + if (qtd == end)
- + break;
- +
- + /* hardware copies qtd out of qh overlay */
- + rmb();
- + token = hc32_to_cpu(fotg210, qtd->hw_token);
- +
- + /* always clean up qtds the hc de-activated */
- +retry_xacterr:
- + if ((token & QTD_STS_ACTIVE) == 0) {
- +
- + /* Report Data Buffer Error: non-fatal but useful */
- + if (token & QTD_STS_DBE)
- + fotg210_dbg(fotg210,
- + "detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n",
- + urb, usb_endpoint_num(&urb->ep->desc),
- + usb_endpoint_dir_in(&urb->ep->desc)
- + ? "in" : "out",
- + urb->transfer_buffer_length, qtd, qh);
- +
- + /* on STALL, error, and short reads this urb must
- + * complete and all its qtds must be recycled.
- + */
- + if ((token & QTD_STS_HALT) != 0) {
- +
- + /* retry transaction errors until we
- + * reach the software xacterr limit
- + */
- + if ((token & QTD_STS_XACT) &&
- + QTD_CERR(token) == 0 &&
- + ++qh->xacterrs < QH_XACTERR_MAX &&
- + !urb->unlinked) {
- + fotg210_dbg(fotg210,
- + "detected XactErr len %zu/%zu retry %d\n",
- + qtd->length - QTD_LENGTH(token),
- + qtd->length,
- + qh->xacterrs);
- +
- + /* reset the token in the qtd and the
- + * qh overlay (which still contains
- + * the qtd) so that we pick up from
- + * where we left off
- + */
- + token &= ~QTD_STS_HALT;
- + token |= QTD_STS_ACTIVE |
- + (FOTG210_TUNE_CERR << 10);
- + qtd->hw_token = cpu_to_hc32(fotg210,
- + token);
- + wmb();
- + hw->hw_token = cpu_to_hc32(fotg210,
- + token);
- + goto retry_xacterr;
- + }
- + stopped = 1;
- +
- + /* magic dummy for some short reads; qh won't advance.
- + * that silicon quirk can kick in with this dummy too.
- + *
- + * other short reads won't stop the queue, including
- + * control transfers (status stage handles that) or
- + * most other single-qtd reads ... the queue stops if
- + * URB_SHORT_NOT_OK was set so the driver submitting
- + * the urbs could clean it up.
- + */
- + } else if (IS_SHORT_READ(token) &&
- + !(qtd->hw_alt_next &
- + FOTG210_LIST_END(fotg210))) {
- + stopped = 1;
- + }
- +
- + /* stop scanning when we reach qtds the hc is using */
- + } else if (likely(!stopped
- + && fotg210->rh_state >= FOTG210_RH_RUNNING)) {
- + break;
- +
- + /* scan the whole queue for unlinks whenever it stops */
- + } else {
- + stopped = 1;
- +
- + /* cancel everything if we halt, suspend, etc */
- + if (fotg210->rh_state < FOTG210_RH_RUNNING)
- + last_status = -ESHUTDOWN;
- +
- + /* this qtd is active; skip it unless a previous qtd
- + * for its urb faulted, or its urb was canceled.
- + */
- + else if (last_status == -EINPROGRESS && !urb->unlinked)
- + continue;
- +
- + /* qh unlinked; token in overlay may be most current */
- + if (state == QH_STATE_IDLE &&
- + cpu_to_hc32(fotg210, qtd->qtd_dma)
- + == hw->hw_current) {
- + token = hc32_to_cpu(fotg210, hw->hw_token);
- +
- + /* An unlink may leave an incomplete
- + * async transaction in the TT buffer.
- + * We have to clear it.
- + */
- + fotg210_clear_tt_buffer(fotg210, qh, urb,
- + token);
- + }
- + }
- +
- + /* unless we already know the urb's status, collect qtd status
- + * and update count of bytes transferred. in common short read
- + * cases with only one data qtd (including control transfers),
- + * queue processing won't halt. but with two or more qtds (for
- + * example, with a 32 KB transfer), when the first qtd gets a
- + * short read the second must be removed by hand.
- + */
- + if (last_status == -EINPROGRESS) {
- + last_status = qtd_copy_status(fotg210, urb,
- + qtd->length, token);
- + if (last_status == -EREMOTEIO &&
- + (qtd->hw_alt_next &
- + FOTG210_LIST_END(fotg210)))
- + last_status = -EINPROGRESS;
- +
- + /* As part of low/full-speed endpoint-halt processing
- + * we must clear the TT buffer (11.17.5).
- + */
- + if (unlikely(last_status != -EINPROGRESS &&
- + last_status != -EREMOTEIO)) {
- + /* The TT's in some hubs malfunction when they
- + * receive this request following a STALL (they
- + * stop sending isochronous packets). Since a
- + * STALL can't leave the TT buffer in a busy
- + * state (if you believe Figures 11-48 - 11-51
- + * in the USB 2.0 spec), we won't clear the TT
- + * buffer in this case. Strictly speaking this
- + * is a violation of the spec.
- + */
- + if (last_status != -EPIPE)
- + fotg210_clear_tt_buffer(fotg210, qh,
- + urb, token);
- + }
- + }
- +
- + /* if we're removing something not at the queue head,
- + * patch the hardware queue pointer.
- + */
- + if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
- + last = list_entry(qtd->qtd_list.prev,
- + struct fotg210_qtd, qtd_list);
- + last->hw_next = qtd->hw_next;
- + }
- +
- + /* remove qtd; it's recycled after possible urb completion */
- + list_del(&qtd->qtd_list);
- + last = qtd;
- +
- + /* reinit the xacterr counter for the next qtd */
- + qh->xacterrs = 0;
- + }
- +
- + /* last urb's completion might still need calling */
- + if (likely(last != NULL)) {
- + fotg210_urb_done(fotg210, last->urb, last_status);
- + count++;
- + fotg210_qtd_free(fotg210, last);
- + }
- +
- + /* Do we need to rescan for URBs dequeued during a giveback? */
- + if (unlikely(qh->needs_rescan)) {
- + /* If the QH is already unlinked, do the rescan now. */
- + if (state == QH_STATE_IDLE)
- + goto rescan;
- +
- + /* Otherwise we have to wait until the QH is fully unlinked.
- + * Our caller will start an unlink if qh->needs_rescan is
- + * set. But if an unlink has already started, nothing needs
- + * to be done.
- + */
- + if (state != QH_STATE_LINKED)
- + qh->needs_rescan = 0;
- + }
- +
- + /* restore original state; caller must unlink or relink */
- + qh->qh_state = state;
- +
- + /* be sure the hardware's done with the qh before refreshing
- + * it after fault cleanup, or recovering from silicon wrongly
- + * overlaying the dummy qtd (which reduces DMA chatter).
- + */
- + if (stopped != 0 || hw->hw_qtd_next == FOTG210_LIST_END(fotg210)) {
- + switch (state) {
- + case QH_STATE_IDLE:
- + qh_refresh(fotg210, qh);
- + break;
- + case QH_STATE_LINKED:
- + /* We won't refresh a QH that's linked (after the HC
- + * stopped the queue). That avoids a race:
- + * - HC reads first part of QH;
- + * - CPU updates that first part and the token;
- + * - HC reads rest of that QH, including token
- + * Result: HC gets an inconsistent image, and then
- + * DMAs to/from the wrong memory (corrupting it).
- + *
- + * That should be rare for interrupt transfers,
- + * except maybe high bandwidth ...
- + */
- +
- + /* Tell the caller to start an unlink */
- + qh->needs_rescan = 1;
- + break;
- + /* otherwise, unlink already started */
- + }
- + }
- +
- + return count;
- +}
- +
- +/* reverse of qh_urb_transaction: free a list of TDs.
- + * used for cleanup after errors, before HC sees an URB's TDs.
- + */
- +static void qtd_list_free(struct fotg210_hcd *fotg210, struct urb *urb,
- + struct list_head *head)
- +{
- + struct fotg210_qtd *qtd, *temp;
- +
- + list_for_each_entry_safe(qtd, temp, head, qtd_list) {
- + list_del(&qtd->qtd_list);
- + fotg210_qtd_free(fotg210, qtd);
- + }
- +}
- +
- +/* create a list of filled qtds for this URB; won't link into qh.
- + */
- +static struct list_head *qh_urb_transaction(struct fotg210_hcd *fotg210,
- + struct urb *urb, struct list_head *head, gfp_t flags)
- +{
- + struct fotg210_qtd *qtd, *qtd_prev;
- + dma_addr_t buf;
- + int len, this_sg_len, maxpacket;
- + int is_input;
- + u32 token;
- + int i;
- + struct scatterlist *sg;
- +
- + /*
- + * URBs map to sequences of QTDs: one logical transaction
- + */
- + qtd = fotg210_qtd_alloc(fotg210, flags);
- + if (unlikely(!qtd))
- + return NULL;
- + list_add_tail(&qtd->qtd_list, head);
- + qtd->urb = urb;
- +
- + token = QTD_STS_ACTIVE;
- + token |= (FOTG210_TUNE_CERR << 10);
- + /* for split transactions, SplitXState initialized to zero */
- +
- + len = urb->transfer_buffer_length;
- + is_input = usb_pipein(urb->pipe);
- + if (usb_pipecontrol(urb->pipe)) {
- + /* SETUP pid */
- + qtd_fill(fotg210, qtd, urb->setup_dma,
- + sizeof(struct usb_ctrlrequest),
- + token | (2 /* "setup" */ << 8), 8);
- +
- + /* ... and always at least one more pid */
- + token ^= QTD_TOGGLE;
- + qtd_prev = qtd;
- + qtd = fotg210_qtd_alloc(fotg210, flags);
- + if (unlikely(!qtd))
- + goto cleanup;
- + qtd->urb = urb;
- + qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
- + list_add_tail(&qtd->qtd_list, head);
- +
- + /* for zero length DATA stages, STATUS is always IN */
- + if (len == 0)
- + token |= (1 /* "in" */ << 8);
- + }
- +
- + /*
- + * data transfer stage: buffer setup
- + */
- + i = urb->num_mapped_sgs;
- + if (len > 0 && i > 0) {
- + sg = urb->sg;
- + buf = sg_dma_address(sg);
- +
- + /* urb->transfer_buffer_length may be smaller than the
- + * size of the scatterlist (or vice versa)
- + */
- + this_sg_len = min_t(int, sg_dma_len(sg), len);
- + } else {
- + sg = NULL;
- + buf = urb->transfer_dma;
- + this_sg_len = len;
- + }
- +
- + if (is_input)
- + token |= (1 /* "in" */ << 8);
- + /* else it's already initted to "out" pid (0 << 8) */
- +
- + maxpacket = usb_maxpacket(urb->dev, urb->pipe);
- +
- + /*
- + * buffer gets wrapped in one or more qtds;
- + * last one may be "short" (including zero len)
- + * and may serve as a control status ack
- + */
- + for (;;) {
- + int this_qtd_len;
- +
- + this_qtd_len = qtd_fill(fotg210, qtd, buf, this_sg_len, token,
- + maxpacket);
- + this_sg_len -= this_qtd_len;
- + len -= this_qtd_len;
- + buf += this_qtd_len;
- +
- + /*
- + * short reads advance to a "magic" dummy instead of the next
- + * qtd ... that forces the queue to stop, for manual cleanup.
- + * (this will usually be overridden later.)
- + */
- + if (is_input)
- + qtd->hw_alt_next = fotg210->async->hw->hw_alt_next;
- +
- + /* qh makes control packets use qtd toggle; maybe switch it */
- + if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
- + token ^= QTD_TOGGLE;
- +
- + if (likely(this_sg_len <= 0)) {
- + if (--i <= 0 || len <= 0)
- + break;
- + sg = sg_next(sg);
- + buf = sg_dma_address(sg);
- + this_sg_len = min_t(int, sg_dma_len(sg), len);
- + }
- +
- + qtd_prev = qtd;
- + qtd = fotg210_qtd_alloc(fotg210, flags);
- + if (unlikely(!qtd))
- + goto cleanup;
- + qtd->urb = urb;
- + qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
- + list_add_tail(&qtd->qtd_list, head);
- + }
- +
- + /*
- + * unless the caller requires manual cleanup after short reads,
- + * have the alt_next mechanism keep the queue running after the
- + * last data qtd (the only one, for control and most other cases).
- + */
- + if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0 ||
- + usb_pipecontrol(urb->pipe)))
- + qtd->hw_alt_next = FOTG210_LIST_END(fotg210);
- +
- + /*
- + * control requests may need a terminating data "status" ack;
- + * other OUT ones may need a terminating short packet
- + * (zero length).
- + */
- + if (likely(urb->transfer_buffer_length != 0)) {
- + int one_more = 0;
- +
- + if (usb_pipecontrol(urb->pipe)) {
- + one_more = 1;
- + token ^= 0x0100; /* "in" <--> "out" */
- + token |= QTD_TOGGLE; /* force DATA1 */
- + } else if (usb_pipeout(urb->pipe)
- + && (urb->transfer_flags & URB_ZERO_PACKET)
- + && !(urb->transfer_buffer_length % maxpacket)) {
- + one_more = 1;
- + }
- + if (one_more) {
- + qtd_prev = qtd;
- + qtd = fotg210_qtd_alloc(fotg210, flags);
- + if (unlikely(!qtd))
- + goto cleanup;
- + qtd->urb = urb;
- + qtd_prev->hw_next = QTD_NEXT(fotg210, qtd->qtd_dma);
- + list_add_tail(&qtd->qtd_list, head);
- +
- + /* never any data in such packets */
- + qtd_fill(fotg210, qtd, 0, 0, token, 0);
- + }
- + }
- +
- + /* by default, enable interrupt on urb completion */
- + if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
- + qtd->hw_token |= cpu_to_hc32(fotg210, QTD_IOC);
- + return head;
- +
- +cleanup:
- + qtd_list_free(fotg210, urb, head);
- + return NULL;
- +}
- +
- +/* Would be best to create all qh's from config descriptors,
- + * when each interface/altsetting is established. Unlink
- + * any previous qh and cancel its urbs first; endpoints are
- + * implicitly reset then (data toggle too).
- + * That'd mean updating how usbcore talks to HCDs. (2.7?)
- + */
- +
- +
- +/* Each QH holds a qtd list; a QH is used for everything except iso.
- + *
- + * For interrupt urbs, the scheduler must set the microframe scheduling
- + * mask(s) each time the QH gets scheduled. For highspeed, that's
- + * just one microframe in the s-mask. For split interrupt transactions
- + * there are additional complications: c-mask, maybe FSTNs.
- + */
- +static struct fotg210_qh *qh_make(struct fotg210_hcd *fotg210, struct urb *urb,
- + gfp_t flags)
- +{
- + struct fotg210_qh *qh = fotg210_qh_alloc(fotg210, flags);
- + struct usb_host_endpoint *ep;
- + u32 info1 = 0, info2 = 0;
- + int is_input, type;
- + int maxp = 0;
- + int mult;
- + struct usb_tt *tt = urb->dev->tt;
- + struct fotg210_qh_hw *hw;
- +
- + if (!qh)
- + return qh;
- +
- + /*
- + * init endpoint/device data for this QH
- + */
- + info1 |= usb_pipeendpoint(urb->pipe) << 8;
- + info1 |= usb_pipedevice(urb->pipe) << 0;
- +
- + is_input = usb_pipein(urb->pipe);
- + type = usb_pipetype(urb->pipe);
- + ep = usb_pipe_endpoint(urb->dev, urb->pipe);
- + maxp = usb_endpoint_maxp(&ep->desc);
- + mult = usb_endpoint_maxp_mult(&ep->desc);
- +
- + /* 1024 byte maxpacket is a hardware ceiling. High bandwidth
- + * acts like up to 3KB, but is built from smaller packets.
- + */
- + if (maxp > 1024) {
- + fotg210_dbg(fotg210, "bogus qh maxpacket %d\n", maxp);
- + goto done;
- + }
- +
- + /* Compute interrupt scheduling parameters just once, and save.
- + * - allowing for high bandwidth, how many nsec/uframe are used?
- + * - split transactions need a second CSPLIT uframe; same question
- + * - splits also need a schedule gap (for full/low speed I/O)
- + * - qh has a polling interval
- + *
- + * For control/bulk requests, the HC or TT handles these.
- + */
- + if (type == PIPE_INTERRUPT) {
- + qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
- + is_input, 0, mult * maxp));
- + qh->start = NO_FRAME;
- +
- + if (urb->dev->speed == USB_SPEED_HIGH) {
- + qh->c_usecs = 0;
- + qh->gap_uf = 0;
- +
- + qh->period = urb->interval >> 3;
- + if (qh->period == 0 && urb->interval != 1) {
- + /* NOTE interval 2 or 4 uframes could work.
- + * But interval 1 scheduling is simpler, and
- + * includes high bandwidth.
- + */
- + urb->interval = 1;
- + } else if (qh->period > fotg210->periodic_size) {
- + qh->period = fotg210->periodic_size;
- + urb->interval = qh->period << 3;
- + }
- + } else {
- + int think_time;
- +
- + /* gap is f(FS/LS transfer times) */
- + qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed,
- + is_input, 0, maxp) / (125 * 1000);
- +
- + /* FIXME this just approximates SPLIT/CSPLIT times */
- + if (is_input) { /* SPLIT, gap, CSPLIT+DATA */
- + qh->c_usecs = qh->usecs + HS_USECS(0);
- + qh->usecs = HS_USECS(1);
- + } else { /* SPLIT+DATA, gap, CSPLIT */
- + qh->usecs += HS_USECS(1);
- + qh->c_usecs = HS_USECS(0);
- + }
- +
- + think_time = tt ? tt->think_time : 0;
- + qh->tt_usecs = NS_TO_US(think_time +
- + usb_calc_bus_time(urb->dev->speed,
- + is_input, 0, maxp));
- + qh->period = urb->interval;
- + if (qh->period > fotg210->periodic_size) {
- + qh->period = fotg210->periodic_size;
- + urb->interval = qh->period;
- + }
- + }
- + }
- +
- + /* support for tt scheduling, and access to toggles */
- + qh->dev = urb->dev;
- +
- + /* using TT? */
- + switch (urb->dev->speed) {
- + case USB_SPEED_LOW:
- + info1 |= QH_LOW_SPEED;
- + fallthrough;
- +
- + case USB_SPEED_FULL:
- + /* EPS 0 means "full" */
- + if (type != PIPE_INTERRUPT)
- + info1 |= (FOTG210_TUNE_RL_TT << 28);
- + if (type == PIPE_CONTROL) {
- + info1 |= QH_CONTROL_EP; /* for TT */
- + info1 |= QH_TOGGLE_CTL; /* toggle from qtd */
- + }
- + info1 |= maxp << 16;
- +
- + info2 |= (FOTG210_TUNE_MULT_TT << 30);
- +
- + /* Some Freescale processors have an erratum in which the
- + * port number in the queue head was 0..N-1 instead of 1..N.
- + */
- + if (fotg210_has_fsl_portno_bug(fotg210))
- + info2 |= (urb->dev->ttport-1) << 23;
- + else
- + info2 |= urb->dev->ttport << 23;
- +
- + /* set the address of the TT; for TDI's integrated
- + * root hub tt, leave it zeroed.
- + */
- + if (tt && tt->hub != fotg210_to_hcd(fotg210)->self.root_hub)
- + info2 |= tt->hub->devnum << 16;
- +
- + /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */
- +
- + break;
- +
- + case USB_SPEED_HIGH: /* no TT involved */
- + info1 |= QH_HIGH_SPEED;
- + if (type == PIPE_CONTROL) {
- + info1 |= (FOTG210_TUNE_RL_HS << 28);
- + info1 |= 64 << 16; /* usb2 fixed maxpacket */
- + info1 |= QH_TOGGLE_CTL; /* toggle from qtd */
- + info2 |= (FOTG210_TUNE_MULT_HS << 30);
- + } else if (type == PIPE_BULK) {
- + info1 |= (FOTG210_TUNE_RL_HS << 28);
- + /* The USB spec says that high speed bulk endpoints
- + * always use 512 byte maxpacket. But some device
- + * vendors decided to ignore that, and MSFT is happy
- + * to help them do so. So now people expect to use
- + * such nonconformant devices with Linux too; sigh.
- + */
- + info1 |= maxp << 16;
- + info2 |= (FOTG210_TUNE_MULT_HS << 30);
- + } else { /* PIPE_INTERRUPT */
- + info1 |= maxp << 16;
- + info2 |= mult << 30;
- + }
- + break;
- + default:
- + fotg210_dbg(fotg210, "bogus dev %p speed %d\n", urb->dev,
- + urb->dev->speed);
- +done:
- + qh_destroy(fotg210, qh);
- + return NULL;
- + }
- +
- + /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */
- +
- + /* init as live, toggle clear, advance to dummy */
- + qh->qh_state = QH_STATE_IDLE;
- + hw = qh->hw;
- + hw->hw_info1 = cpu_to_hc32(fotg210, info1);
- + hw->hw_info2 = cpu_to_hc32(fotg210, info2);
- + qh->is_out = !is_input;
- + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1);
- + qh_refresh(fotg210, qh);
- + return qh;
- +}
- +
- +static void enable_async(struct fotg210_hcd *fotg210)
- +{
- + if (fotg210->async_count++)
- + return;
- +
- + /* Stop waiting to turn off the async schedule */
- + fotg210->enabled_hrtimer_events &= ~BIT(FOTG210_HRTIMER_DISABLE_ASYNC);
- +
- + /* Don't start the schedule until ASS is 0 */
- + fotg210_poll_ASS(fotg210);
- + turn_on_io_watchdog(fotg210);
- +}
- +
- +static void disable_async(struct fotg210_hcd *fotg210)
- +{
- + if (--fotg210->async_count)
- + return;
- +
- + /* The async schedule and async_unlink list are supposed to be empty */
- + WARN_ON(fotg210->async->qh_next.qh || fotg210->async_unlink);
- +
- + /* Don't turn off the schedule until ASS is 1 */
- + fotg210_poll_ASS(fotg210);
- +}
- +
- +/* move qh (and its qtds) onto async queue; maybe enable queue. */
- +
- +static void qh_link_async(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- +{
- + __hc32 dma = QH_NEXT(fotg210, qh->qh_dma);
- + struct fotg210_qh *head;
- +
- + /* Don't link a QH if there's a Clear-TT-Buffer pending */
- + if (unlikely(qh->clearing_tt))
- + return;
- +
- + WARN_ON(qh->qh_state != QH_STATE_IDLE);
- +
- + /* clear halt and/or toggle; and maybe recover from silicon quirk */
- + qh_refresh(fotg210, qh);
- +
- + /* splice right after start */
- + head = fotg210->async;
- + qh->qh_next = head->qh_next;
- + qh->hw->hw_next = head->hw->hw_next;
- + wmb();
- +
- + head->qh_next.qh = qh;
- + head->hw->hw_next = dma;
- +
- + qh->xacterrs = 0;
- + qh->qh_state = QH_STATE_LINKED;
- + /* qtd completions reported later by interrupt */
- +
- + enable_async(fotg210);
- +}
- +
- +/* For control/bulk/interrupt, return QH with these TDs appended.
- + * Allocates and initializes the QH if necessary.
- + * Returns null if it can't allocate a QH it needs to.
- + * If the QH has TDs (urbs) already, that's great.
- + */
- +static struct fotg210_qh *qh_append_tds(struct fotg210_hcd *fotg210,
- + struct urb *urb, struct list_head *qtd_list,
- + int epnum, void **ptr)
- +{
- + struct fotg210_qh *qh = NULL;
- + __hc32 qh_addr_mask = cpu_to_hc32(fotg210, 0x7f);
- +
- + qh = (struct fotg210_qh *) *ptr;
- + if (unlikely(qh == NULL)) {
- + /* can't sleep here, we have fotg210->lock... */
- + qh = qh_make(fotg210, urb, GFP_ATOMIC);
- + *ptr = qh;
- + }
- + if (likely(qh != NULL)) {
- + struct fotg210_qtd *qtd;
- +
- + if (unlikely(list_empty(qtd_list)))
- + qtd = NULL;
- + else
- + qtd = list_entry(qtd_list->next, struct fotg210_qtd,
- + qtd_list);
- +
- + /* control qh may need patching ... */
- + if (unlikely(epnum == 0)) {
- + /* usb_reset_device() briefly reverts to address 0 */
- + if (usb_pipedevice(urb->pipe) == 0)
- + qh->hw->hw_info1 &= ~qh_addr_mask;
- + }
- +
- + /* just one way to queue requests: swap with the dummy qtd.
- + * only hc or qh_refresh() ever modify the overlay.
- + */
- + if (likely(qtd != NULL)) {
- + struct fotg210_qtd *dummy;
- + dma_addr_t dma;
- + __hc32 token;
- +
- + /* to avoid racing the HC, use the dummy td instead of
- + * the first td of our list (becomes new dummy). both
- + * tds stay deactivated until we're done, when the
- + * HC is allowed to fetch the old dummy (4.10.2).
- + */
- + token = qtd->hw_token;
- + qtd->hw_token = HALT_BIT(fotg210);
- +
- + dummy = qh->dummy;
- +
- + dma = dummy->qtd_dma;
- + *dummy = *qtd;
- + dummy->qtd_dma = dma;
- +
- + list_del(&qtd->qtd_list);
- + list_add(&dummy->qtd_list, qtd_list);
- + list_splice_tail(qtd_list, &qh->qtd_list);
- +
- + fotg210_qtd_init(fotg210, qtd, qtd->qtd_dma);
- + qh->dummy = qtd;
- +
- + /* hc must see the new dummy at list end */
- + dma = qtd->qtd_dma;
- + qtd = list_entry(qh->qtd_list.prev,
- + struct fotg210_qtd, qtd_list);
- + qtd->hw_next = QTD_NEXT(fotg210, dma);
- +
- + /* let the hc process these next qtds */
- + wmb();
- + dummy->hw_token = token;
- +
- + urb->hcpriv = qh;
- + }
- + }
- + return qh;
- +}
- +
- +static int submit_async(struct fotg210_hcd *fotg210, struct urb *urb,
- + struct list_head *qtd_list, gfp_t mem_flags)
- +{
- + int epnum;
- + unsigned long flags;
- + struct fotg210_qh *qh = NULL;
- + int rc;
- +
- + epnum = urb->ep->desc.bEndpointAddress;
- +
- +#ifdef FOTG210_URB_TRACE
- + {
- + struct fotg210_qtd *qtd;
- +
- + qtd = list_entry(qtd_list->next, struct fotg210_qtd, qtd_list);
- + fotg210_dbg(fotg210,
- + "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
- + __func__, urb->dev->devpath, urb,
- + epnum & 0x0f, (epnum & USB_DIR_IN)
- + ? "in" : "out",
- + urb->transfer_buffer_length,
- + qtd, urb->ep->hcpriv);
- + }
- +#endif
- +
- + spin_lock_irqsave(&fotg210->lock, flags);
- + if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
- + rc = -ESHUTDOWN;
- + goto done;
- + }
- + rc = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
- + if (unlikely(rc))
- + goto done;
- +
- + qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
- + if (unlikely(qh == NULL)) {
- + usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
- + rc = -ENOMEM;
- + goto done;
- + }
- +
- + /* Control/bulk operations through TTs don't need scheduling,
- + * the HC and TT handle it when the TT has a buffer ready.
- + */
- + if (likely(qh->qh_state == QH_STATE_IDLE))
- + qh_link_async(fotg210, qh);
- +done:
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + if (unlikely(qh == NULL))
- + qtd_list_free(fotg210, urb, qtd_list);
- + return rc;
- +}
- +
- +static void single_unlink_async(struct fotg210_hcd *fotg210,
- + struct fotg210_qh *qh)
- +{
- + struct fotg210_qh *prev;
- +
- + /* Add to the end of the list of QHs waiting for the next IAAD */
- + qh->qh_state = QH_STATE_UNLINK;
- + if (fotg210->async_unlink)
- + fotg210->async_unlink_last->unlink_next = qh;
- + else
- + fotg210->async_unlink = qh;
- + fotg210->async_unlink_last = qh;
- +
- + /* Unlink it from the schedule */
- + prev = fotg210->async;
- + while (prev->qh_next.qh != qh)
- + prev = prev->qh_next.qh;
- +
- + prev->hw->hw_next = qh->hw->hw_next;
- + prev->qh_next = qh->qh_next;
- + if (fotg210->qh_scan_next == qh)
- + fotg210->qh_scan_next = qh->qh_next.qh;
- +}
- +
- +static void start_iaa_cycle(struct fotg210_hcd *fotg210, bool nested)
- +{
- + /*
- + * Do nothing if an IAA cycle is already running or
- + * if one will be started shortly.
- + */
- + if (fotg210->async_iaa || fotg210->async_unlinking)
- + return;
- +
- + /* Do all the waiting QHs at once */
- + fotg210->async_iaa = fotg210->async_unlink;
- + fotg210->async_unlink = NULL;
- +
- + /* If the controller isn't running, we don't have to wait for it */
- + if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING)) {
- + if (!nested) /* Avoid recursion */
- + end_unlink_async(fotg210);
- +
- + /* Otherwise start a new IAA cycle */
- + } else if (likely(fotg210->rh_state == FOTG210_RH_RUNNING)) {
- + /* Make sure the unlinks are all visible to the hardware */
- + wmb();
- +
- + fotg210_writel(fotg210, fotg210->command | CMD_IAAD,
- + &fotg210->regs->command);
- + fotg210_readl(fotg210, &fotg210->regs->command);
- + fotg210_enable_event(fotg210, FOTG210_HRTIMER_IAA_WATCHDOG,
- + true);
- + }
- +}
- +
- +/* the async qh for the qtds being unlinked are now gone from the HC */
- +
- +static void end_unlink_async(struct fotg210_hcd *fotg210)
- +{
- + struct fotg210_qh *qh;
- +
- + /* Process the idle QHs */
- +restart:
- + fotg210->async_unlinking = true;
- + while (fotg210->async_iaa) {
- + qh = fotg210->async_iaa;
- + fotg210->async_iaa = qh->unlink_next;
- + qh->unlink_next = NULL;
- +
- + qh->qh_state = QH_STATE_IDLE;
- + qh->qh_next.qh = NULL;
- +
- + qh_completions(fotg210, qh);
- + if (!list_empty(&qh->qtd_list) &&
- + fotg210->rh_state == FOTG210_RH_RUNNING)
- + qh_link_async(fotg210, qh);
- + disable_async(fotg210);
- + }
- + fotg210->async_unlinking = false;
- +
- + /* Start a new IAA cycle if any QHs are waiting for it */
- + if (fotg210->async_unlink) {
- + start_iaa_cycle(fotg210, true);
- + if (unlikely(fotg210->rh_state < FOTG210_RH_RUNNING))
- + goto restart;
- + }
- +}
- +
- +static void unlink_empty_async(struct fotg210_hcd *fotg210)
- +{
- + struct fotg210_qh *qh, *next;
- + bool stopped = (fotg210->rh_state < FOTG210_RH_RUNNING);
- + bool check_unlinks_later = false;
- +
- + /* Unlink all the async QHs that have been empty for a timer cycle */
- + next = fotg210->async->qh_next.qh;
- + while (next) {
- + qh = next;
- + next = qh->qh_next.qh;
- +
- + if (list_empty(&qh->qtd_list) &&
- + qh->qh_state == QH_STATE_LINKED) {
- + if (!stopped && qh->unlink_cycle ==
- + fotg210->async_unlink_cycle)
- + check_unlinks_later = true;
- + else
- + single_unlink_async(fotg210, qh);
- + }
- + }
- +
- + /* Start a new IAA cycle if any QHs are waiting for it */
- + if (fotg210->async_unlink)
- + start_iaa_cycle(fotg210, false);
- +
- + /* QHs that haven't been empty for long enough will be handled later */
- + if (check_unlinks_later) {
- + fotg210_enable_event(fotg210, FOTG210_HRTIMER_ASYNC_UNLINKS,
- + true);
- + ++fotg210->async_unlink_cycle;
- + }
- +}
- +
- +/* makes sure the async qh will become idle */
- +/* caller must own fotg210->lock */
- +
- +static void start_unlink_async(struct fotg210_hcd *fotg210,
- + struct fotg210_qh *qh)
- +{
- + /*
- + * If the QH isn't linked then there's nothing we can do
- + * unless we were called during a giveback, in which case
- + * qh_completions() has to deal with it.
- + */
- + if (qh->qh_state != QH_STATE_LINKED) {
- + if (qh->qh_state == QH_STATE_COMPLETING)
- + qh->needs_rescan = 1;
- + return;
- + }
- +
- + single_unlink_async(fotg210, qh);
- + start_iaa_cycle(fotg210, false);
- +}
- +
- +static void scan_async(struct fotg210_hcd *fotg210)
- +{
- + struct fotg210_qh *qh;
- + bool check_unlinks_later = false;
- +
- + fotg210->qh_scan_next = fotg210->async->qh_next.qh;
- + while (fotg210->qh_scan_next) {
- + qh = fotg210->qh_scan_next;
- + fotg210->qh_scan_next = qh->qh_next.qh;
- +rescan:
- + /* clean any finished work for this qh */
- + if (!list_empty(&qh->qtd_list)) {
- + int temp;
- +
- + /*
- + * Unlinks could happen here; completion reporting
- + * drops the lock. That's why fotg210->qh_scan_next
- + * always holds the next qh to scan; if the next qh
- + * gets unlinked then fotg210->qh_scan_next is adjusted
- + * in single_unlink_async().
- + */
- + temp = qh_completions(fotg210, qh);
- + if (qh->needs_rescan) {
- + start_unlink_async(fotg210, qh);
- + } else if (list_empty(&qh->qtd_list)
- + && qh->qh_state == QH_STATE_LINKED) {
- + qh->unlink_cycle = fotg210->async_unlink_cycle;
- + check_unlinks_later = true;
- + } else if (temp != 0)
- + goto rescan;
- + }
- + }
- +
- + /*
- + * Unlink empty entries, reducing DMA usage as well
- + * as HCD schedule-scanning costs. Delay for any qh
- + * we just scanned, there's a not-unusual case that it
- + * doesn't stay idle for long.
- + */
- + if (check_unlinks_later && fotg210->rh_state == FOTG210_RH_RUNNING &&
- + !(fotg210->enabled_hrtimer_events &
- + BIT(FOTG210_HRTIMER_ASYNC_UNLINKS))) {
- + fotg210_enable_event(fotg210,
- + FOTG210_HRTIMER_ASYNC_UNLINKS, true);
- + ++fotg210->async_unlink_cycle;
- + }
- +}
- +/* EHCI scheduled transaction support: interrupt, iso, split iso
- + * These are called "periodic" transactions in the EHCI spec.
- + *
- + * Note that for interrupt transfers, the QH/QTD manipulation is shared
- + * with the "asynchronous" transaction support (control/bulk transfers).
- + * The only real difference is in how interrupt transfers are scheduled.
- + *
- + * For ISO, we make an "iso_stream" head to serve the same role as a QH.
- + * It keeps track of every ITD (or SITD) that's linked, and holds enough
- + * pre-calculated schedule data to make appending to the queue be quick.
- + */
- +static int fotg210_get_frame(struct usb_hcd *hcd);
- +
- +/* periodic_next_shadow - return "next" pointer on shadow list
- + * @periodic: host pointer to qh/itd
- + * @tag: hardware tag for type of this record
- + */
- +static union fotg210_shadow *periodic_next_shadow(struct fotg210_hcd *fotg210,
- + union fotg210_shadow *periodic, __hc32 tag)
- +{
- + switch (hc32_to_cpu(fotg210, tag)) {
- + case Q_TYPE_QH:
- + return &periodic->qh->qh_next;
- + case Q_TYPE_FSTN:
- + return &periodic->fstn->fstn_next;
- + default:
- + return &periodic->itd->itd_next;
- + }
- +}
- +
- +static __hc32 *shadow_next_periodic(struct fotg210_hcd *fotg210,
- + union fotg210_shadow *periodic, __hc32 tag)
- +{
- + switch (hc32_to_cpu(fotg210, tag)) {
- + /* our fotg210_shadow.qh is actually software part */
- + case Q_TYPE_QH:
- + return &periodic->qh->hw->hw_next;
- + /* others are hw parts */
- + default:
- + return periodic->hw_next;
- + }
- +}
- +
- +/* caller must hold fotg210->lock */
- +static void periodic_unlink(struct fotg210_hcd *fotg210, unsigned frame,
- + void *ptr)
- +{
- + union fotg210_shadow *prev_p = &fotg210->pshadow[frame];
- + __hc32 *hw_p = &fotg210->periodic[frame];
- + union fotg210_shadow here = *prev_p;
- +
- + /* find predecessor of "ptr"; hw and shadow lists are in sync */
- + while (here.ptr && here.ptr != ptr) {
- + prev_p = periodic_next_shadow(fotg210, prev_p,
- + Q_NEXT_TYPE(fotg210, *hw_p));
- + hw_p = shadow_next_periodic(fotg210, &here,
- + Q_NEXT_TYPE(fotg210, *hw_p));
- + here = *prev_p;
- + }
- + /* an interrupt entry (at list end) could have been shared */
- + if (!here.ptr)
- + return;
- +
- + /* update shadow and hardware lists ... the old "next" pointers
- + * from ptr may still be in use, the caller updates them.
- + */
- + *prev_p = *periodic_next_shadow(fotg210, &here,
- + Q_NEXT_TYPE(fotg210, *hw_p));
- +
- + *hw_p = *shadow_next_periodic(fotg210, &here,
- + Q_NEXT_TYPE(fotg210, *hw_p));
- +}
- +
- +/* how many of the uframe's 125 usecs are allocated? */
- +static unsigned short periodic_usecs(struct fotg210_hcd *fotg210,
- + unsigned frame, unsigned uframe)
- +{
- + __hc32 *hw_p = &fotg210->periodic[frame];
- + union fotg210_shadow *q = &fotg210->pshadow[frame];
- + unsigned usecs = 0;
- + struct fotg210_qh_hw *hw;
- +
- + while (q->ptr) {
- + switch (hc32_to_cpu(fotg210, Q_NEXT_TYPE(fotg210, *hw_p))) {
- + case Q_TYPE_QH:
- + hw = q->qh->hw;
- + /* is it in the S-mask? */
- + if (hw->hw_info2 & cpu_to_hc32(fotg210, 1 << uframe))
- + usecs += q->qh->usecs;
- + /* ... or C-mask? */
- + if (hw->hw_info2 & cpu_to_hc32(fotg210,
- + 1 << (8 + uframe)))
- + usecs += q->qh->c_usecs;
- + hw_p = &hw->hw_next;
- + q = &q->qh->qh_next;
- + break;
- + /* case Q_TYPE_FSTN: */
- + default:
- + /* for "save place" FSTNs, count the relevant INTR
- + * bandwidth from the previous frame
- + */
- + if (q->fstn->hw_prev != FOTG210_LIST_END(fotg210))
- + fotg210_dbg(fotg210, "ignoring FSTN cost ...\n");
- +
- + hw_p = &q->fstn->hw_next;
- + q = &q->fstn->fstn_next;
- + break;
- + case Q_TYPE_ITD:
- + if (q->itd->hw_transaction[uframe])
- + usecs += q->itd->stream->usecs;
- + hw_p = &q->itd->hw_next;
- + q = &q->itd->itd_next;
- + break;
- + }
- + }
- + if (usecs > fotg210->uframe_periodic_max)
- + fotg210_err(fotg210, "uframe %d sched overrun: %d usecs\n",
- + frame * 8 + uframe, usecs);
- + return usecs;
- +}
- +
- +static int same_tt(struct usb_device *dev1, struct usb_device *dev2)
- +{
- + if (!dev1->tt || !dev2->tt)
- + return 0;
- + if (dev1->tt != dev2->tt)
- + return 0;
- + if (dev1->tt->multi)
- + return dev1->ttport == dev2->ttport;
- + else
- + return 1;
- +}
- +
- +/* return true iff the device's transaction translator is available
- + * for a periodic transfer starting at the specified frame, using
- + * all the uframes in the mask.
- + */
- +static int tt_no_collision(struct fotg210_hcd *fotg210, unsigned period,
- + struct usb_device *dev, unsigned frame, u32 uf_mask)
- +{
- + if (period == 0) /* error */
- + return 0;
- +
- + /* note bandwidth wastage: split never follows csplit
- + * (different dev or endpoint) until the next uframe.
- + * calling convention doesn't make that distinction.
- + */
- + for (; frame < fotg210->periodic_size; frame += period) {
- + union fotg210_shadow here;
- + __hc32 type;
- + struct fotg210_qh_hw *hw;
- +
- + here = fotg210->pshadow[frame];
- + type = Q_NEXT_TYPE(fotg210, fotg210->periodic[frame]);
- + while (here.ptr) {
- + switch (hc32_to_cpu(fotg210, type)) {
- + case Q_TYPE_ITD:
- + type = Q_NEXT_TYPE(fotg210, here.itd->hw_next);
- + here = here.itd->itd_next;
- + continue;
- + case Q_TYPE_QH:
- + hw = here.qh->hw;
- + if (same_tt(dev, here.qh->dev)) {
- + u32 mask;
- +
- + mask = hc32_to_cpu(fotg210,
- + hw->hw_info2);
- + /* "knows" no gap is needed */
- + mask |= mask >> 8;
- + if (mask & uf_mask)
- + break;
- + }
- + type = Q_NEXT_TYPE(fotg210, hw->hw_next);
- + here = here.qh->qh_next;
- + continue;
- + /* case Q_TYPE_FSTN: */
- + default:
- + fotg210_dbg(fotg210,
- + "periodic frame %d bogus type %d\n",
- + frame, type);
- + }
- +
- + /* collision or error */
- + return 0;
- + }
- + }
- +
- + /* no collision */
- + return 1;
- +}
- +
- +static void enable_periodic(struct fotg210_hcd *fotg210)
- +{
- + if (fotg210->periodic_count++)
- + return;
- +
- + /* Stop waiting to turn off the periodic schedule */
- + fotg210->enabled_hrtimer_events &=
- + ~BIT(FOTG210_HRTIMER_DISABLE_PERIODIC);
- +
- + /* Don't start the schedule until PSS is 0 */
- + fotg210_poll_PSS(fotg210);
- + turn_on_io_watchdog(fotg210);
- +}
- +
- +static void disable_periodic(struct fotg210_hcd *fotg210)
- +{
- + if (--fotg210->periodic_count)
- + return;
- +
- + /* Don't turn off the schedule until PSS is 1 */
- + fotg210_poll_PSS(fotg210);
- +}
- +
- +/* periodic schedule slots have iso tds (normal or split) first, then a
- + * sparse tree for active interrupt transfers.
- + *
- + * this just links in a qh; caller guarantees uframe masks are set right.
- + * no FSTN support (yet; fotg210 0.96+)
- + */
- +static void qh_link_periodic(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- +{
- + unsigned i;
- + unsigned period = qh->period;
- +
- + dev_dbg(&qh->dev->dev,
- + "link qh%d-%04x/%p start %d [%d/%d us]\n", period,
- + hc32_to_cpup(fotg210, &qh->hw->hw_info2) &
- + (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs,
- + qh->c_usecs);
- +
- + /* high bandwidth, or otherwise every microframe */
- + if (period == 0)
- + period = 1;
- +
- + for (i = qh->start; i < fotg210->periodic_size; i += period) {
- + union fotg210_shadow *prev = &fotg210->pshadow[i];
- + __hc32 *hw_p = &fotg210->periodic[i];
- + union fotg210_shadow here = *prev;
- + __hc32 type = 0;
- +
- + /* skip the iso nodes at list head */
- + while (here.ptr) {
- + type = Q_NEXT_TYPE(fotg210, *hw_p);
- + if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
- + break;
- + prev = periodic_next_shadow(fotg210, prev, type);
- + hw_p = shadow_next_periodic(fotg210, &here, type);
- + here = *prev;
- + }
- +
- + /* sorting each branch by period (slow-->fast)
- + * enables sharing interior tree nodes
- + */
- + while (here.ptr && qh != here.qh) {
- + if (qh->period > here.qh->period)
- + break;
- + prev = &here.qh->qh_next;
- + hw_p = &here.qh->hw->hw_next;
- + here = *prev;
- + }
- + /* link in this qh, unless some earlier pass did that */
- + if (qh != here.qh) {
- + qh->qh_next = here;
- + if (here.qh)
- + qh->hw->hw_next = *hw_p;
- + wmb();
- + prev->qh = qh;
- + *hw_p = QH_NEXT(fotg210, qh->qh_dma);
- + }
- + }
- + qh->qh_state = QH_STATE_LINKED;
- + qh->xacterrs = 0;
- +
- + /* update per-qh bandwidth for usbfs */
- + fotg210_to_hcd(fotg210)->self.bandwidth_allocated += qh->period
- + ? ((qh->usecs + qh->c_usecs) / qh->period)
- + : (qh->usecs * 8);
- +
- + list_add(&qh->intr_node, &fotg210->intr_qh_list);
- +
- + /* maybe enable periodic schedule processing */
- + ++fotg210->intr_count;
- + enable_periodic(fotg210);
- +}
- +
- +static void qh_unlink_periodic(struct fotg210_hcd *fotg210,
- + struct fotg210_qh *qh)
- +{
- + unsigned i;
- + unsigned period;
- +
- + /*
- + * If qh is for a low/full-speed device, simply unlinking it
- + * could interfere with an ongoing split transaction. To unlink
- + * it safely would require setting the QH_INACTIVATE bit and
- + * waiting at least one frame, as described in EHCI 4.12.2.5.
- + *
- + * We won't bother with any of this. Instead, we assume that the
- + * only reason for unlinking an interrupt QH while the current URB
- + * is still active is to dequeue all the URBs (flush the whole
- + * endpoint queue).
- + *
- + * If rebalancing the periodic schedule is ever implemented, this
- + * approach will no longer be valid.
- + */
- +
- + /* high bandwidth, or otherwise part of every microframe */
- + period = qh->period;
- + if (!period)
- + period = 1;
- +
- + for (i = qh->start; i < fotg210->periodic_size; i += period)
- + periodic_unlink(fotg210, i, qh);
- +
- + /* update per-qh bandwidth for usbfs */
- + fotg210_to_hcd(fotg210)->self.bandwidth_allocated -= qh->period
- + ? ((qh->usecs + qh->c_usecs) / qh->period)
- + : (qh->usecs * 8);
- +
- + dev_dbg(&qh->dev->dev,
- + "unlink qh%d-%04x/%p start %d [%d/%d us]\n",
- + qh->period, hc32_to_cpup(fotg210, &qh->hw->hw_info2) &
- + (QH_CMASK | QH_SMASK), qh, qh->start, qh->usecs,
- + qh->c_usecs);
- +
- + /* qh->qh_next still "live" to HC */
- + qh->qh_state = QH_STATE_UNLINK;
- + qh->qh_next.ptr = NULL;
- +
- + if (fotg210->qh_scan_next == qh)
- + fotg210->qh_scan_next = list_entry(qh->intr_node.next,
- + struct fotg210_qh, intr_node);
- + list_del(&qh->intr_node);
- +}
- +
- +static void start_unlink_intr(struct fotg210_hcd *fotg210,
- + struct fotg210_qh *qh)
- +{
- + /* If the QH isn't linked then there's nothing we can do
- + * unless we were called during a giveback, in which case
- + * qh_completions() has to deal with it.
- + */
- + if (qh->qh_state != QH_STATE_LINKED) {
- + if (qh->qh_state == QH_STATE_COMPLETING)
- + qh->needs_rescan = 1;
- + return;
- + }
- +
- + qh_unlink_periodic(fotg210, qh);
- +
- + /* Make sure the unlinks are visible before starting the timer */
- + wmb();
- +
- + /*
- + * The EHCI spec doesn't say how long it takes the controller to
- + * stop accessing an unlinked interrupt QH. The timer delay is
- + * 9 uframes; presumably that will be long enough.
- + */
- + qh->unlink_cycle = fotg210->intr_unlink_cycle;
- +
- + /* New entries go at the end of the intr_unlink list */
- + if (fotg210->intr_unlink)
- + fotg210->intr_unlink_last->unlink_next = qh;
- + else
- + fotg210->intr_unlink = qh;
- + fotg210->intr_unlink_last = qh;
- +
- + if (fotg210->intr_unlinking)
- + ; /* Avoid recursive calls */
- + else if (fotg210->rh_state < FOTG210_RH_RUNNING)
- + fotg210_handle_intr_unlinks(fotg210);
- + else if (fotg210->intr_unlink == qh) {
- + fotg210_enable_event(fotg210, FOTG210_HRTIMER_UNLINK_INTR,
- + true);
- + ++fotg210->intr_unlink_cycle;
- + }
- +}
- +
- +static void end_unlink_intr(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- +{
- + struct fotg210_qh_hw *hw = qh->hw;
- + int rc;
- +
- + qh->qh_state = QH_STATE_IDLE;
- + hw->hw_next = FOTG210_LIST_END(fotg210);
- +
- + qh_completions(fotg210, qh);
- +
- + /* reschedule QH iff another request is queued */
- + if (!list_empty(&qh->qtd_list) &&
- + fotg210->rh_state == FOTG210_RH_RUNNING) {
- + rc = qh_schedule(fotg210, qh);
- +
- + /* An error here likely indicates handshake failure
- + * or no space left in the schedule. Neither fault
- + * should happen often ...
- + *
- + * FIXME kill the now-dysfunctional queued urbs
- + */
- + if (rc != 0)
- + fotg210_err(fotg210, "can't reschedule qh %p, err %d\n",
- + qh, rc);
- + }
- +
- + /* maybe turn off periodic schedule */
- + --fotg210->intr_count;
- + disable_periodic(fotg210);
- +}
- +
- +static int check_period(struct fotg210_hcd *fotg210, unsigned frame,
- + unsigned uframe, unsigned period, unsigned usecs)
- +{
- + int claimed;
- +
- + /* complete split running into next frame?
- + * given FSTN support, we could sometimes check...
- + */
- + if (uframe >= 8)
- + return 0;
- +
- + /* convert "usecs we need" to "max already claimed" */
- + usecs = fotg210->uframe_periodic_max - usecs;
- +
- + /* we "know" 2 and 4 uframe intervals were rejected; so
- + * for period 0, check _every_ microframe in the schedule.
- + */
- + if (unlikely(period == 0)) {
- + do {
- + for (uframe = 0; uframe < 7; uframe++) {
- + claimed = periodic_usecs(fotg210, frame,
- + uframe);
- + if (claimed > usecs)
- + return 0;
- + }
- + } while ((frame += 1) < fotg210->periodic_size);
- +
- + /* just check the specified uframe, at that period */
- + } else {
- + do {
- + claimed = periodic_usecs(fotg210, frame, uframe);
- + if (claimed > usecs)
- + return 0;
- + } while ((frame += period) < fotg210->periodic_size);
- + }
- +
- + /* success! */
- + return 1;
- +}
- +
- +static int check_intr_schedule(struct fotg210_hcd *fotg210, unsigned frame,
- + unsigned uframe, const struct fotg210_qh *qh, __hc32 *c_maskp)
- +{
- + int retval = -ENOSPC;
- + u8 mask = 0;
- +
- + if (qh->c_usecs && uframe >= 6) /* FSTN territory? */
- + goto done;
- +
- + if (!check_period(fotg210, frame, uframe, qh->period, qh->usecs))
- + goto done;
- + if (!qh->c_usecs) {
- + retval = 0;
- + *c_maskp = 0;
- + goto done;
- + }
- +
- + /* Make sure this tt's buffer is also available for CSPLITs.
- + * We pessimize a bit; probably the typical full speed case
- + * doesn't need the second CSPLIT.
- + *
- + * NOTE: both SPLIT and CSPLIT could be checked in just
- + * one smart pass...
- + */
- + mask = 0x03 << (uframe + qh->gap_uf);
- + *c_maskp = cpu_to_hc32(fotg210, mask << 8);
- +
- + mask |= 1 << uframe;
- + if (tt_no_collision(fotg210, qh->period, qh->dev, frame, mask)) {
- + if (!check_period(fotg210, frame, uframe + qh->gap_uf + 1,
- + qh->period, qh->c_usecs))
- + goto done;
- + if (!check_period(fotg210, frame, uframe + qh->gap_uf,
- + qh->period, qh->c_usecs))
- + goto done;
- + retval = 0;
- + }
- +done:
- + return retval;
- +}
- +
- +/* "first fit" scheduling policy used the first time through,
- + * or when the previous schedule slot can't be re-used.
- + */
- +static int qh_schedule(struct fotg210_hcd *fotg210, struct fotg210_qh *qh)
- +{
- + int status;
- + unsigned uframe;
- + __hc32 c_mask;
- + unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
- + struct fotg210_qh_hw *hw = qh->hw;
- +
- + qh_refresh(fotg210, qh);
- + hw->hw_next = FOTG210_LIST_END(fotg210);
- + frame = qh->start;
- +
- + /* reuse the previous schedule slots, if we can */
- + if (frame < qh->period) {
- + uframe = ffs(hc32_to_cpup(fotg210, &hw->hw_info2) & QH_SMASK);
- + status = check_intr_schedule(fotg210, frame, --uframe,
- + qh, &c_mask);
- + } else {
- + uframe = 0;
- + c_mask = 0;
- + status = -ENOSPC;
- + }
- +
- + /* else scan the schedule to find a group of slots such that all
- + * uframes have enough periodic bandwidth available.
- + */
- + if (status) {
- + /* "normal" case, uframing flexible except with splits */
- + if (qh->period) {
- + int i;
- +
- + for (i = qh->period; status && i > 0; --i) {
- + frame = ++fotg210->random_frame % qh->period;
- + for (uframe = 0; uframe < 8; uframe++) {
- + status = check_intr_schedule(fotg210,
- + frame, uframe, qh,
- + &c_mask);
- + if (status == 0)
- + break;
- + }
- + }
- +
- + /* qh->period == 0 means every uframe */
- + } else {
- + frame = 0;
- + status = check_intr_schedule(fotg210, 0, 0, qh,
- + &c_mask);
- + }
- + if (status)
- + goto done;
- + qh->start = frame;
- +
- + /* reset S-frame and (maybe) C-frame masks */
- + hw->hw_info2 &= cpu_to_hc32(fotg210, ~(QH_CMASK | QH_SMASK));
- + hw->hw_info2 |= qh->period
- + ? cpu_to_hc32(fotg210, 1 << uframe)
- + : cpu_to_hc32(fotg210, QH_SMASK);
- + hw->hw_info2 |= c_mask;
- + } else
- + fotg210_dbg(fotg210, "reused qh %p schedule\n", qh);
- +
- + /* stuff into the periodic schedule */
- + qh_link_periodic(fotg210, qh);
- +done:
- + return status;
- +}
- +
- +static int intr_submit(struct fotg210_hcd *fotg210, struct urb *urb,
- + struct list_head *qtd_list, gfp_t mem_flags)
- +{
- + unsigned epnum;
- + unsigned long flags;
- + struct fotg210_qh *qh;
- + int status;
- + struct list_head empty;
- +
- + /* get endpoint and transfer/schedule data */
- + epnum = urb->ep->desc.bEndpointAddress;
- +
- + spin_lock_irqsave(&fotg210->lock, flags);
- +
- + if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
- + status = -ESHUTDOWN;
- + goto done_not_linked;
- + }
- + status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
- + if (unlikely(status))
- + goto done_not_linked;
- +
- + /* get qh and force any scheduling errors */
- + INIT_LIST_HEAD(&empty);
- + qh = qh_append_tds(fotg210, urb, &empty, epnum, &urb->ep->hcpriv);
- + if (qh == NULL) {
- + status = -ENOMEM;
- + goto done;
- + }
- + if (qh->qh_state == QH_STATE_IDLE) {
- + status = qh_schedule(fotg210, qh);
- + if (status)
- + goto done;
- + }
- +
- + /* then queue the urb's tds to the qh */
- + qh = qh_append_tds(fotg210, urb, qtd_list, epnum, &urb->ep->hcpriv);
- + BUG_ON(qh == NULL);
- +
- + /* ... update usbfs periodic stats */
- + fotg210_to_hcd(fotg210)->self.bandwidth_int_reqs++;
- +
- +done:
- + if (unlikely(status))
- + usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
- +done_not_linked:
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + if (status)
- + qtd_list_free(fotg210, urb, qtd_list);
- +
- + return status;
- +}
- +
- +static void scan_intr(struct fotg210_hcd *fotg210)
- +{
- + struct fotg210_qh *qh;
- +
- + list_for_each_entry_safe(qh, fotg210->qh_scan_next,
- + &fotg210->intr_qh_list, intr_node) {
- +rescan:
- + /* clean any finished work for this qh */
- + if (!list_empty(&qh->qtd_list)) {
- + int temp;
- +
- + /*
- + * Unlinks could happen here; completion reporting
- + * drops the lock. That's why fotg210->qh_scan_next
- + * always holds the next qh to scan; if the next qh
- + * gets unlinked then fotg210->qh_scan_next is adjusted
- + * in qh_unlink_periodic().
- + */
- + temp = qh_completions(fotg210, qh);
- + if (unlikely(qh->needs_rescan ||
- + (list_empty(&qh->qtd_list) &&
- + qh->qh_state == QH_STATE_LINKED)))
- + start_unlink_intr(fotg210, qh);
- + else if (temp != 0)
- + goto rescan;
- + }
- + }
- +}
- +
- +/* fotg210_iso_stream ops work with both ITD and SITD */
- +
- +static struct fotg210_iso_stream *iso_stream_alloc(gfp_t mem_flags)
- +{
- + struct fotg210_iso_stream *stream;
- +
- + stream = kzalloc(sizeof(*stream), mem_flags);
- + if (likely(stream != NULL)) {
- + INIT_LIST_HEAD(&stream->td_list);
- + INIT_LIST_HEAD(&stream->free_list);
- + stream->next_uframe = -1;
- + }
- + return stream;
- +}
- +
- +static void iso_stream_init(struct fotg210_hcd *fotg210,
- + struct fotg210_iso_stream *stream, struct usb_device *dev,
- + int pipe, unsigned interval)
- +{
- + u32 buf1;
- + unsigned epnum, maxp;
- + int is_input;
- + long bandwidth;
- + unsigned multi;
- + struct usb_host_endpoint *ep;
- +
- + /*
- + * this might be a "high bandwidth" highspeed endpoint,
- + * as encoded in the ep descriptor's wMaxPacket field
- + */
- + epnum = usb_pipeendpoint(pipe);
- + is_input = usb_pipein(pipe) ? USB_DIR_IN : 0;
- + ep = usb_pipe_endpoint(dev, pipe);
- + maxp = usb_endpoint_maxp(&ep->desc);
- + if (is_input)
- + buf1 = (1 << 11);
- + else
- + buf1 = 0;
- +
- + multi = usb_endpoint_maxp_mult(&ep->desc);
- + buf1 |= maxp;
- + maxp *= multi;
- +
- + stream->buf0 = cpu_to_hc32(fotg210, (epnum << 8) | dev->devnum);
- + stream->buf1 = cpu_to_hc32(fotg210, buf1);
- + stream->buf2 = cpu_to_hc32(fotg210, multi);
- +
- + /* usbfs wants to report the average usecs per frame tied up
- + * when transfers on this endpoint are scheduled ...
- + */
- + if (dev->speed == USB_SPEED_FULL) {
- + interval <<= 3;
- + stream->usecs = NS_TO_US(usb_calc_bus_time(dev->speed,
- + is_input, 1, maxp));
- + stream->usecs /= 8;
- + } else {
- + stream->highspeed = 1;
- + stream->usecs = HS_USECS_ISO(maxp);
- + }
- + bandwidth = stream->usecs * 8;
- + bandwidth /= interval;
- +
- + stream->bandwidth = bandwidth;
- + stream->udev = dev;
- + stream->bEndpointAddress = is_input | epnum;
- + stream->interval = interval;
- + stream->maxp = maxp;
- +}
- +
- +static struct fotg210_iso_stream *iso_stream_find(struct fotg210_hcd *fotg210,
- + struct urb *urb)
- +{
- + unsigned epnum;
- + struct fotg210_iso_stream *stream;
- + struct usb_host_endpoint *ep;
- + unsigned long flags;
- +
- + epnum = usb_pipeendpoint(urb->pipe);
- + if (usb_pipein(urb->pipe))
- + ep = urb->dev->ep_in[epnum];
- + else
- + ep = urb->dev->ep_out[epnum];
- +
- + spin_lock_irqsave(&fotg210->lock, flags);
- + stream = ep->hcpriv;
- +
- + if (unlikely(stream == NULL)) {
- + stream = iso_stream_alloc(GFP_ATOMIC);
- + if (likely(stream != NULL)) {
- + ep->hcpriv = stream;
- + stream->ep = ep;
- + iso_stream_init(fotg210, stream, urb->dev, urb->pipe,
- + urb->interval);
- + }
- +
- + /* if dev->ep[epnum] is a QH, hw is set */
- + } else if (unlikely(stream->hw != NULL)) {
- + fotg210_dbg(fotg210, "dev %s ep%d%s, not iso??\n",
- + urb->dev->devpath, epnum,
- + usb_pipein(urb->pipe) ? "in" : "out");
- + stream = NULL;
- + }
- +
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + return stream;
- +}
- +
- +/* fotg210_iso_sched ops can be ITD-only or SITD-only */
- +
- +static struct fotg210_iso_sched *iso_sched_alloc(unsigned packets,
- + gfp_t mem_flags)
- +{
- + struct fotg210_iso_sched *iso_sched;
- +
- + iso_sched = kzalloc(struct_size(iso_sched, packet, packets), mem_flags);
- + if (likely(iso_sched != NULL))
- + INIT_LIST_HEAD(&iso_sched->td_list);
- +
- + return iso_sched;
- +}
- +
- +static inline void itd_sched_init(struct fotg210_hcd *fotg210,
- + struct fotg210_iso_sched *iso_sched,
- + struct fotg210_iso_stream *stream, struct urb *urb)
- +{
- + unsigned i;
- + dma_addr_t dma = urb->transfer_dma;
- +
- + /* how many uframes are needed for these transfers */
- + iso_sched->span = urb->number_of_packets * stream->interval;
- +
- + /* figure out per-uframe itd fields that we'll need later
- + * when we fit new itds into the schedule.
- + */
- + for (i = 0; i < urb->number_of_packets; i++) {
- + struct fotg210_iso_packet *uframe = &iso_sched->packet[i];
- + unsigned length;
- + dma_addr_t buf;
- + u32 trans;
- +
- + length = urb->iso_frame_desc[i].length;
- + buf = dma + urb->iso_frame_desc[i].offset;
- +
- + trans = FOTG210_ISOC_ACTIVE;
- + trans |= buf & 0x0fff;
- + if (unlikely(((i + 1) == urb->number_of_packets))
- + && !(urb->transfer_flags & URB_NO_INTERRUPT))
- + trans |= FOTG210_ITD_IOC;
- + trans |= length << 16;
- + uframe->transaction = cpu_to_hc32(fotg210, trans);
- +
- + /* might need to cross a buffer page within a uframe */
- + uframe->bufp = (buf & ~(u64)0x0fff);
- + buf += length;
- + if (unlikely((uframe->bufp != (buf & ~(u64)0x0fff))))
- + uframe->cross = 1;
- + }
- +}
- +
- +static void iso_sched_free(struct fotg210_iso_stream *stream,
- + struct fotg210_iso_sched *iso_sched)
- +{
- + if (!iso_sched)
- + return;
- + /* caller must hold fotg210->lock!*/
- + list_splice(&iso_sched->td_list, &stream->free_list);
- + kfree(iso_sched);
- +}
- +
- +static int itd_urb_transaction(struct fotg210_iso_stream *stream,
- + struct fotg210_hcd *fotg210, struct urb *urb, gfp_t mem_flags)
- +{
- + struct fotg210_itd *itd;
- + dma_addr_t itd_dma;
- + int i;
- + unsigned num_itds;
- + struct fotg210_iso_sched *sched;
- + unsigned long flags;
- +
- + sched = iso_sched_alloc(urb->number_of_packets, mem_flags);
- + if (unlikely(sched == NULL))
- + return -ENOMEM;
- +
- + itd_sched_init(fotg210, sched, stream, urb);
- +
- + if (urb->interval < 8)
- + num_itds = 1 + (sched->span + 7) / 8;
- + else
- + num_itds = urb->number_of_packets;
- +
- + /* allocate/init ITDs */
- + spin_lock_irqsave(&fotg210->lock, flags);
- + for (i = 0; i < num_itds; i++) {
- +
- + /*
- + * Use iTDs from the free list, but not iTDs that may
- + * still be in use by the hardware.
- + */
- + if (likely(!list_empty(&stream->free_list))) {
- + itd = list_first_entry(&stream->free_list,
- + struct fotg210_itd, itd_list);
- + if (itd->frame == fotg210->now_frame)
- + goto alloc_itd;
- + list_del(&itd->itd_list);
- + itd_dma = itd->itd_dma;
- + } else {
- +alloc_itd:
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + itd = dma_pool_alloc(fotg210->itd_pool, mem_flags,
- + &itd_dma);
- + spin_lock_irqsave(&fotg210->lock, flags);
- + if (!itd) {
- + iso_sched_free(stream, sched);
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + return -ENOMEM;
- + }
- + }
- +
- + memset(itd, 0, sizeof(*itd));
- + itd->itd_dma = itd_dma;
- + list_add(&itd->itd_list, &sched->td_list);
- + }
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- +
- + /* temporarily store schedule info in hcpriv */
- + urb->hcpriv = sched;
- + urb->error_count = 0;
- + return 0;
- +}
- +
- +static inline int itd_slot_ok(struct fotg210_hcd *fotg210, u32 mod, u32 uframe,
- + u8 usecs, u32 period)
- +{
- + uframe %= period;
- + do {
- + /* can't commit more than uframe_periodic_max usec */
- + if (periodic_usecs(fotg210, uframe >> 3, uframe & 0x7)
- + > (fotg210->uframe_periodic_max - usecs))
- + return 0;
- +
- + /* we know urb->interval is 2^N uframes */
- + uframe += period;
- + } while (uframe < mod);
- + return 1;
- +}
- +
- +/* This scheduler plans almost as far into the future as it has actual
- + * periodic schedule slots. (Affected by TUNE_FLS, which defaults to
- + * "as small as possible" to be cache-friendlier.) That limits the size
- + * transfers you can stream reliably; avoid more than 64 msec per urb.
- + * Also avoid queue depths of less than fotg210's worst irq latency (affected
- + * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter,
- + * and other factors); or more than about 230 msec total (for portability,
- + * given FOTG210_TUNE_FLS and the slop). Or, write a smarter scheduler!
- + */
- +
- +#define SCHEDULE_SLOP 80 /* microframes */
- +
- +static int iso_stream_schedule(struct fotg210_hcd *fotg210, struct urb *urb,
- + struct fotg210_iso_stream *stream)
- +{
- + u32 now, next, start, period, span;
- + int status;
- + unsigned mod = fotg210->periodic_size << 3;
- + struct fotg210_iso_sched *sched = urb->hcpriv;
- +
- + period = urb->interval;
- + span = sched->span;
- +
- + if (span > mod - SCHEDULE_SLOP) {
- + fotg210_dbg(fotg210, "iso request %p too long\n", urb);
- + status = -EFBIG;
- + goto fail;
- + }
- +
- + now = fotg210_read_frame_index(fotg210) & (mod - 1);
- +
- + /* Typical case: reuse current schedule, stream is still active.
- + * Hopefully there are no gaps from the host falling behind
- + * (irq delays etc), but if there are we'll take the next
- + * slot in the schedule, implicitly assuming URB_ISO_ASAP.
- + */
- + if (likely(!list_empty(&stream->td_list))) {
- + u32 excess;
- +
- + /* For high speed devices, allow scheduling within the
- + * isochronous scheduling threshold. For full speed devices
- + * and Intel PCI-based controllers, don't (work around for
- + * Intel ICH9 bug).
- + */
- + if (!stream->highspeed && fotg210->fs_i_thresh)
- + next = now + fotg210->i_thresh;
- + else
- + next = now;
- +
- + /* Fell behind (by up to twice the slop amount)?
- + * We decide based on the time of the last currently-scheduled
- + * slot, not the time of the next available slot.
- + */
- + excess = (stream->next_uframe - period - next) & (mod - 1);
- + if (excess >= mod - 2 * SCHEDULE_SLOP)
- + start = next + excess - mod + period *
- + DIV_ROUND_UP(mod - excess, period);
- + else
- + start = next + excess + period;
- + if (start - now >= mod) {
- + fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
- + urb, start - now - period, period,
- + mod);
- + status = -EFBIG;
- + goto fail;
- + }
- + }
- +
- + /* need to schedule; when's the next (u)frame we could start?
- + * this is bigger than fotg210->i_thresh allows; scheduling itself
- + * isn't free, the slop should handle reasonably slow cpus. it
- + * can also help high bandwidth if the dma and irq loads don't
- + * jump until after the queue is primed.
- + */
- + else {
- + int done = 0;
- +
- + start = SCHEDULE_SLOP + (now & ~0x07);
- +
- + /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */
- +
- + /* find a uframe slot with enough bandwidth.
- + * Early uframes are more precious because full-speed
- + * iso IN transfers can't use late uframes,
- + * and therefore they should be allocated last.
- + */
- + next = start;
- + start += period;
- + do {
- + start--;
- + /* check schedule: enough space? */
- + if (itd_slot_ok(fotg210, mod, start,
- + stream->usecs, period))
- + done = 1;
- + } while (start > next && !done);
- +
- + /* no room in the schedule */
- + if (!done) {
- + fotg210_dbg(fotg210, "iso resched full %p (now %d max %d)\n",
- + urb, now, now + mod);
- + status = -ENOSPC;
- + goto fail;
- + }
- + }
- +
- + /* Tried to schedule too far into the future? */
- + if (unlikely(start - now + span - period >=
- + mod - 2 * SCHEDULE_SLOP)) {
- + fotg210_dbg(fotg210, "request %p would overflow (%d+%d >= %d)\n",
- + urb, start - now, span - period,
- + mod - 2 * SCHEDULE_SLOP);
- + status = -EFBIG;
- + goto fail;
- + }
- +
- + stream->next_uframe = start & (mod - 1);
- +
- + /* report high speed start in uframes; full speed, in frames */
- + urb->start_frame = stream->next_uframe;
- + if (!stream->highspeed)
- + urb->start_frame >>= 3;
- +
- + /* Make sure scan_isoc() sees these */
- + if (fotg210->isoc_count == 0)
- + fotg210->next_frame = now >> 3;
- + return 0;
- +
- +fail:
- + iso_sched_free(stream, sched);
- + urb->hcpriv = NULL;
- + return status;
- +}
- +
- +static inline void itd_init(struct fotg210_hcd *fotg210,
- + struct fotg210_iso_stream *stream, struct fotg210_itd *itd)
- +{
- + int i;
- +
- + /* it's been recently zeroed */
- + itd->hw_next = FOTG210_LIST_END(fotg210);
- + itd->hw_bufp[0] = stream->buf0;
- + itd->hw_bufp[1] = stream->buf1;
- + itd->hw_bufp[2] = stream->buf2;
- +
- + for (i = 0; i < 8; i++)
- + itd->index[i] = -1;
- +
- + /* All other fields are filled when scheduling */
- +}
- +
- +static inline void itd_patch(struct fotg210_hcd *fotg210,
- + struct fotg210_itd *itd, struct fotg210_iso_sched *iso_sched,
- + unsigned index, u16 uframe)
- +{
- + struct fotg210_iso_packet *uf = &iso_sched->packet[index];
- + unsigned pg = itd->pg;
- +
- + uframe &= 0x07;
- + itd->index[uframe] = index;
- +
- + itd->hw_transaction[uframe] = uf->transaction;
- + itd->hw_transaction[uframe] |= cpu_to_hc32(fotg210, pg << 12);
- + itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, uf->bufp & ~(u32)0);
- + itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(uf->bufp >> 32));
- +
- + /* iso_frame_desc[].offset must be strictly increasing */
- + if (unlikely(uf->cross)) {
- + u64 bufp = uf->bufp + 4096;
- +
- + itd->pg = ++pg;
- + itd->hw_bufp[pg] |= cpu_to_hc32(fotg210, bufp & ~(u32)0);
- + itd->hw_bufp_hi[pg] |= cpu_to_hc32(fotg210, (u32)(bufp >> 32));
- + }
- +}
- +
- +static inline void itd_link(struct fotg210_hcd *fotg210, unsigned frame,
- + struct fotg210_itd *itd)
- +{
- + union fotg210_shadow *prev = &fotg210->pshadow[frame];
- + __hc32 *hw_p = &fotg210->periodic[frame];
- + union fotg210_shadow here = *prev;
- + __hc32 type = 0;
- +
- + /* skip any iso nodes which might belong to previous microframes */
- + while (here.ptr) {
- + type = Q_NEXT_TYPE(fotg210, *hw_p);
- + if (type == cpu_to_hc32(fotg210, Q_TYPE_QH))
- + break;
- + prev = periodic_next_shadow(fotg210, prev, type);
- + hw_p = shadow_next_periodic(fotg210, &here, type);
- + here = *prev;
- + }
- +
- + itd->itd_next = here;
- + itd->hw_next = *hw_p;
- + prev->itd = itd;
- + itd->frame = frame;
- + wmb();
- + *hw_p = cpu_to_hc32(fotg210, itd->itd_dma | Q_TYPE_ITD);
- +}
- +
- +/* fit urb's itds into the selected schedule slot; activate as needed */
- +static void itd_link_urb(struct fotg210_hcd *fotg210, struct urb *urb,
- + unsigned mod, struct fotg210_iso_stream *stream)
- +{
- + int packet;
- + unsigned next_uframe, uframe, frame;
- + struct fotg210_iso_sched *iso_sched = urb->hcpriv;
- + struct fotg210_itd *itd;
- +
- + next_uframe = stream->next_uframe & (mod - 1);
- +
- + if (unlikely(list_empty(&stream->td_list))) {
- + fotg210_to_hcd(fotg210)->self.bandwidth_allocated
- + += stream->bandwidth;
- + fotg210_dbg(fotg210,
- + "schedule devp %s ep%d%s-iso period %d start %d.%d\n",
- + urb->dev->devpath, stream->bEndpointAddress & 0x0f,
- + (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
- + urb->interval,
- + next_uframe >> 3, next_uframe & 0x7);
- + }
- +
- + /* fill iTDs uframe by uframe */
- + for (packet = 0, itd = NULL; packet < urb->number_of_packets;) {
- + if (itd == NULL) {
- + /* ASSERT: we have all necessary itds */
- +
- + /* ASSERT: no itds for this endpoint in this uframe */
- +
- + itd = list_entry(iso_sched->td_list.next,
- + struct fotg210_itd, itd_list);
- + list_move_tail(&itd->itd_list, &stream->td_list);
- + itd->stream = stream;
- + itd->urb = urb;
- + itd_init(fotg210, stream, itd);
- + }
- +
- + uframe = next_uframe & 0x07;
- + frame = next_uframe >> 3;
- +
- + itd_patch(fotg210, itd, iso_sched, packet, uframe);
- +
- + next_uframe += stream->interval;
- + next_uframe &= mod - 1;
- + packet++;
- +
- + /* link completed itds into the schedule */
- + if (((next_uframe >> 3) != frame)
- + || packet == urb->number_of_packets) {
- + itd_link(fotg210, frame & (fotg210->periodic_size - 1),
- + itd);
- + itd = NULL;
- + }
- + }
- + stream->next_uframe = next_uframe;
- +
- + /* don't need that schedule data any more */
- + iso_sched_free(stream, iso_sched);
- + urb->hcpriv = NULL;
- +
- + ++fotg210->isoc_count;
- + enable_periodic(fotg210);
- +}
- +
- +#define ISO_ERRS (FOTG210_ISOC_BUF_ERR | FOTG210_ISOC_BABBLE |\
- + FOTG210_ISOC_XACTERR)
- +
- +/* Process and recycle a completed ITD. Return true iff its urb completed,
- + * and hence its completion callback probably added things to the hardware
- + * schedule.
- + *
- + * Note that we carefully avoid recycling this descriptor until after any
- + * completion callback runs, so that it won't be reused quickly. That is,
- + * assuming (a) no more than two urbs per frame on this endpoint, and also
- + * (b) only this endpoint's completions submit URBs. It seems some silicon
- + * corrupts things if you reuse completed descriptors very quickly...
- + */
- +static bool itd_complete(struct fotg210_hcd *fotg210, struct fotg210_itd *itd)
- +{
- + struct urb *urb = itd->urb;
- + struct usb_iso_packet_descriptor *desc;
- + u32 t;
- + unsigned uframe;
- + int urb_index = -1;
- + struct fotg210_iso_stream *stream = itd->stream;
- + struct usb_device *dev;
- + bool retval = false;
- +
- + /* for each uframe with a packet */
- + for (uframe = 0; uframe < 8; uframe++) {
- + if (likely(itd->index[uframe] == -1))
- + continue;
- + urb_index = itd->index[uframe];
- + desc = &urb->iso_frame_desc[urb_index];
- +
- + t = hc32_to_cpup(fotg210, &itd->hw_transaction[uframe]);
- + itd->hw_transaction[uframe] = 0;
- +
- + /* report transfer status */
- + if (unlikely(t & ISO_ERRS)) {
- + urb->error_count++;
- + if (t & FOTG210_ISOC_BUF_ERR)
- + desc->status = usb_pipein(urb->pipe)
- + ? -ENOSR /* hc couldn't read */
- + : -ECOMM; /* hc couldn't write */
- + else if (t & FOTG210_ISOC_BABBLE)
- + desc->status = -EOVERFLOW;
- + else /* (t & FOTG210_ISOC_XACTERR) */
- + desc->status = -EPROTO;
- +
- + /* HC need not update length with this error */
- + if (!(t & FOTG210_ISOC_BABBLE)) {
- + desc->actual_length = FOTG210_ITD_LENGTH(t);
- + urb->actual_length += desc->actual_length;
- + }
- + } else if (likely((t & FOTG210_ISOC_ACTIVE) == 0)) {
- + desc->status = 0;
- + desc->actual_length = FOTG210_ITD_LENGTH(t);
- + urb->actual_length += desc->actual_length;
- + } else {
- + /* URB was too late */
- + desc->status = -EXDEV;
- + }
- + }
- +
- + /* handle completion now? */
- + if (likely((urb_index + 1) != urb->number_of_packets))
- + goto done;
- +
- + /* ASSERT: it's really the last itd for this urb
- + * list_for_each_entry (itd, &stream->td_list, itd_list)
- + * BUG_ON (itd->urb == urb);
- + */
- +
- + /* give urb back to the driver; completion often (re)submits */
- + dev = urb->dev;
- + fotg210_urb_done(fotg210, urb, 0);
- + retval = true;
- + urb = NULL;
- +
- + --fotg210->isoc_count;
- + disable_periodic(fotg210);
- +
- + if (unlikely(list_is_singular(&stream->td_list))) {
- + fotg210_to_hcd(fotg210)->self.bandwidth_allocated
- + -= stream->bandwidth;
- + fotg210_dbg(fotg210,
- + "deschedule devp %s ep%d%s-iso\n",
- + dev->devpath, stream->bEndpointAddress & 0x0f,
- + (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
- + }
- +
- +done:
- + itd->urb = NULL;
- +
- + /* Add to the end of the free list for later reuse */
- + list_move_tail(&itd->itd_list, &stream->free_list);
- +
- + /* Recycle the iTDs when the pipeline is empty (ep no longer in use) */
- + if (list_empty(&stream->td_list)) {
- + list_splice_tail_init(&stream->free_list,
- + &fotg210->cached_itd_list);
- + start_free_itds(fotg210);
- + }
- +
- + return retval;
- +}
- +
- +static int itd_submit(struct fotg210_hcd *fotg210, struct urb *urb,
- + gfp_t mem_flags)
- +{
- + int status = -EINVAL;
- + unsigned long flags;
- + struct fotg210_iso_stream *stream;
- +
- + /* Get iso_stream head */
- + stream = iso_stream_find(fotg210, urb);
- + if (unlikely(stream == NULL)) {
- + fotg210_dbg(fotg210, "can't get iso stream\n");
- + return -ENOMEM;
- + }
- + if (unlikely(urb->interval != stream->interval &&
- + fotg210_port_speed(fotg210, 0) ==
- + USB_PORT_STAT_HIGH_SPEED)) {
- + fotg210_dbg(fotg210, "can't change iso interval %d --> %d\n",
- + stream->interval, urb->interval);
- + goto done;
- + }
- +
- +#ifdef FOTG210_URB_TRACE
- + fotg210_dbg(fotg210,
- + "%s %s urb %p ep%d%s len %d, %d pkts %d uframes[%p]\n",
- + __func__, urb->dev->devpath, urb,
- + usb_pipeendpoint(urb->pipe),
- + usb_pipein(urb->pipe) ? "in" : "out",
- + urb->transfer_buffer_length,
- + urb->number_of_packets, urb->interval,
- + stream);
- +#endif
- +
- + /* allocate ITDs w/o locking anything */
- + status = itd_urb_transaction(stream, fotg210, urb, mem_flags);
- + if (unlikely(status < 0)) {
- + fotg210_dbg(fotg210, "can't init itds\n");
- + goto done;
- + }
- +
- + /* schedule ... need to lock */
- + spin_lock_irqsave(&fotg210->lock, flags);
- + if (unlikely(!HCD_HW_ACCESSIBLE(fotg210_to_hcd(fotg210)))) {
- + status = -ESHUTDOWN;
- + goto done_not_linked;
- + }
- + status = usb_hcd_link_urb_to_ep(fotg210_to_hcd(fotg210), urb);
- + if (unlikely(status))
- + goto done_not_linked;
- + status = iso_stream_schedule(fotg210, urb, stream);
- + if (likely(status == 0))
- + itd_link_urb(fotg210, urb, fotg210->periodic_size << 3, stream);
- + else
- + usb_hcd_unlink_urb_from_ep(fotg210_to_hcd(fotg210), urb);
- +done_not_linked:
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- +done:
- + return status;
- +}
- +
- +static inline int scan_frame_queue(struct fotg210_hcd *fotg210, unsigned frame,
- + unsigned now_frame, bool live)
- +{
- + unsigned uf;
- + bool modified;
- + union fotg210_shadow q, *q_p;
- + __hc32 type, *hw_p;
- +
- + /* scan each element in frame's queue for completions */
- + q_p = &fotg210->pshadow[frame];
- + hw_p = &fotg210->periodic[frame];
- + q.ptr = q_p->ptr;
- + type = Q_NEXT_TYPE(fotg210, *hw_p);
- + modified = false;
- +
- + while (q.ptr) {
- + switch (hc32_to_cpu(fotg210, type)) {
- + case Q_TYPE_ITD:
- + /* If this ITD is still active, leave it for
- + * later processing ... check the next entry.
- + * No need to check for activity unless the
- + * frame is current.
- + */
- + if (frame == now_frame && live) {
- + rmb();
- + for (uf = 0; uf < 8; uf++) {
- + if (q.itd->hw_transaction[uf] &
- + ITD_ACTIVE(fotg210))
- + break;
- + }
- + if (uf < 8) {
- + q_p = &q.itd->itd_next;
- + hw_p = &q.itd->hw_next;
- + type = Q_NEXT_TYPE(fotg210,
- + q.itd->hw_next);
- + q = *q_p;
- + break;
- + }
- + }
- +
- + /* Take finished ITDs out of the schedule
- + * and process them: recycle, maybe report
- + * URB completion. HC won't cache the
- + * pointer for much longer, if at all.
- + */
- + *q_p = q.itd->itd_next;
- + *hw_p = q.itd->hw_next;
- + type = Q_NEXT_TYPE(fotg210, q.itd->hw_next);
- + wmb();
- + modified = itd_complete(fotg210, q.itd);
- + q = *q_p;
- + break;
- + default:
- + fotg210_dbg(fotg210, "corrupt type %d frame %d shadow %p\n",
- + type, frame, q.ptr);
- + fallthrough;
- + case Q_TYPE_QH:
- + case Q_TYPE_FSTN:
- + /* End of the iTDs and siTDs */
- + q.ptr = NULL;
- + break;
- + }
- +
- + /* assume completion callbacks modify the queue */
- + if (unlikely(modified && fotg210->isoc_count > 0))
- + return -EINVAL;
- + }
- + return 0;
- +}
- +
- +static void scan_isoc(struct fotg210_hcd *fotg210)
- +{
- + unsigned uf, now_frame, frame, ret;
- + unsigned fmask = fotg210->periodic_size - 1;
- + bool live;
- +
- + /*
- + * When running, scan from last scan point up to "now"
- + * else clean up by scanning everything that's left.
- + * Touches as few pages as possible: cache-friendly.
- + */
- + if (fotg210->rh_state >= FOTG210_RH_RUNNING) {
- + uf = fotg210_read_frame_index(fotg210);
- + now_frame = (uf >> 3) & fmask;
- + live = true;
- + } else {
- + now_frame = (fotg210->next_frame - 1) & fmask;
- + live = false;
- + }
- + fotg210->now_frame = now_frame;
- +
- + frame = fotg210->next_frame;
- + for (;;) {
- + ret = 1;
- + while (ret != 0)
- + ret = scan_frame_queue(fotg210, frame,
- + now_frame, live);
- +
- + /* Stop when we have reached the current frame */
- + if (frame == now_frame)
- + break;
- + frame = (frame + 1) & fmask;
- + }
- + fotg210->next_frame = now_frame;
- +}
- +
- +/* Display / Set uframe_periodic_max
- + */
- +static ssize_t uframe_periodic_max_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct fotg210_hcd *fotg210;
- + int n;
- +
- + fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
- + n = scnprintf(buf, PAGE_SIZE, "%d\n", fotg210->uframe_periodic_max);
- + return n;
- +}
- +
- +
- +static ssize_t uframe_periodic_max_store(struct device *dev,
- + struct device_attribute *attr, const char *buf, size_t count)
- +{
- + struct fotg210_hcd *fotg210;
- + unsigned uframe_periodic_max;
- + unsigned frame, uframe;
- + unsigned short allocated_max;
- + unsigned long flags;
- + ssize_t ret;
- +
- + fotg210 = hcd_to_fotg210(bus_to_hcd(dev_get_drvdata(dev)));
- + if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
- + return -EINVAL;
- +
- + if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
- + fotg210_info(fotg210, "rejecting invalid request for uframe_periodic_max=%u\n",
- + uframe_periodic_max);
- + return -EINVAL;
- + }
- +
- + ret = -EINVAL;
- +
- + /*
- + * lock, so that our checking does not race with possible periodic
- + * bandwidth allocation through submitting new urbs.
- + */
- + spin_lock_irqsave(&fotg210->lock, flags);
- +
- + /*
- + * for request to decrease max periodic bandwidth, we have to check
- + * every microframe in the schedule to see whether the decrease is
- + * possible.
- + */
- + if (uframe_periodic_max < fotg210->uframe_periodic_max) {
- + allocated_max = 0;
- +
- + for (frame = 0; frame < fotg210->periodic_size; ++frame)
- + for (uframe = 0; uframe < 7; ++uframe)
- + allocated_max = max(allocated_max,
- + periodic_usecs(fotg210, frame,
- + uframe));
- +
- + if (allocated_max > uframe_periodic_max) {
- + fotg210_info(fotg210,
- + "cannot decrease uframe_periodic_max because periodic bandwidth is already allocated (%u > %u)\n",
- + allocated_max, uframe_periodic_max);
- + goto out_unlock;
- + }
- + }
- +
- + /* increasing is always ok */
- +
- + fotg210_info(fotg210,
- + "setting max periodic bandwidth to %u%% (== %u usec/uframe)\n",
- + 100 * uframe_periodic_max/125, uframe_periodic_max);
- +
- + if (uframe_periodic_max != 100)
- + fotg210_warn(fotg210, "max periodic bandwidth set is non-standard\n");
- +
- + fotg210->uframe_periodic_max = uframe_periodic_max;
- + ret = count;
- +
- +out_unlock:
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + return ret;
- +}
- +
- +static DEVICE_ATTR_RW(uframe_periodic_max);
- +
- +static inline int create_sysfs_files(struct fotg210_hcd *fotg210)
- +{
- + struct device *controller = fotg210_to_hcd(fotg210)->self.controller;
- +
- + return device_create_file(controller, &dev_attr_uframe_periodic_max);
- +}
- +
- +static inline void remove_sysfs_files(struct fotg210_hcd *fotg210)
- +{
- + struct device *controller = fotg210_to_hcd(fotg210)->self.controller;
- +
- + device_remove_file(controller, &dev_attr_uframe_periodic_max);
- +}
- +/* On some systems, leaving remote wakeup enabled prevents system shutdown.
- + * The firmware seems to think that powering off is a wakeup event!
- + * This routine turns off remote wakeup and everything else, on all ports.
- + */
- +static void fotg210_turn_off_all_ports(struct fotg210_hcd *fotg210)
- +{
- + u32 __iomem *status_reg = &fotg210->regs->port_status;
- +
- + fotg210_writel(fotg210, PORT_RWC_BITS, status_reg);
- +}
- +
- +/* Halt HC, turn off all ports, and let the BIOS use the companion controllers.
- + * Must be called with interrupts enabled and the lock not held.
- + */
- +static void fotg210_silence_controller(struct fotg210_hcd *fotg210)
- +{
- + fotg210_halt(fotg210);
- +
- + spin_lock_irq(&fotg210->lock);
- + fotg210->rh_state = FOTG210_RH_HALTED;
- + fotg210_turn_off_all_ports(fotg210);
- + spin_unlock_irq(&fotg210->lock);
- +}
- +
- +/* fotg210_shutdown kick in for silicon on any bus (not just pci, etc).
- + * This forcibly disables dma and IRQs, helping kexec and other cases
- + * where the next system software may expect clean state.
- + */
- +static void fotg210_shutdown(struct usb_hcd *hcd)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- +
- + spin_lock_irq(&fotg210->lock);
- + fotg210->shutdown = true;
- + fotg210->rh_state = FOTG210_RH_STOPPING;
- + fotg210->enabled_hrtimer_events = 0;
- + spin_unlock_irq(&fotg210->lock);
- +
- + fotg210_silence_controller(fotg210);
- +
- + hrtimer_cancel(&fotg210->hrtimer);
- +}
- +
- +/* fotg210_work is called from some interrupts, timers, and so on.
- + * it calls driver completion functions, after dropping fotg210->lock.
- + */
- +static void fotg210_work(struct fotg210_hcd *fotg210)
- +{
- + /* another CPU may drop fotg210->lock during a schedule scan while
- + * it reports urb completions. this flag guards against bogus
- + * attempts at re-entrant schedule scanning.
- + */
- + if (fotg210->scanning) {
- + fotg210->need_rescan = true;
- + return;
- + }
- + fotg210->scanning = true;
- +
- +rescan:
- + fotg210->need_rescan = false;
- + if (fotg210->async_count)
- + scan_async(fotg210);
- + if (fotg210->intr_count > 0)
- + scan_intr(fotg210);
- + if (fotg210->isoc_count > 0)
- + scan_isoc(fotg210);
- + if (fotg210->need_rescan)
- + goto rescan;
- + fotg210->scanning = false;
- +
- + /* the IO watchdog guards against hardware or driver bugs that
- + * misplace IRQs, and should let us run completely without IRQs.
- + * such lossage has been observed on both VT6202 and VT8235.
- + */
- + turn_on_io_watchdog(fotg210);
- +}
- +
- +/* Called when the fotg210_hcd module is removed.
- + */
- +static void fotg210_stop(struct usb_hcd *hcd)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- +
- + fotg210_dbg(fotg210, "stop\n");
- +
- + /* no more interrupts ... */
- +
- + spin_lock_irq(&fotg210->lock);
- + fotg210->enabled_hrtimer_events = 0;
- + spin_unlock_irq(&fotg210->lock);
- +
- + fotg210_quiesce(fotg210);
- + fotg210_silence_controller(fotg210);
- + fotg210_reset(fotg210);
- +
- + hrtimer_cancel(&fotg210->hrtimer);
- + remove_sysfs_files(fotg210);
- + remove_debug_files(fotg210);
- +
- + /* root hub is shut down separately (first, when possible) */
- + spin_lock_irq(&fotg210->lock);
- + end_free_itds(fotg210);
- + spin_unlock_irq(&fotg210->lock);
- + fotg210_mem_cleanup(fotg210);
- +
- +#ifdef FOTG210_STATS
- + fotg210_dbg(fotg210, "irq normal %ld err %ld iaa %ld (lost %ld)\n",
- + fotg210->stats.normal, fotg210->stats.error,
- + fotg210->stats.iaa, fotg210->stats.lost_iaa);
- + fotg210_dbg(fotg210, "complete %ld unlink %ld\n",
- + fotg210->stats.complete, fotg210->stats.unlink);
- +#endif
- +
- + dbg_status(fotg210, "fotg210_stop completed",
- + fotg210_readl(fotg210, &fotg210->regs->status));
- +}
- +
- +/* one-time init, only for memory state */
- +static int hcd_fotg210_init(struct usb_hcd *hcd)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- + u32 temp;
- + int retval;
- + u32 hcc_params;
- + struct fotg210_qh_hw *hw;
- +
- + spin_lock_init(&fotg210->lock);
- +
- + /*
- + * keep io watchdog by default, those good HCDs could turn off it later
- + */
- + fotg210->need_io_watchdog = 1;
- +
- + hrtimer_init(&fotg210->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
- + fotg210->hrtimer.function = fotg210_hrtimer_func;
- + fotg210->next_hrtimer_event = FOTG210_HRTIMER_NO_EVENT;
- +
- + hcc_params = fotg210_readl(fotg210, &fotg210->caps->hcc_params);
- +
- + /*
- + * by default set standard 80% (== 100 usec/uframe) max periodic
- + * bandwidth as required by USB 2.0
- + */
- + fotg210->uframe_periodic_max = 100;
- +
- + /*
- + * hw default: 1K periodic list heads, one per frame.
- + * periodic_size can shrink by USBCMD update if hcc_params allows.
- + */
- + fotg210->periodic_size = DEFAULT_I_TDPS;
- + INIT_LIST_HEAD(&fotg210->intr_qh_list);
- + INIT_LIST_HEAD(&fotg210->cached_itd_list);
- +
- + if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
- + /* periodic schedule size can be smaller than default */
- + switch (FOTG210_TUNE_FLS) {
- + case 0:
- + fotg210->periodic_size = 1024;
- + break;
- + case 1:
- + fotg210->periodic_size = 512;
- + break;
- + case 2:
- + fotg210->periodic_size = 256;
- + break;
- + default:
- + BUG();
- + }
- + }
- + retval = fotg210_mem_init(fotg210, GFP_KERNEL);
- + if (retval < 0)
- + return retval;
- +
- + /* controllers may cache some of the periodic schedule ... */
- + fotg210->i_thresh = 2;
- +
- + /*
- + * dedicate a qh for the async ring head, since we couldn't unlink
- + * a 'real' qh without stopping the async schedule [4.8]. use it
- + * as the 'reclamation list head' too.
- + * its dummy is used in hw_alt_next of many tds, to prevent the qh
- + * from automatically advancing to the next td after short reads.
- + */
- + fotg210->async->qh_next.qh = NULL;
- + hw = fotg210->async->hw;
- + hw->hw_next = QH_NEXT(fotg210, fotg210->async->qh_dma);
- + hw->hw_info1 = cpu_to_hc32(fotg210, QH_HEAD);
- + hw->hw_token = cpu_to_hc32(fotg210, QTD_STS_HALT);
- + hw->hw_qtd_next = FOTG210_LIST_END(fotg210);
- + fotg210->async->qh_state = QH_STATE_LINKED;
- + hw->hw_alt_next = QTD_NEXT(fotg210, fotg210->async->dummy->qtd_dma);
- +
- + /* clear interrupt enables, set irq latency */
- + if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
- + log2_irq_thresh = 0;
- + temp = 1 << (16 + log2_irq_thresh);
- + if (HCC_CANPARK(hcc_params)) {
- + /* HW default park == 3, on hardware that supports it (like
- + * NVidia and ALI silicon), maximizes throughput on the async
- + * schedule by avoiding QH fetches between transfers.
- + *
- + * With fast usb storage devices and NForce2, "park" seems to
- + * make problems: throughput reduction (!), data errors...
- + */
- + if (park) {
- + park = min_t(unsigned, park, 3);
- + temp |= CMD_PARK;
- + temp |= park << 8;
- + }
- + fotg210_dbg(fotg210, "park %d\n", park);
- + }
- + if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
- + /* periodic schedule size can be smaller than default */
- + temp &= ~(3 << 2);
- + temp |= (FOTG210_TUNE_FLS << 2);
- + }
- + fotg210->command = temp;
- +
- + /* Accept arbitrarily long scatter-gather lists */
- + if (!hcd->localmem_pool)
- + hcd->self.sg_tablesize = ~0;
- + return 0;
- +}
- +
- +/* start HC running; it's halted, hcd_fotg210_init() has been run (once) */
- +static int fotg210_run(struct usb_hcd *hcd)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- + u32 temp;
- +
- + hcd->uses_new_polling = 1;
- +
- + /* EHCI spec section 4.1 */
- +
- + fotg210_writel(fotg210, fotg210->periodic_dma,
- + &fotg210->regs->frame_list);
- + fotg210_writel(fotg210, (u32)fotg210->async->qh_dma,
- + &fotg210->regs->async_next);
- +
- + /*
- + * hcc_params controls whether fotg210->regs->segment must (!!!)
- + * be used; it constrains QH/ITD/SITD and QTD locations.
- + * dma_pool consistent memory always uses segment zero.
- + * streaming mappings for I/O buffers, like dma_map_single(),
- + * can return segments above 4GB, if the device allows.
- + *
- + * NOTE: the dma mask is visible through dev->dma_mask, so
- + * drivers can pass this info along ... like NETIF_F_HIGHDMA,
- + * Scsi_Host.highmem_io, and so forth. It's readonly to all
- + * host side drivers though.
- + */
- + fotg210_readl(fotg210, &fotg210->caps->hcc_params);
- +
- + /*
- + * Philips, Intel, and maybe others need CMD_RUN before the
- + * root hub will detect new devices (why?); NEC doesn't
- + */
- + fotg210->command &= ~(CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
- + fotg210->command |= CMD_RUN;
- + fotg210_writel(fotg210, fotg210->command, &fotg210->regs->command);
- + dbg_cmd(fotg210, "init", fotg210->command);
- +
- + /*
- + * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
- + * are explicitly handed to companion controller(s), so no TT is
- + * involved with the root hub. (Except where one is integrated,
- + * and there's no companion controller unless maybe for USB OTG.)
- + *
- + * Turning on the CF flag will transfer ownership of all ports
- + * from the companions to the EHCI controller. If any of the
- + * companions are in the middle of a port reset at the time, it
- + * could cause trouble. Write-locking ehci_cf_port_reset_rwsem
- + * guarantees that no resets are in progress. After we set CF,
- + * a short delay lets the hardware catch up; new resets shouldn't
- + * be started before the port switching actions could complete.
- + */
- + down_write(&ehci_cf_port_reset_rwsem);
- + fotg210->rh_state = FOTG210_RH_RUNNING;
- + /* unblock posted writes */
- + fotg210_readl(fotg210, &fotg210->regs->command);
- + usleep_range(5000, 10000);
- + up_write(&ehci_cf_port_reset_rwsem);
- + fotg210->last_periodic_enable = ktime_get_real();
- +
- + temp = HC_VERSION(fotg210,
- + fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
- + fotg210_info(fotg210,
- + "USB %x.%x started, EHCI %x.%02x\n",
- + ((fotg210->sbrn & 0xf0) >> 4), (fotg210->sbrn & 0x0f),
- + temp >> 8, temp & 0xff);
- +
- + fotg210_writel(fotg210, INTR_MASK,
- + &fotg210->regs->intr_enable); /* Turn On Interrupts */
- +
- + /* GRR this is run-once init(), being done every time the HC starts.
- + * So long as they're part of class devices, we can't do it init()
- + * since the class device isn't created that early.
- + */
- + create_debug_files(fotg210);
- + create_sysfs_files(fotg210);
- +
- + return 0;
- +}
- +
- +static int fotg210_setup(struct usb_hcd *hcd)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- + int retval;
- +
- + fotg210->regs = (void __iomem *)fotg210->caps +
- + HC_LENGTH(fotg210,
- + fotg210_readl(fotg210, &fotg210->caps->hc_capbase));
- + dbg_hcs_params(fotg210, "reset");
- + dbg_hcc_params(fotg210, "reset");
- +
- + /* cache this readonly data; minimize chip reads */
- + fotg210->hcs_params = fotg210_readl(fotg210,
- + &fotg210->caps->hcs_params);
- +
- + fotg210->sbrn = HCD_USB2;
- +
- + /* data structure init */
- + retval = hcd_fotg210_init(hcd);
- + if (retval)
- + return retval;
- +
- + retval = fotg210_halt(fotg210);
- + if (retval)
- + return retval;
- +
- + fotg210_reset(fotg210);
- +
- + return 0;
- +}
- +
- +static irqreturn_t fotg210_irq(struct usb_hcd *hcd)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- + u32 status, masked_status, pcd_status = 0, cmd;
- + int bh;
- +
- + spin_lock(&fotg210->lock);
- +
- + status = fotg210_readl(fotg210, &fotg210->regs->status);
- +
- + /* e.g. cardbus physical eject */
- + if (status == ~(u32) 0) {
- + fotg210_dbg(fotg210, "device removed\n");
- + goto dead;
- + }
- +
- + /*
- + * We don't use STS_FLR, but some controllers don't like it to
- + * remain on, so mask it out along with the other status bits.
- + */
- + masked_status = status & (INTR_MASK | STS_FLR);
- +
- + /* Shared IRQ? */
- + if (!masked_status ||
- + unlikely(fotg210->rh_state == FOTG210_RH_HALTED)) {
- + spin_unlock(&fotg210->lock);
- + return IRQ_NONE;
- + }
- +
- + /* clear (just) interrupts */
- + fotg210_writel(fotg210, masked_status, &fotg210->regs->status);
- + cmd = fotg210_readl(fotg210, &fotg210->regs->command);
- + bh = 0;
- +
- + /* unrequested/ignored: Frame List Rollover */
- + dbg_status(fotg210, "irq", status);
- +
- + /* INT, ERR, and IAA interrupt rates can be throttled */
- +
- + /* normal [4.15.1.2] or error [4.15.1.1] completion */
- + if (likely((status & (STS_INT|STS_ERR)) != 0)) {
- + if (likely((status & STS_ERR) == 0))
- + INCR(fotg210->stats.normal);
- + else
- + INCR(fotg210->stats.error);
- + bh = 1;
- + }
- +
- + /* complete the unlinking of some qh [4.15.2.3] */
- + if (status & STS_IAA) {
- +
- + /* Turn off the IAA watchdog */
- + fotg210->enabled_hrtimer_events &=
- + ~BIT(FOTG210_HRTIMER_IAA_WATCHDOG);
- +
- + /*
- + * Mild optimization: Allow another IAAD to reset the
- + * hrtimer, if one occurs before the next expiration.
- + * In theory we could always cancel the hrtimer, but
- + * tests show that about half the time it will be reset
- + * for some other event anyway.
- + */
- + if (fotg210->next_hrtimer_event == FOTG210_HRTIMER_IAA_WATCHDOG)
- + ++fotg210->next_hrtimer_event;
- +
- + /* guard against (alleged) silicon errata */
- + if (cmd & CMD_IAAD)
- + fotg210_dbg(fotg210, "IAA with IAAD still set?\n");
- + if (fotg210->async_iaa) {
- + INCR(fotg210->stats.iaa);
- + end_unlink_async(fotg210);
- + } else
- + fotg210_dbg(fotg210, "IAA with nothing unlinked?\n");
- + }
- +
- + /* remote wakeup [4.3.1] */
- + if (status & STS_PCD) {
- + int pstatus;
- + u32 __iomem *status_reg = &fotg210->regs->port_status;
- +
- + /* kick root hub later */
- + pcd_status = status;
- +
- + /* resume root hub? */
- + if (fotg210->rh_state == FOTG210_RH_SUSPENDED)
- + usb_hcd_resume_root_hub(hcd);
- +
- + pstatus = fotg210_readl(fotg210, status_reg);
- +
- + if (test_bit(0, &fotg210->suspended_ports) &&
- + ((pstatus & PORT_RESUME) ||
- + !(pstatus & PORT_SUSPEND)) &&
- + (pstatus & PORT_PE) &&
- + fotg210->reset_done[0] == 0) {
- +
- + /* start 20 msec resume signaling from this port,
- + * and make hub_wq collect PORT_STAT_C_SUSPEND to
- + * stop that signaling. Use 5 ms extra for safety,
- + * like usb_port_resume() does.
- + */
- + fotg210->reset_done[0] = jiffies + msecs_to_jiffies(25);
- + set_bit(0, &fotg210->resuming_ports);
- + fotg210_dbg(fotg210, "port 1 remote wakeup\n");
- + mod_timer(&hcd->rh_timer, fotg210->reset_done[0]);
- + }
- + }
- +
- + /* PCI errors [4.15.2.4] */
- + if (unlikely((status & STS_FATAL) != 0)) {
- + fotg210_err(fotg210, "fatal error\n");
- + dbg_cmd(fotg210, "fatal", cmd);
- + dbg_status(fotg210, "fatal", status);
- +dead:
- + usb_hc_died(hcd);
- +
- + /* Don't let the controller do anything more */
- + fotg210->shutdown = true;
- + fotg210->rh_state = FOTG210_RH_STOPPING;
- + fotg210->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE);
- + fotg210_writel(fotg210, fotg210->command,
- + &fotg210->regs->command);
- + fotg210_writel(fotg210, 0, &fotg210->regs->intr_enable);
- + fotg210_handle_controller_death(fotg210);
- +
- + /* Handle completions when the controller stops */
- + bh = 0;
- + }
- +
- + if (bh)
- + fotg210_work(fotg210);
- + spin_unlock(&fotg210->lock);
- + if (pcd_status)
- + usb_hcd_poll_rh_status(hcd);
- + return IRQ_HANDLED;
- +}
- +
- +/* non-error returns are a promise to giveback() the urb later
- + * we drop ownership so next owner (or urb unlink) can get it
- + *
- + * urb + dev is in hcd.self.controller.urb_list
- + * we're queueing TDs onto software and hardware lists
- + *
- + * hcd-specific init for hcpriv hasn't been done yet
- + *
- + * NOTE: control, bulk, and interrupt share the same code to append TDs
- + * to a (possibly active) QH, and the same QH scanning code.
- + */
- +static int fotg210_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
- + gfp_t mem_flags)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- + struct list_head qtd_list;
- +
- + INIT_LIST_HEAD(&qtd_list);
- +
- + switch (usb_pipetype(urb->pipe)) {
- + case PIPE_CONTROL:
- + /* qh_completions() code doesn't handle all the fault cases
- + * in multi-TD control transfers. Even 1KB is rare anyway.
- + */
- + if (urb->transfer_buffer_length > (16 * 1024))
- + return -EMSGSIZE;
- + fallthrough;
- + /* case PIPE_BULK: */
- + default:
- + if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
- + return -ENOMEM;
- + return submit_async(fotg210, urb, &qtd_list, mem_flags);
- +
- + case PIPE_INTERRUPT:
- + if (!qh_urb_transaction(fotg210, urb, &qtd_list, mem_flags))
- + return -ENOMEM;
- + return intr_submit(fotg210, urb, &qtd_list, mem_flags);
- +
- + case PIPE_ISOCHRONOUS:
- + return itd_submit(fotg210, urb, mem_flags);
- + }
- +}
- +
- +/* remove from hardware lists
- + * completions normally happen asynchronously
- + */
- +
- +static int fotg210_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- + struct fotg210_qh *qh;
- + unsigned long flags;
- + int rc;
- +
- + spin_lock_irqsave(&fotg210->lock, flags);
- + rc = usb_hcd_check_unlink_urb(hcd, urb, status);
- + if (rc)
- + goto done;
- +
- + switch (usb_pipetype(urb->pipe)) {
- + /* case PIPE_CONTROL: */
- + /* case PIPE_BULK:*/
- + default:
- + qh = (struct fotg210_qh *) urb->hcpriv;
- + if (!qh)
- + break;
- + switch (qh->qh_state) {
- + case QH_STATE_LINKED:
- + case QH_STATE_COMPLETING:
- + start_unlink_async(fotg210, qh);
- + break;
- + case QH_STATE_UNLINK:
- + case QH_STATE_UNLINK_WAIT:
- + /* already started */
- + break;
- + case QH_STATE_IDLE:
- + /* QH might be waiting for a Clear-TT-Buffer */
- + qh_completions(fotg210, qh);
- + break;
- + }
- + break;
- +
- + case PIPE_INTERRUPT:
- + qh = (struct fotg210_qh *) urb->hcpriv;
- + if (!qh)
- + break;
- + switch (qh->qh_state) {
- + case QH_STATE_LINKED:
- + case QH_STATE_COMPLETING:
- + start_unlink_intr(fotg210, qh);
- + break;
- + case QH_STATE_IDLE:
- + qh_completions(fotg210, qh);
- + break;
- + default:
- + fotg210_dbg(fotg210, "bogus qh %p state %d\n",
- + qh, qh->qh_state);
- + goto done;
- + }
- + break;
- +
- + case PIPE_ISOCHRONOUS:
- + /* itd... */
- +
- + /* wait till next completion, do it then. */
- + /* completion irqs can wait up to 1024 msec, */
- + break;
- + }
- +done:
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + return rc;
- +}
- +
- +/* bulk qh holds the data toggle */
- +
- +static void fotg210_endpoint_disable(struct usb_hcd *hcd,
- + struct usb_host_endpoint *ep)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- + unsigned long flags;
- + struct fotg210_qh *qh, *tmp;
- +
- + /* ASSERT: any requests/urbs are being unlinked */
- + /* ASSERT: nobody can be submitting urbs for this any more */
- +
- +rescan:
- + spin_lock_irqsave(&fotg210->lock, flags);
- + qh = ep->hcpriv;
- + if (!qh)
- + goto done;
- +
- + /* endpoints can be iso streams. for now, we don't
- + * accelerate iso completions ... so spin a while.
- + */
- + if (qh->hw == NULL) {
- + struct fotg210_iso_stream *stream = ep->hcpriv;
- +
- + if (!list_empty(&stream->td_list))
- + goto idle_timeout;
- +
- + /* BUG_ON(!list_empty(&stream->free_list)); */
- + kfree(stream);
- + goto done;
- + }
- +
- + if (fotg210->rh_state < FOTG210_RH_RUNNING)
- + qh->qh_state = QH_STATE_IDLE;
- + switch (qh->qh_state) {
- + case QH_STATE_LINKED:
- + case QH_STATE_COMPLETING:
- + for (tmp = fotg210->async->qh_next.qh;
- + tmp && tmp != qh;
- + tmp = tmp->qh_next.qh)
- + continue;
- + /* periodic qh self-unlinks on empty, and a COMPLETING qh
- + * may already be unlinked.
- + */
- + if (tmp)
- + start_unlink_async(fotg210, qh);
- + fallthrough;
- + case QH_STATE_UNLINK: /* wait for hw to finish? */
- + case QH_STATE_UNLINK_WAIT:
- +idle_timeout:
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- + schedule_timeout_uninterruptible(1);
- + goto rescan;
- + case QH_STATE_IDLE: /* fully unlinked */
- + if (qh->clearing_tt)
- + goto idle_timeout;
- + if (list_empty(&qh->qtd_list)) {
- + qh_destroy(fotg210, qh);
- + break;
- + }
- + fallthrough;
- + default:
- + /* caller was supposed to have unlinked any requests;
- + * that's not our job. just leak this memory.
- + */
- + fotg210_err(fotg210, "qh %p (#%02x) state %d%s\n",
- + qh, ep->desc.bEndpointAddress, qh->qh_state,
- + list_empty(&qh->qtd_list) ? "" : "(has tds)");
- + break;
- + }
- +done:
- + ep->hcpriv = NULL;
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- +}
- +
- +static void fotg210_endpoint_reset(struct usb_hcd *hcd,
- + struct usb_host_endpoint *ep)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- + struct fotg210_qh *qh;
- + int eptype = usb_endpoint_type(&ep->desc);
- + int epnum = usb_endpoint_num(&ep->desc);
- + int is_out = usb_endpoint_dir_out(&ep->desc);
- + unsigned long flags;
- +
- + if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
- + return;
- +
- + spin_lock_irqsave(&fotg210->lock, flags);
- + qh = ep->hcpriv;
- +
- + /* For Bulk and Interrupt endpoints we maintain the toggle state
- + * in the hardware; the toggle bits in udev aren't used at all.
- + * When an endpoint is reset by usb_clear_halt() we must reset
- + * the toggle bit in the QH.
- + */
- + if (qh) {
- + usb_settoggle(qh->dev, epnum, is_out, 0);
- + if (!list_empty(&qh->qtd_list)) {
- + WARN_ONCE(1, "clear_halt for a busy endpoint\n");
- + } else if (qh->qh_state == QH_STATE_LINKED ||
- + qh->qh_state == QH_STATE_COMPLETING) {
- +
- + /* The toggle value in the QH can't be updated
- + * while the QH is active. Unlink it now;
- + * re-linking will call qh_refresh().
- + */
- + if (eptype == USB_ENDPOINT_XFER_BULK)
- + start_unlink_async(fotg210, qh);
- + else
- + start_unlink_intr(fotg210, qh);
- + }
- + }
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- +}
- +
- +static int fotg210_get_frame(struct usb_hcd *hcd)
- +{
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- +
- + return (fotg210_read_frame_index(fotg210) >> 3) %
- + fotg210->periodic_size;
- +}
- +
- +/* The EHCI in ChipIdea HDRC cannot be a separate module or device,
- + * because its registers (and irq) are shared between host/gadget/otg
- + * functions and in order to facilitate role switching we cannot
- + * give the fotg210 driver exclusive access to those.
- + */
- +MODULE_DESCRIPTION(DRIVER_DESC);
- +MODULE_AUTHOR(DRIVER_AUTHOR);
- +MODULE_LICENSE("GPL");
- +
- +static const struct hc_driver fotg210_fotg210_hc_driver = {
- + .description = hcd_name,
- + .product_desc = "Faraday USB2.0 Host Controller",
- + .hcd_priv_size = sizeof(struct fotg210_hcd),
- +
- + /*
- + * generic hardware linkage
- + */
- + .irq = fotg210_irq,
- + .flags = HCD_MEMORY | HCD_DMA | HCD_USB2,
- +
- + /*
- + * basic lifecycle operations
- + */
- + .reset = hcd_fotg210_init,
- + .start = fotg210_run,
- + .stop = fotg210_stop,
- + .shutdown = fotg210_shutdown,
- +
- + /*
- + * managing i/o requests and associated device resources
- + */
- + .urb_enqueue = fotg210_urb_enqueue,
- + .urb_dequeue = fotg210_urb_dequeue,
- + .endpoint_disable = fotg210_endpoint_disable,
- + .endpoint_reset = fotg210_endpoint_reset,
- +
- + /*
- + * scheduling support
- + */
- + .get_frame_number = fotg210_get_frame,
- +
- + /*
- + * root hub support
- + */
- + .hub_status_data = fotg210_hub_status_data,
- + .hub_control = fotg210_hub_control,
- + .bus_suspend = fotg210_bus_suspend,
- + .bus_resume = fotg210_bus_resume,
- +
- + .relinquish_port = fotg210_relinquish_port,
- + .port_handed_over = fotg210_port_handed_over,
- +
- + .clear_tt_buffer_complete = fotg210_clear_tt_buffer_complete,
- +};
- +
- +static void fotg210_init(struct fotg210_hcd *fotg210)
- +{
- + u32 value;
- +
- + iowrite32(GMIR_MDEV_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY,
- + &fotg210->regs->gmir);
- +
- + value = ioread32(&fotg210->regs->otgcsr);
- + value &= ~OTGCSR_A_BUS_DROP;
- + value |= OTGCSR_A_BUS_REQ;
- + iowrite32(value, &fotg210->regs->otgcsr);
- +}
- +
- +/*
- + * fotg210_hcd_probe - initialize faraday FOTG210 HCDs
- + *
- + * Allocates basic resources for this USB host controller, and
- + * then invokes the start() method for the HCD associated with it
- + * through the hotplug entry's driver_data.
- + */
- +static int fotg210_hcd_probe(struct platform_device *pdev)
- +{
- + struct device *dev = &pdev->dev;
- + struct usb_hcd *hcd;
- + struct resource *res;
- + int irq;
- + int retval;
- + struct fotg210_hcd *fotg210;
- +
- + if (usb_disabled())
- + return -ENODEV;
- +
- + pdev->dev.power.power_state = PMSG_ON;
- +
- + irq = platform_get_irq(pdev, 0);
- + if (irq < 0)
- + return irq;
- +
- + hcd = usb_create_hcd(&fotg210_fotg210_hc_driver, dev,
- + dev_name(dev));
- + if (!hcd) {
- + dev_err(dev, "failed to create hcd\n");
- + retval = -ENOMEM;
- + goto fail_create_hcd;
- + }
- +
- + hcd->has_tt = 1;
- +
- + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- + hcd->regs = devm_ioremap_resource(&pdev->dev, res);
- + if (IS_ERR(hcd->regs)) {
- + retval = PTR_ERR(hcd->regs);
- + goto failed_put_hcd;
- + }
- +
- + hcd->rsrc_start = res->start;
- + hcd->rsrc_len = resource_size(res);
- +
- + fotg210 = hcd_to_fotg210(hcd);
- +
- + fotg210->caps = hcd->regs;
- +
- + /* It's OK not to supply this clock */
- + fotg210->pclk = clk_get(dev, "PCLK");
- + if (!IS_ERR(fotg210->pclk)) {
- + retval = clk_prepare_enable(fotg210->pclk);
- + if (retval) {
- + dev_err(dev, "failed to enable PCLK\n");
- + goto failed_put_hcd;
- + }
- + } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) {
- + /*
- + * Percolate deferrals, for anything else,
- + * just live without the clocking.
- + */
- + retval = PTR_ERR(fotg210->pclk);
- + goto failed_dis_clk;
- + }
- +
- + retval = fotg210_setup(hcd);
- + if (retval)
- + goto failed_dis_clk;
- +
- + fotg210_init(fotg210);
- +
- + retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
- + if (retval) {
- + dev_err(dev, "failed to add hcd with err %d\n", retval);
- + goto failed_dis_clk;
- + }
- + device_wakeup_enable(hcd->self.controller);
- + platform_set_drvdata(pdev, hcd);
- +
- + return retval;
- +
- +failed_dis_clk:
- + if (!IS_ERR(fotg210->pclk)) {
- + clk_disable_unprepare(fotg210->pclk);
- + clk_put(fotg210->pclk);
- + }
- +failed_put_hcd:
- + usb_put_hcd(hcd);
- +fail_create_hcd:
- + dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval);
- + return retval;
- +}
- +
- +/*
- + * fotg210_hcd_remove - shutdown processing for EHCI HCDs
- + * @dev: USB Host Controller being removed
- + *
- + */
- +static int fotg210_hcd_remove(struct platform_device *pdev)
- +{
- + struct usb_hcd *hcd = platform_get_drvdata(pdev);
- + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
- +
- + if (!IS_ERR(fotg210->pclk)) {
- + clk_disable_unprepare(fotg210->pclk);
- + clk_put(fotg210->pclk);
- + }
- +
- + usb_remove_hcd(hcd);
- + usb_put_hcd(hcd);
- +
- + return 0;
- +}
- +
- +#ifdef CONFIG_OF
- +static const struct of_device_id fotg210_of_match[] = {
- + { .compatible = "faraday,fotg210" },
- + {},
- +};
- +MODULE_DEVICE_TABLE(of, fotg210_of_match);
- +#endif
- +
- +static struct platform_driver fotg210_hcd_driver = {
- + .driver = {
- + .name = "fotg210-hcd",
- + .of_match_table = of_match_ptr(fotg210_of_match),
- + },
- + .probe = fotg210_hcd_probe,
- + .remove = fotg210_hcd_remove,
- +};
- +
- +static int __init fotg210_hcd_init(void)
- +{
- + int retval = 0;
- +
- + if (usb_disabled())
- + return -ENODEV;
- +
- + set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
- + if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
- + test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
- + pr_warn("Warning! fotg210_hcd should always be loaded before uhci_hcd and ohci_hcd, not after\n");
- +
- + pr_debug("%s: block sizes: qh %zd qtd %zd itd %zd\n",
- + hcd_name, sizeof(struct fotg210_qh),
- + sizeof(struct fotg210_qtd),
- + sizeof(struct fotg210_itd));
- +
- + fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root);
- +
- + retval = platform_driver_register(&fotg210_hcd_driver);
- + if (retval < 0)
- + goto clean;
- + return retval;
- +
- +clean:
- + debugfs_remove(fotg210_debug_root);
- + fotg210_debug_root = NULL;
- +
- + clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
- + return retval;
- +}
- +module_init(fotg210_hcd_init);
- +
- +static void __exit fotg210_hcd_cleanup(void)
- +{
- + platform_driver_unregister(&fotg210_hcd_driver);
- + debugfs_remove(fotg210_debug_root);
- + clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
- +}
- +module_exit(fotg210_hcd_cleanup);
- --- a/drivers/usb/gadget/udc/fotg210-udc.c
- +++ /dev/null
- @@ -1,1239 +0,0 @@
- -// SPDX-License-Identifier: GPL-2.0
- -/*
- - * FOTG210 UDC Driver supports Bulk transfer so far
- - *
- - * Copyright (C) 2013 Faraday Technology Corporation
- - *
- - * Author : Yuan-Hsin Chen <[email protected]>
- - */
- -
- -#include <linux/dma-mapping.h>
- -#include <linux/err.h>
- -#include <linux/interrupt.h>
- -#include <linux/io.h>
- -#include <linux/module.h>
- -#include <linux/platform_device.h>
- -#include <linux/usb/ch9.h>
- -#include <linux/usb/gadget.h>
- -
- -#include "fotg210.h"
- -
- -#define DRIVER_DESC "FOTG210 USB Device Controller Driver"
- -#define DRIVER_VERSION "30-April-2013"
- -
- -static const char udc_name[] = "fotg210_udc";
- -static const char * const fotg210_ep_name[] = {
- - "ep0", "ep1", "ep2", "ep3", "ep4"};
- -
- -static void fotg210_disable_fifo_int(struct fotg210_ep *ep)
- -{
- - u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR1);
- -
- - if (ep->dir_in)
- - value |= DMISGR1_MF_IN_INT(ep->epnum - 1);
- - else
- - value |= DMISGR1_MF_OUTSPK_INT(ep->epnum - 1);
- - iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR1);
- -}
- -
- -static void fotg210_enable_fifo_int(struct fotg210_ep *ep)
- -{
- - u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR1);
- -
- - if (ep->dir_in)
- - value &= ~DMISGR1_MF_IN_INT(ep->epnum - 1);
- - else
- - value &= ~DMISGR1_MF_OUTSPK_INT(ep->epnum - 1);
- - iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR1);
- -}
- -
- -static void fotg210_set_cxdone(struct fotg210_udc *fotg210)
- -{
- - u32 value = ioread32(fotg210->reg + FOTG210_DCFESR);
- -
- - value |= DCFESR_CX_DONE;
- - iowrite32(value, fotg210->reg + FOTG210_DCFESR);
- -}
- -
- -static void fotg210_done(struct fotg210_ep *ep, struct fotg210_request *req,
- - int status)
- -{
- - list_del_init(&req->queue);
- -
- - /* don't modify queue heads during completion callback */
- - if (ep->fotg210->gadget.speed == USB_SPEED_UNKNOWN)
- - req->req.status = -ESHUTDOWN;
- - else
- - req->req.status = status;
- -
- - spin_unlock(&ep->fotg210->lock);
- - usb_gadget_giveback_request(&ep->ep, &req->req);
- - spin_lock(&ep->fotg210->lock);
- -
- - if (ep->epnum) {
- - if (list_empty(&ep->queue))
- - fotg210_disable_fifo_int(ep);
- - } else {
- - fotg210_set_cxdone(ep->fotg210);
- - }
- -}
- -
- -static void fotg210_fifo_ep_mapping(struct fotg210_ep *ep, u32 epnum,
- - u32 dir_in)
- -{
- - struct fotg210_udc *fotg210 = ep->fotg210;
- - u32 val;
- -
- - /* Driver should map an ep to a fifo and then map the fifo
- - * to the ep. What a brain-damaged design!
- - */
- -
- - /* map a fifo to an ep */
- - val = ioread32(fotg210->reg + FOTG210_EPMAP);
- - val &= ~EPMAP_FIFONOMSK(epnum, dir_in);
- - val |= EPMAP_FIFONO(epnum, dir_in);
- - iowrite32(val, fotg210->reg + FOTG210_EPMAP);
- -
- - /* map the ep to the fifo */
- - val = ioread32(fotg210->reg + FOTG210_FIFOMAP);
- - val &= ~FIFOMAP_EPNOMSK(epnum);
- - val |= FIFOMAP_EPNO(epnum);
- - iowrite32(val, fotg210->reg + FOTG210_FIFOMAP);
- -
- - /* enable fifo */
- - val = ioread32(fotg210->reg + FOTG210_FIFOCF);
- - val |= FIFOCF_FIFO_EN(epnum - 1);
- - iowrite32(val, fotg210->reg + FOTG210_FIFOCF);
- -}
- -
- -static void fotg210_set_fifo_dir(struct fotg210_ep *ep, u32 epnum, u32 dir_in)
- -{
- - struct fotg210_udc *fotg210 = ep->fotg210;
- - u32 val;
- -
- - val = ioread32(fotg210->reg + FOTG210_FIFOMAP);
- - val |= (dir_in ? FIFOMAP_DIRIN(epnum - 1) : FIFOMAP_DIROUT(epnum - 1));
- - iowrite32(val, fotg210->reg + FOTG210_FIFOMAP);
- -}
- -
- -static void fotg210_set_tfrtype(struct fotg210_ep *ep, u32 epnum, u32 type)
- -{
- - struct fotg210_udc *fotg210 = ep->fotg210;
- - u32 val;
- -
- - val = ioread32(fotg210->reg + FOTG210_FIFOCF);
- - val |= FIFOCF_TYPE(type, epnum - 1);
- - iowrite32(val, fotg210->reg + FOTG210_FIFOCF);
- -}
- -
- -static void fotg210_set_mps(struct fotg210_ep *ep, u32 epnum, u32 mps,
- - u32 dir_in)
- -{
- - struct fotg210_udc *fotg210 = ep->fotg210;
- - u32 val;
- - u32 offset = dir_in ? FOTG210_INEPMPSR(epnum) :
- - FOTG210_OUTEPMPSR(epnum);
- -
- - val = ioread32(fotg210->reg + offset);
- - val |= INOUTEPMPSR_MPS(mps);
- - iowrite32(val, fotg210->reg + offset);
- -}
- -
- -static int fotg210_config_ep(struct fotg210_ep *ep,
- - const struct usb_endpoint_descriptor *desc)
- -{
- - struct fotg210_udc *fotg210 = ep->fotg210;
- -
- - fotg210_set_fifo_dir(ep, ep->epnum, ep->dir_in);
- - fotg210_set_tfrtype(ep, ep->epnum, ep->type);
- - fotg210_set_mps(ep, ep->epnum, ep->ep.maxpacket, ep->dir_in);
- - fotg210_fifo_ep_mapping(ep, ep->epnum, ep->dir_in);
- -
- - fotg210->ep[ep->epnum] = ep;
- -
- - return 0;
- -}
- -
- -static int fotg210_ep_enable(struct usb_ep *_ep,
- - const struct usb_endpoint_descriptor *desc)
- -{
- - struct fotg210_ep *ep;
- -
- - ep = container_of(_ep, struct fotg210_ep, ep);
- -
- - ep->desc = desc;
- - ep->epnum = usb_endpoint_num(desc);
- - ep->type = usb_endpoint_type(desc);
- - ep->dir_in = usb_endpoint_dir_in(desc);
- - ep->ep.maxpacket = usb_endpoint_maxp(desc);
- -
- - return fotg210_config_ep(ep, desc);
- -}
- -
- -static void fotg210_reset_tseq(struct fotg210_udc *fotg210, u8 epnum)
- -{
- - struct fotg210_ep *ep = fotg210->ep[epnum];
- - u32 value;
- - void __iomem *reg;
- -
- - reg = (ep->dir_in) ?
- - fotg210->reg + FOTG210_INEPMPSR(epnum) :
- - fotg210->reg + FOTG210_OUTEPMPSR(epnum);
- -
- - /* Note: Driver needs to set and clear INOUTEPMPSR_RESET_TSEQ
- - * bit. Controller wouldn't clear this bit. WTF!!!
- - */
- -
- - value = ioread32(reg);
- - value |= INOUTEPMPSR_RESET_TSEQ;
- - iowrite32(value, reg);
- -
- - value = ioread32(reg);
- - value &= ~INOUTEPMPSR_RESET_TSEQ;
- - iowrite32(value, reg);
- -}
- -
- -static int fotg210_ep_release(struct fotg210_ep *ep)
- -{
- - if (!ep->epnum)
- - return 0;
- - ep->epnum = 0;
- - ep->stall = 0;
- - ep->wedged = 0;
- -
- - fotg210_reset_tseq(ep->fotg210, ep->epnum);
- -
- - return 0;
- -}
- -
- -static int fotg210_ep_disable(struct usb_ep *_ep)
- -{
- - struct fotg210_ep *ep;
- - struct fotg210_request *req;
- - unsigned long flags;
- -
- - BUG_ON(!_ep);
- -
- - ep = container_of(_ep, struct fotg210_ep, ep);
- -
- - while (!list_empty(&ep->queue)) {
- - req = list_entry(ep->queue.next,
- - struct fotg210_request, queue);
- - spin_lock_irqsave(&ep->fotg210->lock, flags);
- - fotg210_done(ep, req, -ECONNRESET);
- - spin_unlock_irqrestore(&ep->fotg210->lock, flags);
- - }
- -
- - return fotg210_ep_release(ep);
- -}
- -
- -static struct usb_request *fotg210_ep_alloc_request(struct usb_ep *_ep,
- - gfp_t gfp_flags)
- -{
- - struct fotg210_request *req;
- -
- - req = kzalloc(sizeof(struct fotg210_request), gfp_flags);
- - if (!req)
- - return NULL;
- -
- - INIT_LIST_HEAD(&req->queue);
- -
- - return &req->req;
- -}
- -
- -static void fotg210_ep_free_request(struct usb_ep *_ep,
- - struct usb_request *_req)
- -{
- - struct fotg210_request *req;
- -
- - req = container_of(_req, struct fotg210_request, req);
- - kfree(req);
- -}
- -
- -static void fotg210_enable_dma(struct fotg210_ep *ep,
- - dma_addr_t d, u32 len)
- -{
- - u32 value;
- - struct fotg210_udc *fotg210 = ep->fotg210;
- -
- - /* set transfer length and direction */
- - value = ioread32(fotg210->reg + FOTG210_DMACPSR1);
- - value &= ~(DMACPSR1_DMA_LEN(0xFFFF) | DMACPSR1_DMA_TYPE(1));
- - value |= DMACPSR1_DMA_LEN(len) | DMACPSR1_DMA_TYPE(ep->dir_in);
- - iowrite32(value, fotg210->reg + FOTG210_DMACPSR1);
- -
- - /* set device DMA target FIFO number */
- - value = ioread32(fotg210->reg + FOTG210_DMATFNR);
- - if (ep->epnum)
- - value |= DMATFNR_ACC_FN(ep->epnum - 1);
- - else
- - value |= DMATFNR_ACC_CXF;
- - iowrite32(value, fotg210->reg + FOTG210_DMATFNR);
- -
- - /* set DMA memory address */
- - iowrite32(d, fotg210->reg + FOTG210_DMACPSR2);
- -
- - /* enable MDMA_EROR and MDMA_CMPLT interrupt */
- - value = ioread32(fotg210->reg + FOTG210_DMISGR2);
- - value &= ~(DMISGR2_MDMA_CMPLT | DMISGR2_MDMA_ERROR);
- - iowrite32(value, fotg210->reg + FOTG210_DMISGR2);
- -
- - /* start DMA */
- - value = ioread32(fotg210->reg + FOTG210_DMACPSR1);
- - value |= DMACPSR1_DMA_START;
- - iowrite32(value, fotg210->reg + FOTG210_DMACPSR1);
- -}
- -
- -static void fotg210_disable_dma(struct fotg210_ep *ep)
- -{
- - iowrite32(DMATFNR_DISDMA, ep->fotg210->reg + FOTG210_DMATFNR);
- -}
- -
- -static void fotg210_wait_dma_done(struct fotg210_ep *ep)
- -{
- - u32 value;
- -
- - do {
- - value = ioread32(ep->fotg210->reg + FOTG210_DISGR2);
- - if ((value & DISGR2_USBRST_INT) ||
- - (value & DISGR2_DMA_ERROR))
- - goto dma_reset;
- - } while (!(value & DISGR2_DMA_CMPLT));
- -
- - value &= ~DISGR2_DMA_CMPLT;
- - iowrite32(value, ep->fotg210->reg + FOTG210_DISGR2);
- - return;
- -
- -dma_reset:
- - value = ioread32(ep->fotg210->reg + FOTG210_DMACPSR1);
- - value |= DMACPSR1_DMA_ABORT;
- - iowrite32(value, ep->fotg210->reg + FOTG210_DMACPSR1);
- -
- - /* reset fifo */
- - if (ep->epnum) {
- - value = ioread32(ep->fotg210->reg +
- - FOTG210_FIBCR(ep->epnum - 1));
- - value |= FIBCR_FFRST;
- - iowrite32(value, ep->fotg210->reg +
- - FOTG210_FIBCR(ep->epnum - 1));
- - } else {
- - value = ioread32(ep->fotg210->reg + FOTG210_DCFESR);
- - value |= DCFESR_CX_CLR;
- - iowrite32(value, ep->fotg210->reg + FOTG210_DCFESR);
- - }
- -}
- -
- -static void fotg210_start_dma(struct fotg210_ep *ep,
- - struct fotg210_request *req)
- -{
- - struct device *dev = &ep->fotg210->gadget.dev;
- - dma_addr_t d;
- - u8 *buffer;
- - u32 length;
- -
- - if (ep->epnum) {
- - if (ep->dir_in) {
- - buffer = req->req.buf;
- - length = req->req.length;
- - } else {
- - buffer = req->req.buf + req->req.actual;
- - length = ioread32(ep->fotg210->reg +
- - FOTG210_FIBCR(ep->epnum - 1)) & FIBCR_BCFX;
- - if (length > req->req.length - req->req.actual)
- - length = req->req.length - req->req.actual;
- - }
- - } else {
- - buffer = req->req.buf + req->req.actual;
- - if (req->req.length - req->req.actual > ep->ep.maxpacket)
- - length = ep->ep.maxpacket;
- - else
- - length = req->req.length - req->req.actual;
- - }
- -
- - d = dma_map_single(dev, buffer, length,
- - ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- -
- - if (dma_mapping_error(dev, d)) {
- - pr_err("dma_mapping_error\n");
- - return;
- - }
- -
- - fotg210_enable_dma(ep, d, length);
- -
- - /* check if dma is done */
- - fotg210_wait_dma_done(ep);
- -
- - fotg210_disable_dma(ep);
- -
- - /* update actual transfer length */
- - req->req.actual += length;
- -
- - dma_unmap_single(dev, d, length, DMA_TO_DEVICE);
- -}
- -
- -static void fotg210_ep0_queue(struct fotg210_ep *ep,
- - struct fotg210_request *req)
- -{
- - if (!req->req.length) {
- - fotg210_done(ep, req, 0);
- - return;
- - }
- - if (ep->dir_in) { /* if IN */
- - fotg210_start_dma(ep, req);
- - if (req->req.length == req->req.actual)
- - fotg210_done(ep, req, 0);
- - } else { /* OUT */
- - u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR0);
- -
- - value &= ~DMISGR0_MCX_OUT_INT;
- - iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR0);
- - }
- -}
- -
- -static int fotg210_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
- - gfp_t gfp_flags)
- -{
- - struct fotg210_ep *ep;
- - struct fotg210_request *req;
- - unsigned long flags;
- - int request = 0;
- -
- - ep = container_of(_ep, struct fotg210_ep, ep);
- - req = container_of(_req, struct fotg210_request, req);
- -
- - if (ep->fotg210->gadget.speed == USB_SPEED_UNKNOWN)
- - return -ESHUTDOWN;
- -
- - spin_lock_irqsave(&ep->fotg210->lock, flags);
- -
- - if (list_empty(&ep->queue))
- - request = 1;
- -
- - list_add_tail(&req->queue, &ep->queue);
- -
- - req->req.actual = 0;
- - req->req.status = -EINPROGRESS;
- -
- - if (!ep->epnum) /* ep0 */
- - fotg210_ep0_queue(ep, req);
- - else if (request && !ep->stall)
- - fotg210_enable_fifo_int(ep);
- -
- - spin_unlock_irqrestore(&ep->fotg210->lock, flags);
- -
- - return 0;
- -}
- -
- -static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
- -{
- - struct fotg210_ep *ep;
- - struct fotg210_request *req;
- - unsigned long flags;
- -
- - ep = container_of(_ep, struct fotg210_ep, ep);
- - req = container_of(_req, struct fotg210_request, req);
- -
- - spin_lock_irqsave(&ep->fotg210->lock, flags);
- - if (!list_empty(&ep->queue))
- - fotg210_done(ep, req, -ECONNRESET);
- - spin_unlock_irqrestore(&ep->fotg210->lock, flags);
- -
- - return 0;
- -}
- -
- -static void fotg210_set_epnstall(struct fotg210_ep *ep)
- -{
- - struct fotg210_udc *fotg210 = ep->fotg210;
- - u32 value;
- - void __iomem *reg;
- -
- - /* check if IN FIFO is empty before stall */
- - if (ep->dir_in) {
- - do {
- - value = ioread32(fotg210->reg + FOTG210_DCFESR);
- - } while (!(value & DCFESR_FIFO_EMPTY(ep->epnum - 1)));
- - }
- -
- - reg = (ep->dir_in) ?
- - fotg210->reg + FOTG210_INEPMPSR(ep->epnum) :
- - fotg210->reg + FOTG210_OUTEPMPSR(ep->epnum);
- - value = ioread32(reg);
- - value |= INOUTEPMPSR_STL_EP;
- - iowrite32(value, reg);
- -}
- -
- -static void fotg210_clear_epnstall(struct fotg210_ep *ep)
- -{
- - struct fotg210_udc *fotg210 = ep->fotg210;
- - u32 value;
- - void __iomem *reg;
- -
- - reg = (ep->dir_in) ?
- - fotg210->reg + FOTG210_INEPMPSR(ep->epnum) :
- - fotg210->reg + FOTG210_OUTEPMPSR(ep->epnum);
- - value = ioread32(reg);
- - value &= ~INOUTEPMPSR_STL_EP;
- - iowrite32(value, reg);
- -}
- -
- -static int fotg210_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge)
- -{
- - struct fotg210_ep *ep;
- - struct fotg210_udc *fotg210;
- - unsigned long flags;
- -
- - ep = container_of(_ep, struct fotg210_ep, ep);
- -
- - fotg210 = ep->fotg210;
- -
- - spin_lock_irqsave(&ep->fotg210->lock, flags);
- -
- - if (value) {
- - fotg210_set_epnstall(ep);
- - ep->stall = 1;
- - if (wedge)
- - ep->wedged = 1;
- - } else {
- - fotg210_reset_tseq(fotg210, ep->epnum);
- - fotg210_clear_epnstall(ep);
- - ep->stall = 0;
- - ep->wedged = 0;
- - if (!list_empty(&ep->queue))
- - fotg210_enable_fifo_int(ep);
- - }
- -
- - spin_unlock_irqrestore(&ep->fotg210->lock, flags);
- - return 0;
- -}
- -
- -static int fotg210_ep_set_halt(struct usb_ep *_ep, int value)
- -{
- - return fotg210_set_halt_and_wedge(_ep, value, 0);
- -}
- -
- -static int fotg210_ep_set_wedge(struct usb_ep *_ep)
- -{
- - return fotg210_set_halt_and_wedge(_ep, 1, 1);
- -}
- -
- -static void fotg210_ep_fifo_flush(struct usb_ep *_ep)
- -{
- -}
- -
- -static const struct usb_ep_ops fotg210_ep_ops = {
- - .enable = fotg210_ep_enable,
- - .disable = fotg210_ep_disable,
- -
- - .alloc_request = fotg210_ep_alloc_request,
- - .free_request = fotg210_ep_free_request,
- -
- - .queue = fotg210_ep_queue,
- - .dequeue = fotg210_ep_dequeue,
- -
- - .set_halt = fotg210_ep_set_halt,
- - .fifo_flush = fotg210_ep_fifo_flush,
- - .set_wedge = fotg210_ep_set_wedge,
- -};
- -
- -static void fotg210_clear_tx0byte(struct fotg210_udc *fotg210)
- -{
- - u32 value = ioread32(fotg210->reg + FOTG210_TX0BYTE);
- -
- - value &= ~(TX0BYTE_EP1 | TX0BYTE_EP2 | TX0BYTE_EP3
- - | TX0BYTE_EP4);
- - iowrite32(value, fotg210->reg + FOTG210_TX0BYTE);
- -}
- -
- -static void fotg210_clear_rx0byte(struct fotg210_udc *fotg210)
- -{
- - u32 value = ioread32(fotg210->reg + FOTG210_RX0BYTE);
- -
- - value &= ~(RX0BYTE_EP1 | RX0BYTE_EP2 | RX0BYTE_EP3
- - | RX0BYTE_EP4);
- - iowrite32(value, fotg210->reg + FOTG210_RX0BYTE);
- -}
- -
- -/* read 8-byte setup packet only */
- -static void fotg210_rdsetupp(struct fotg210_udc *fotg210,
- - u8 *buffer)
- -{
- - int i = 0;
- - u8 *tmp = buffer;
- - u32 data;
- - u32 length = 8;
- -
- - iowrite32(DMATFNR_ACC_CXF, fotg210->reg + FOTG210_DMATFNR);
- -
- - for (i = (length >> 2); i > 0; i--) {
- - data = ioread32(fotg210->reg + FOTG210_CXPORT);
- - *tmp = data & 0xFF;
- - *(tmp + 1) = (data >> 8) & 0xFF;
- - *(tmp + 2) = (data >> 16) & 0xFF;
- - *(tmp + 3) = (data >> 24) & 0xFF;
- - tmp = tmp + 4;
- - }
- -
- - switch (length % 4) {
- - case 1:
- - data = ioread32(fotg210->reg + FOTG210_CXPORT);
- - *tmp = data & 0xFF;
- - break;
- - case 2:
- - data = ioread32(fotg210->reg + FOTG210_CXPORT);
- - *tmp = data & 0xFF;
- - *(tmp + 1) = (data >> 8) & 0xFF;
- - break;
- - case 3:
- - data = ioread32(fotg210->reg + FOTG210_CXPORT);
- - *tmp = data & 0xFF;
- - *(tmp + 1) = (data >> 8) & 0xFF;
- - *(tmp + 2) = (data >> 16) & 0xFF;
- - break;
- - default:
- - break;
- - }
- -
- - iowrite32(DMATFNR_DISDMA, fotg210->reg + FOTG210_DMATFNR);
- -}
- -
- -static void fotg210_set_configuration(struct fotg210_udc *fotg210)
- -{
- - u32 value = ioread32(fotg210->reg + FOTG210_DAR);
- -
- - value |= DAR_AFT_CONF;
- - iowrite32(value, fotg210->reg + FOTG210_DAR);
- -}
- -
- -static void fotg210_set_dev_addr(struct fotg210_udc *fotg210, u32 addr)
- -{
- - u32 value = ioread32(fotg210->reg + FOTG210_DAR);
- -
- - value |= (addr & 0x7F);
- - iowrite32(value, fotg210->reg + FOTG210_DAR);
- -}
- -
- -static void fotg210_set_cxstall(struct fotg210_udc *fotg210)
- -{
- - u32 value = ioread32(fotg210->reg + FOTG210_DCFESR);
- -
- - value |= DCFESR_CX_STL;
- - iowrite32(value, fotg210->reg + FOTG210_DCFESR);
- -}
- -
- -static void fotg210_request_error(struct fotg210_udc *fotg210)
- -{
- - fotg210_set_cxstall(fotg210);
- - pr_err("request error!!\n");
- -}
- -
- -static void fotg210_set_address(struct fotg210_udc *fotg210,
- - struct usb_ctrlrequest *ctrl)
- -{
- - if (le16_to_cpu(ctrl->wValue) >= 0x0100) {
- - fotg210_request_error(fotg210);
- - } else {
- - fotg210_set_dev_addr(fotg210, le16_to_cpu(ctrl->wValue));
- - fotg210_set_cxdone(fotg210);
- - }
- -}
- -
- -static void fotg210_set_feature(struct fotg210_udc *fotg210,
- - struct usb_ctrlrequest *ctrl)
- -{
- - switch (ctrl->bRequestType & USB_RECIP_MASK) {
- - case USB_RECIP_DEVICE:
- - fotg210_set_cxdone(fotg210);
- - break;
- - case USB_RECIP_INTERFACE:
- - fotg210_set_cxdone(fotg210);
- - break;
- - case USB_RECIP_ENDPOINT: {
- - u8 epnum;
- - epnum = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK;
- - if (epnum)
- - fotg210_set_epnstall(fotg210->ep[epnum]);
- - else
- - fotg210_set_cxstall(fotg210);
- - fotg210_set_cxdone(fotg210);
- - }
- - break;
- - default:
- - fotg210_request_error(fotg210);
- - break;
- - }
- -}
- -
- -static void fotg210_clear_feature(struct fotg210_udc *fotg210,
- - struct usb_ctrlrequest *ctrl)
- -{
- - struct fotg210_ep *ep =
- - fotg210->ep[ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK];
- -
- - switch (ctrl->bRequestType & USB_RECIP_MASK) {
- - case USB_RECIP_DEVICE:
- - fotg210_set_cxdone(fotg210);
- - break;
- - case USB_RECIP_INTERFACE:
- - fotg210_set_cxdone(fotg210);
- - break;
- - case USB_RECIP_ENDPOINT:
- - if (ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK) {
- - if (ep->wedged) {
- - fotg210_set_cxdone(fotg210);
- - break;
- - }
- - if (ep->stall)
- - fotg210_set_halt_and_wedge(&ep->ep, 0, 0);
- - }
- - fotg210_set_cxdone(fotg210);
- - break;
- - default:
- - fotg210_request_error(fotg210);
- - break;
- - }
- -}
- -
- -static int fotg210_is_epnstall(struct fotg210_ep *ep)
- -{
- - struct fotg210_udc *fotg210 = ep->fotg210;
- - u32 value;
- - void __iomem *reg;
- -
- - reg = (ep->dir_in) ?
- - fotg210->reg + FOTG210_INEPMPSR(ep->epnum) :
- - fotg210->reg + FOTG210_OUTEPMPSR(ep->epnum);
- - value = ioread32(reg);
- - return value & INOUTEPMPSR_STL_EP ? 1 : 0;
- -}
- -
- -/* For EP0 requests triggered by this driver (currently GET_STATUS response) */
- -static void fotg210_ep0_complete(struct usb_ep *_ep, struct usb_request *req)
- -{
- - struct fotg210_ep *ep;
- - struct fotg210_udc *fotg210;
- -
- - ep = container_of(_ep, struct fotg210_ep, ep);
- - fotg210 = ep->fotg210;
- -
- - if (req->status || req->actual != req->length) {
- - dev_warn(&fotg210->gadget.dev, "EP0 request failed: %d\n", req->status);
- - }
- -}
- -
- -static void fotg210_get_status(struct fotg210_udc *fotg210,
- - struct usb_ctrlrequest *ctrl)
- -{
- - u8 epnum;
- -
- - switch (ctrl->bRequestType & USB_RECIP_MASK) {
- - case USB_RECIP_DEVICE:
- - fotg210->ep0_data = cpu_to_le16(1 << USB_DEVICE_SELF_POWERED);
- - break;
- - case USB_RECIP_INTERFACE:
- - fotg210->ep0_data = cpu_to_le16(0);
- - break;
- - case USB_RECIP_ENDPOINT:
- - epnum = ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK;
- - if (epnum)
- - fotg210->ep0_data =
- - cpu_to_le16(fotg210_is_epnstall(fotg210->ep[epnum])
- - << USB_ENDPOINT_HALT);
- - else
- - fotg210_request_error(fotg210);
- - break;
- -
- - default:
- - fotg210_request_error(fotg210);
- - return; /* exit */
- - }
- -
- - fotg210->ep0_req->buf = &fotg210->ep0_data;
- - fotg210->ep0_req->length = 2;
- -
- - spin_unlock(&fotg210->lock);
- - fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_ATOMIC);
- - spin_lock(&fotg210->lock);
- -}
- -
- -static int fotg210_setup_packet(struct fotg210_udc *fotg210,
- - struct usb_ctrlrequest *ctrl)
- -{
- - u8 *p = (u8 *)ctrl;
- - u8 ret = 0;
- -
- - fotg210_rdsetupp(fotg210, p);
- -
- - fotg210->ep[0]->dir_in = ctrl->bRequestType & USB_DIR_IN;
- -
- - if (fotg210->gadget.speed == USB_SPEED_UNKNOWN) {
- - u32 value = ioread32(fotg210->reg + FOTG210_DMCR);
- - fotg210->gadget.speed = value & DMCR_HS_EN ?
- - USB_SPEED_HIGH : USB_SPEED_FULL;
- - }
- -
- - /* check request */
- - if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
- - switch (ctrl->bRequest) {
- - case USB_REQ_GET_STATUS:
- - fotg210_get_status(fotg210, ctrl);
- - break;
- - case USB_REQ_CLEAR_FEATURE:
- - fotg210_clear_feature(fotg210, ctrl);
- - break;
- - case USB_REQ_SET_FEATURE:
- - fotg210_set_feature(fotg210, ctrl);
- - break;
- - case USB_REQ_SET_ADDRESS:
- - fotg210_set_address(fotg210, ctrl);
- - break;
- - case USB_REQ_SET_CONFIGURATION:
- - fotg210_set_configuration(fotg210);
- - ret = 1;
- - break;
- - default:
- - ret = 1;
- - break;
- - }
- - } else {
- - ret = 1;
- - }
- -
- - return ret;
- -}
- -
- -static void fotg210_ep0out(struct fotg210_udc *fotg210)
- -{
- - struct fotg210_ep *ep = fotg210->ep[0];
- -
- - if (!list_empty(&ep->queue) && !ep->dir_in) {
- - struct fotg210_request *req;
- -
- - req = list_first_entry(&ep->queue,
- - struct fotg210_request, queue);
- -
- - if (req->req.length)
- - fotg210_start_dma(ep, req);
- -
- - if ((req->req.length - req->req.actual) < ep->ep.maxpacket)
- - fotg210_done(ep, req, 0);
- - } else {
- - pr_err("%s : empty queue\n", __func__);
- - }
- -}
- -
- -static void fotg210_ep0in(struct fotg210_udc *fotg210)
- -{
- - struct fotg210_ep *ep = fotg210->ep[0];
- -
- - if ((!list_empty(&ep->queue)) && (ep->dir_in)) {
- - struct fotg210_request *req;
- -
- - req = list_entry(ep->queue.next,
- - struct fotg210_request, queue);
- -
- - if (req->req.length)
- - fotg210_start_dma(ep, req);
- -
- - if (req->req.actual == req->req.length)
- - fotg210_done(ep, req, 0);
- - } else {
- - fotg210_set_cxdone(fotg210);
- - }
- -}
- -
- -static void fotg210_clear_comabt_int(struct fotg210_udc *fotg210)
- -{
- - u32 value = ioread32(fotg210->reg + FOTG210_DISGR0);
- -
- - value &= ~DISGR0_CX_COMABT_INT;
- - iowrite32(value, fotg210->reg + FOTG210_DISGR0);
- -}
- -
- -static void fotg210_in_fifo_handler(struct fotg210_ep *ep)
- -{
- - struct fotg210_request *req = list_entry(ep->queue.next,
- - struct fotg210_request, queue);
- -
- - if (req->req.length)
- - fotg210_start_dma(ep, req);
- - fotg210_done(ep, req, 0);
- -}
- -
- -static void fotg210_out_fifo_handler(struct fotg210_ep *ep)
- -{
- - struct fotg210_request *req = list_entry(ep->queue.next,
- - struct fotg210_request, queue);
- - int disgr1 = ioread32(ep->fotg210->reg + FOTG210_DISGR1);
- -
- - fotg210_start_dma(ep, req);
- -
- - /* Complete the request when it's full or a short packet arrived.
- - * Like other drivers, short_not_ok isn't handled.
- - */
- -
- - if (req->req.length == req->req.actual ||
- - (disgr1 & DISGR1_SPK_INT(ep->epnum - 1)))
- - fotg210_done(ep, req, 0);
- -}
- -
- -static irqreturn_t fotg210_irq(int irq, void *_fotg210)
- -{
- - struct fotg210_udc *fotg210 = _fotg210;
- - u32 int_grp = ioread32(fotg210->reg + FOTG210_DIGR);
- - u32 int_msk = ioread32(fotg210->reg + FOTG210_DMIGR);
- -
- - int_grp &= ~int_msk;
- -
- - spin_lock(&fotg210->lock);
- -
- - if (int_grp & DIGR_INT_G2) {
- - void __iomem *reg = fotg210->reg + FOTG210_DISGR2;
- - u32 int_grp2 = ioread32(reg);
- - u32 int_msk2 = ioread32(fotg210->reg + FOTG210_DMISGR2);
- - u32 value;
- -
- - int_grp2 &= ~int_msk2;
- -
- - if (int_grp2 & DISGR2_USBRST_INT) {
- - usb_gadget_udc_reset(&fotg210->gadget,
- - fotg210->driver);
- - value = ioread32(reg);
- - value &= ~DISGR2_USBRST_INT;
- - iowrite32(value, reg);
- - pr_info("fotg210 udc reset\n");
- - }
- - if (int_grp2 & DISGR2_SUSP_INT) {
- - value = ioread32(reg);
- - value &= ~DISGR2_SUSP_INT;
- - iowrite32(value, reg);
- - pr_info("fotg210 udc suspend\n");
- - }
- - if (int_grp2 & DISGR2_RESM_INT) {
- - value = ioread32(reg);
- - value &= ~DISGR2_RESM_INT;
- - iowrite32(value, reg);
- - pr_info("fotg210 udc resume\n");
- - }
- - if (int_grp2 & DISGR2_ISO_SEQ_ERR_INT) {
- - value = ioread32(reg);
- - value &= ~DISGR2_ISO_SEQ_ERR_INT;
- - iowrite32(value, reg);
- - pr_info("fotg210 iso sequence error\n");
- - }
- - if (int_grp2 & DISGR2_ISO_SEQ_ABORT_INT) {
- - value = ioread32(reg);
- - value &= ~DISGR2_ISO_SEQ_ABORT_INT;
- - iowrite32(value, reg);
- - pr_info("fotg210 iso sequence abort\n");
- - }
- - if (int_grp2 & DISGR2_TX0BYTE_INT) {
- - fotg210_clear_tx0byte(fotg210);
- - value = ioread32(reg);
- - value &= ~DISGR2_TX0BYTE_INT;
- - iowrite32(value, reg);
- - pr_info("fotg210 transferred 0 byte\n");
- - }
- - if (int_grp2 & DISGR2_RX0BYTE_INT) {
- - fotg210_clear_rx0byte(fotg210);
- - value = ioread32(reg);
- - value &= ~DISGR2_RX0BYTE_INT;
- - iowrite32(value, reg);
- - pr_info("fotg210 received 0 byte\n");
- - }
- - if (int_grp2 & DISGR2_DMA_ERROR) {
- - value = ioread32(reg);
- - value &= ~DISGR2_DMA_ERROR;
- - iowrite32(value, reg);
- - }
- - }
- -
- - if (int_grp & DIGR_INT_G0) {
- - void __iomem *reg = fotg210->reg + FOTG210_DISGR0;
- - u32 int_grp0 = ioread32(reg);
- - u32 int_msk0 = ioread32(fotg210->reg + FOTG210_DMISGR0);
- - struct usb_ctrlrequest ctrl;
- -
- - int_grp0 &= ~int_msk0;
- -
- - /* the highest priority in this source register */
- - if (int_grp0 & DISGR0_CX_COMABT_INT) {
- - fotg210_clear_comabt_int(fotg210);
- - pr_info("fotg210 CX command abort\n");
- - }
- -
- - if (int_grp0 & DISGR0_CX_SETUP_INT) {
- - if (fotg210_setup_packet(fotg210, &ctrl)) {
- - spin_unlock(&fotg210->lock);
- - if (fotg210->driver->setup(&fotg210->gadget,
- - &ctrl) < 0)
- - fotg210_set_cxstall(fotg210);
- - spin_lock(&fotg210->lock);
- - }
- - }
- - if (int_grp0 & DISGR0_CX_COMEND_INT)
- - pr_info("fotg210 cmd end\n");
- -
- - if (int_grp0 & DISGR0_CX_IN_INT)
- - fotg210_ep0in(fotg210);
- -
- - if (int_grp0 & DISGR0_CX_OUT_INT)
- - fotg210_ep0out(fotg210);
- -
- - if (int_grp0 & DISGR0_CX_COMFAIL_INT) {
- - fotg210_set_cxstall(fotg210);
- - pr_info("fotg210 ep0 fail\n");
- - }
- - }
- -
- - if (int_grp & DIGR_INT_G1) {
- - void __iomem *reg = fotg210->reg + FOTG210_DISGR1;
- - u32 int_grp1 = ioread32(reg);
- - u32 int_msk1 = ioread32(fotg210->reg + FOTG210_DMISGR1);
- - int fifo;
- -
- - int_grp1 &= ~int_msk1;
- -
- - for (fifo = 0; fifo < FOTG210_MAX_FIFO_NUM; fifo++) {
- - if (int_grp1 & DISGR1_IN_INT(fifo))
- - fotg210_in_fifo_handler(fotg210->ep[fifo + 1]);
- -
- - if ((int_grp1 & DISGR1_OUT_INT(fifo)) ||
- - (int_grp1 & DISGR1_SPK_INT(fifo)))
- - fotg210_out_fifo_handler(fotg210->ep[fifo + 1]);
- - }
- - }
- -
- - spin_unlock(&fotg210->lock);
- -
- - return IRQ_HANDLED;
- -}
- -
- -static void fotg210_disable_unplug(struct fotg210_udc *fotg210)
- -{
- - u32 reg = ioread32(fotg210->reg + FOTG210_PHYTMSR);
- -
- - reg &= ~PHYTMSR_UNPLUG;
- - iowrite32(reg, fotg210->reg + FOTG210_PHYTMSR);
- -}
- -
- -static int fotg210_udc_start(struct usb_gadget *g,
- - struct usb_gadget_driver *driver)
- -{
- - struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
- - u32 value;
- -
- - /* hook up the driver */
- - fotg210->driver = driver;
- -
- - /* enable device global interrupt */
- - value = ioread32(fotg210->reg + FOTG210_DMCR);
- - value |= DMCR_GLINT_EN;
- - iowrite32(value, fotg210->reg + FOTG210_DMCR);
- -
- - return 0;
- -}
- -
- -static void fotg210_init(struct fotg210_udc *fotg210)
- -{
- - u32 value;
- -
- - /* disable global interrupt and set int polarity to active high */
- - iowrite32(GMIR_MHC_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY,
- - fotg210->reg + FOTG210_GMIR);
- -
- - /* disable device global interrupt */
- - value = ioread32(fotg210->reg + FOTG210_DMCR);
- - value &= ~DMCR_GLINT_EN;
- - iowrite32(value, fotg210->reg + FOTG210_DMCR);
- -
- - /* enable only grp2 irqs we handle */
- - iowrite32(~(DISGR2_DMA_ERROR | DISGR2_RX0BYTE_INT | DISGR2_TX0BYTE_INT
- - | DISGR2_ISO_SEQ_ABORT_INT | DISGR2_ISO_SEQ_ERR_INT
- - | DISGR2_RESM_INT | DISGR2_SUSP_INT | DISGR2_USBRST_INT),
- - fotg210->reg + FOTG210_DMISGR2);
- -
- - /* disable all fifo interrupt */
- - iowrite32(~(u32)0, fotg210->reg + FOTG210_DMISGR1);
- -
- - /* disable cmd end */
- - value = ioread32(fotg210->reg + FOTG210_DMISGR0);
- - value |= DMISGR0_MCX_COMEND;
- - iowrite32(value, fotg210->reg + FOTG210_DMISGR0);
- -}
- -
- -static int fotg210_udc_stop(struct usb_gadget *g)
- -{
- - struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
- - unsigned long flags;
- -
- - spin_lock_irqsave(&fotg210->lock, flags);
- -
- - fotg210_init(fotg210);
- - fotg210->driver = NULL;
- -
- - spin_unlock_irqrestore(&fotg210->lock, flags);
- -
- - return 0;
- -}
- -
- -static const struct usb_gadget_ops fotg210_gadget_ops = {
- - .udc_start = fotg210_udc_start,
- - .udc_stop = fotg210_udc_stop,
- -};
- -
- -static int fotg210_udc_remove(struct platform_device *pdev)
- -{
- - struct fotg210_udc *fotg210 = platform_get_drvdata(pdev);
- - int i;
- -
- - usb_del_gadget_udc(&fotg210->gadget);
- - iounmap(fotg210->reg);
- - free_irq(platform_get_irq(pdev, 0), fotg210);
- -
- - fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req);
- - for (i = 0; i < FOTG210_MAX_NUM_EP; i++)
- - kfree(fotg210->ep[i]);
- - kfree(fotg210);
- -
- - return 0;
- -}
- -
- -static int fotg210_udc_probe(struct platform_device *pdev)
- -{
- - struct resource *res, *ires;
- - struct fotg210_udc *fotg210 = NULL;
- - struct fotg210_ep *_ep[FOTG210_MAX_NUM_EP];
- - int ret = 0;
- - int i;
- -
- - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- - if (!res) {
- - pr_err("platform_get_resource error.\n");
- - return -ENODEV;
- - }
- -
- - ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- - if (!ires) {
- - pr_err("platform_get_resource IORESOURCE_IRQ error.\n");
- - return -ENODEV;
- - }
- -
- - ret = -ENOMEM;
- -
- - /* initialize udc */
- - fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL);
- - if (fotg210 == NULL)
- - goto err;
- -
- - for (i = 0; i < FOTG210_MAX_NUM_EP; i++) {
- - _ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL);
- - if (_ep[i] == NULL)
- - goto err_alloc;
- - fotg210->ep[i] = _ep[i];
- - }
- -
- - fotg210->reg = ioremap(res->start, resource_size(res));
- - if (fotg210->reg == NULL) {
- - pr_err("ioremap error.\n");
- - goto err_alloc;
- - }
- -
- - spin_lock_init(&fotg210->lock);
- -
- - platform_set_drvdata(pdev, fotg210);
- -
- - fotg210->gadget.ops = &fotg210_gadget_ops;
- -
- - fotg210->gadget.max_speed = USB_SPEED_HIGH;
- - fotg210->gadget.dev.parent = &pdev->dev;
- - fotg210->gadget.dev.dma_mask = pdev->dev.dma_mask;
- - fotg210->gadget.name = udc_name;
- -
- - INIT_LIST_HEAD(&fotg210->gadget.ep_list);
- -
- - for (i = 0; i < FOTG210_MAX_NUM_EP; i++) {
- - struct fotg210_ep *ep = fotg210->ep[i];
- -
- - if (i) {
- - INIT_LIST_HEAD(&fotg210->ep[i]->ep.ep_list);
- - list_add_tail(&fotg210->ep[i]->ep.ep_list,
- - &fotg210->gadget.ep_list);
- - }
- - ep->fotg210 = fotg210;
- - INIT_LIST_HEAD(&ep->queue);
- - ep->ep.name = fotg210_ep_name[i];
- - ep->ep.ops = &fotg210_ep_ops;
- - usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);
- -
- - if (i == 0) {
- - ep->ep.caps.type_control = true;
- - } else {
- - ep->ep.caps.type_iso = true;
- - ep->ep.caps.type_bulk = true;
- - ep->ep.caps.type_int = true;
- - }
- -
- - ep->ep.caps.dir_in = true;
- - ep->ep.caps.dir_out = true;
- - }
- - usb_ep_set_maxpacket_limit(&fotg210->ep[0]->ep, 0x40);
- - fotg210->gadget.ep0 = &fotg210->ep[0]->ep;
- - INIT_LIST_HEAD(&fotg210->gadget.ep0->ep_list);
- -
- - fotg210->ep0_req = fotg210_ep_alloc_request(&fotg210->ep[0]->ep,
- - GFP_KERNEL);
- - if (fotg210->ep0_req == NULL)
- - goto err_map;
- -
- - fotg210->ep0_req->complete = fotg210_ep0_complete;
- -
- - fotg210_init(fotg210);
- -
- - fotg210_disable_unplug(fotg210);
- -
- - ret = request_irq(ires->start, fotg210_irq, IRQF_SHARED,
- - udc_name, fotg210);
- - if (ret < 0) {
- - pr_err("request_irq error (%d)\n", ret);
- - goto err_req;
- - }
- -
- - ret = usb_add_gadget_udc(&pdev->dev, &fotg210->gadget);
- - if (ret)
- - goto err_add_udc;
- -
- - dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
- -
- - return 0;
- -
- -err_add_udc:
- - free_irq(ires->start, fotg210);
- -
- -err_req:
- - fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req);
- -
- -err_map:
- - iounmap(fotg210->reg);
- -
- -err_alloc:
- - for (i = 0; i < FOTG210_MAX_NUM_EP; i++)
- - kfree(fotg210->ep[i]);
- - kfree(fotg210);
- -
- -err:
- - return ret;
- -}
- -
- -static struct platform_driver fotg210_driver = {
- - .driver = {
- - .name = udc_name,
- - },
- - .probe = fotg210_udc_probe,
- - .remove = fotg210_udc_remove,
- -};
- -
- -module_platform_driver(fotg210_driver);
- -
- -MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <[email protected]>");
- -MODULE_LICENSE("GPL");
- -MODULE_DESCRIPTION(DRIVER_DESC);
- --- /dev/null
- +++ b/drivers/usb/fotg210/fotg210-udc.c
- @@ -0,0 +1,1239 @@
- +// SPDX-License-Identifier: GPL-2.0
- +/*
- + * FOTG210 UDC Driver supports Bulk transfer so far
- + *
- + * Copyright (C) 2013 Faraday Technology Corporation
- + *
- + * Author : Yuan-Hsin Chen <[email protected]>
- + */
- +
- +#include <linux/dma-mapping.h>
- +#include <linux/err.h>
- +#include <linux/interrupt.h>
- +#include <linux/io.h>
- +#include <linux/module.h>
- +#include <linux/platform_device.h>
- +#include <linux/usb/ch9.h>
- +#include <linux/usb/gadget.h>
- +
- +#include "fotg210-udc.h"
- +
- +#define DRIVER_DESC "FOTG210 USB Device Controller Driver"
- +#define DRIVER_VERSION "30-April-2013"
- +
- +static const char udc_name[] = "fotg210_udc";
- +static const char * const fotg210_ep_name[] = {
- + "ep0", "ep1", "ep2", "ep3", "ep4"};
- +
- +static void fotg210_disable_fifo_int(struct fotg210_ep *ep)
- +{
- + u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR1);
- +
- + if (ep->dir_in)
- + value |= DMISGR1_MF_IN_INT(ep->epnum - 1);
- + else
- + value |= DMISGR1_MF_OUTSPK_INT(ep->epnum - 1);
- + iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR1);
- +}
- +
- +static void fotg210_enable_fifo_int(struct fotg210_ep *ep)
- +{
- + u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR1);
- +
- + if (ep->dir_in)
- + value &= ~DMISGR1_MF_IN_INT(ep->epnum - 1);
- + else
- + value &= ~DMISGR1_MF_OUTSPK_INT(ep->epnum - 1);
- + iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR1);
- +}
- +
- +static void fotg210_set_cxdone(struct fotg210_udc *fotg210)
- +{
- + u32 value = ioread32(fotg210->reg + FOTG210_DCFESR);
- +
- + value |= DCFESR_CX_DONE;
- + iowrite32(value, fotg210->reg + FOTG210_DCFESR);
- +}
- +
- +static void fotg210_done(struct fotg210_ep *ep, struct fotg210_request *req,
- + int status)
- +{
- + list_del_init(&req->queue);
- +
- + /* don't modify queue heads during completion callback */
- + if (ep->fotg210->gadget.speed == USB_SPEED_UNKNOWN)
- + req->req.status = -ESHUTDOWN;
- + else
- + req->req.status = status;
- +
- + spin_unlock(&ep->fotg210->lock);
- + usb_gadget_giveback_request(&ep->ep, &req->req);
- + spin_lock(&ep->fotg210->lock);
- +
- + if (ep->epnum) {
- + if (list_empty(&ep->queue))
- + fotg210_disable_fifo_int(ep);
- + } else {
- + fotg210_set_cxdone(ep->fotg210);
- + }
- +}
- +
- +static void fotg210_fifo_ep_mapping(struct fotg210_ep *ep, u32 epnum,
- + u32 dir_in)
- +{
- + struct fotg210_udc *fotg210 = ep->fotg210;
- + u32 val;
- +
- + /* Driver should map an ep to a fifo and then map the fifo
- + * to the ep. What a brain-damaged design!
- + */
- +
- + /* map a fifo to an ep */
- + val = ioread32(fotg210->reg + FOTG210_EPMAP);
- + val &= ~EPMAP_FIFONOMSK(epnum, dir_in);
- + val |= EPMAP_FIFONO(epnum, dir_in);
- + iowrite32(val, fotg210->reg + FOTG210_EPMAP);
- +
- + /* map the ep to the fifo */
- + val = ioread32(fotg210->reg + FOTG210_FIFOMAP);
- + val &= ~FIFOMAP_EPNOMSK(epnum);
- + val |= FIFOMAP_EPNO(epnum);
- + iowrite32(val, fotg210->reg + FOTG210_FIFOMAP);
- +
- + /* enable fifo */
- + val = ioread32(fotg210->reg + FOTG210_FIFOCF);
- + val |= FIFOCF_FIFO_EN(epnum - 1);
- + iowrite32(val, fotg210->reg + FOTG210_FIFOCF);
- +}
- +
- +static void fotg210_set_fifo_dir(struct fotg210_ep *ep, u32 epnum, u32 dir_in)
- +{
- + struct fotg210_udc *fotg210 = ep->fotg210;
- + u32 val;
- +
- + val = ioread32(fotg210->reg + FOTG210_FIFOMAP);
- + val |= (dir_in ? FIFOMAP_DIRIN(epnum - 1) : FIFOMAP_DIROUT(epnum - 1));
- + iowrite32(val, fotg210->reg + FOTG210_FIFOMAP);
- +}
- +
- +static void fotg210_set_tfrtype(struct fotg210_ep *ep, u32 epnum, u32 type)
- +{
- + struct fotg210_udc *fotg210 = ep->fotg210;
- + u32 val;
- +
- + val = ioread32(fotg210->reg + FOTG210_FIFOCF);
- + val |= FIFOCF_TYPE(type, epnum - 1);
- + iowrite32(val, fotg210->reg + FOTG210_FIFOCF);
- +}
- +
- +static void fotg210_set_mps(struct fotg210_ep *ep, u32 epnum, u32 mps,
- + u32 dir_in)
- +{
- + struct fotg210_udc *fotg210 = ep->fotg210;
- + u32 val;
- + u32 offset = dir_in ? FOTG210_INEPMPSR(epnum) :
- + FOTG210_OUTEPMPSR(epnum);
- +
- + val = ioread32(fotg210->reg + offset);
- + val |= INOUTEPMPSR_MPS(mps);
- + iowrite32(val, fotg210->reg + offset);
- +}
- +
- +static int fotg210_config_ep(struct fotg210_ep *ep,
- + const struct usb_endpoint_descriptor *desc)
- +{
- + struct fotg210_udc *fotg210 = ep->fotg210;
- +
- + fotg210_set_fifo_dir(ep, ep->epnum, ep->dir_in);
- + fotg210_set_tfrtype(ep, ep->epnum, ep->type);
- + fotg210_set_mps(ep, ep->epnum, ep->ep.maxpacket, ep->dir_in);
- + fotg210_fifo_ep_mapping(ep, ep->epnum, ep->dir_in);
- +
- + fotg210->ep[ep->epnum] = ep;
- +
- + return 0;
- +}
- +
- +static int fotg210_ep_enable(struct usb_ep *_ep,
- + const struct usb_endpoint_descriptor *desc)
- +{
- + struct fotg210_ep *ep;
- +
- + ep = container_of(_ep, struct fotg210_ep, ep);
- +
- + ep->desc = desc;
- + ep->epnum = usb_endpoint_num(desc);
- + ep->type = usb_endpoint_type(desc);
- + ep->dir_in = usb_endpoint_dir_in(desc);
- + ep->ep.maxpacket = usb_endpoint_maxp(desc);
- +
- + return fotg210_config_ep(ep, desc);
- +}
- +
- +static void fotg210_reset_tseq(struct fotg210_udc *fotg210, u8 epnum)
- +{
- + struct fotg210_ep *ep = fotg210->ep[epnum];
- + u32 value;
- + void __iomem *reg;
- +
- + reg = (ep->dir_in) ?
- + fotg210->reg + FOTG210_INEPMPSR(epnum) :
- + fotg210->reg + FOTG210_OUTEPMPSR(epnum);
- +
- + /* Note: Driver needs to set and clear INOUTEPMPSR_RESET_TSEQ
- + * bit. Controller wouldn't clear this bit. WTF!!!
- + */
- +
- + value = ioread32(reg);
- + value |= INOUTEPMPSR_RESET_TSEQ;
- + iowrite32(value, reg);
- +
- + value = ioread32(reg);
- + value &= ~INOUTEPMPSR_RESET_TSEQ;
- + iowrite32(value, reg);
- +}
- +
- +static int fotg210_ep_release(struct fotg210_ep *ep)
- +{
- + if (!ep->epnum)
- + return 0;
- + ep->epnum = 0;
- + ep->stall = 0;
- + ep->wedged = 0;
- +
- + fotg210_reset_tseq(ep->fotg210, ep->epnum);
- +
- + return 0;
- +}
- +
- +static int fotg210_ep_disable(struct usb_ep *_ep)
- +{
- + struct fotg210_ep *ep;
- + struct fotg210_request *req;
- + unsigned long flags;
- +
- + BUG_ON(!_ep);
- +
- + ep = container_of(_ep, struct fotg210_ep, ep);
- +
- + while (!list_empty(&ep->queue)) {
- + req = list_entry(ep->queue.next,
- + struct fotg210_request, queue);
- + spin_lock_irqsave(&ep->fotg210->lock, flags);
- + fotg210_done(ep, req, -ECONNRESET);
- + spin_unlock_irqrestore(&ep->fotg210->lock, flags);
- + }
- +
- + return fotg210_ep_release(ep);
- +}
- +
- +static struct usb_request *fotg210_ep_alloc_request(struct usb_ep *_ep,
- + gfp_t gfp_flags)
- +{
- + struct fotg210_request *req;
- +
- + req = kzalloc(sizeof(struct fotg210_request), gfp_flags);
- + if (!req)
- + return NULL;
- +
- + INIT_LIST_HEAD(&req->queue);
- +
- + return &req->req;
- +}
- +
- +static void fotg210_ep_free_request(struct usb_ep *_ep,
- + struct usb_request *_req)
- +{
- + struct fotg210_request *req;
- +
- + req = container_of(_req, struct fotg210_request, req);
- + kfree(req);
- +}
- +
- +static void fotg210_enable_dma(struct fotg210_ep *ep,
- + dma_addr_t d, u32 len)
- +{
- + u32 value;
- + struct fotg210_udc *fotg210 = ep->fotg210;
- +
- + /* set transfer length and direction */
- + value = ioread32(fotg210->reg + FOTG210_DMACPSR1);
- + value &= ~(DMACPSR1_DMA_LEN(0xFFFF) | DMACPSR1_DMA_TYPE(1));
- + value |= DMACPSR1_DMA_LEN(len) | DMACPSR1_DMA_TYPE(ep->dir_in);
- + iowrite32(value, fotg210->reg + FOTG210_DMACPSR1);
- +
- + /* set device DMA target FIFO number */
- + value = ioread32(fotg210->reg + FOTG210_DMATFNR);
- + if (ep->epnum)
- + value |= DMATFNR_ACC_FN(ep->epnum - 1);
- + else
- + value |= DMATFNR_ACC_CXF;
- + iowrite32(value, fotg210->reg + FOTG210_DMATFNR);
- +
- + /* set DMA memory address */
- + iowrite32(d, fotg210->reg + FOTG210_DMACPSR2);
- +
- + /* enable MDMA_EROR and MDMA_CMPLT interrupt */
- + value = ioread32(fotg210->reg + FOTG210_DMISGR2);
- + value &= ~(DMISGR2_MDMA_CMPLT | DMISGR2_MDMA_ERROR);
- + iowrite32(value, fotg210->reg + FOTG210_DMISGR2);
- +
- + /* start DMA */
- + value = ioread32(fotg210->reg + FOTG210_DMACPSR1);
- + value |= DMACPSR1_DMA_START;
- + iowrite32(value, fotg210->reg + FOTG210_DMACPSR1);
- +}
- +
- +static void fotg210_disable_dma(struct fotg210_ep *ep)
- +{
- + iowrite32(DMATFNR_DISDMA, ep->fotg210->reg + FOTG210_DMATFNR);
- +}
- +
- +static void fotg210_wait_dma_done(struct fotg210_ep *ep)
- +{
- + u32 value;
- +
- + do {
- + value = ioread32(ep->fotg210->reg + FOTG210_DISGR2);
- + if ((value & DISGR2_USBRST_INT) ||
- + (value & DISGR2_DMA_ERROR))
- + goto dma_reset;
- + } while (!(value & DISGR2_DMA_CMPLT));
- +
- + value &= ~DISGR2_DMA_CMPLT;
- + iowrite32(value, ep->fotg210->reg + FOTG210_DISGR2);
- + return;
- +
- +dma_reset:
- + value = ioread32(ep->fotg210->reg + FOTG210_DMACPSR1);
- + value |= DMACPSR1_DMA_ABORT;
- + iowrite32(value, ep->fotg210->reg + FOTG210_DMACPSR1);
- +
- + /* reset fifo */
- + if (ep->epnum) {
- + value = ioread32(ep->fotg210->reg +
- + FOTG210_FIBCR(ep->epnum - 1));
- + value |= FIBCR_FFRST;
- + iowrite32(value, ep->fotg210->reg +
- + FOTG210_FIBCR(ep->epnum - 1));
- + } else {
- + value = ioread32(ep->fotg210->reg + FOTG210_DCFESR);
- + value |= DCFESR_CX_CLR;
- + iowrite32(value, ep->fotg210->reg + FOTG210_DCFESR);
- + }
- +}
- +
- +static void fotg210_start_dma(struct fotg210_ep *ep,
- + struct fotg210_request *req)
- +{
- + struct device *dev = &ep->fotg210->gadget.dev;
- + dma_addr_t d;
- + u8 *buffer;
- + u32 length;
- +
- + if (ep->epnum) {
- + if (ep->dir_in) {
- + buffer = req->req.buf;
- + length = req->req.length;
- + } else {
- + buffer = req->req.buf + req->req.actual;
- + length = ioread32(ep->fotg210->reg +
- + FOTG210_FIBCR(ep->epnum - 1)) & FIBCR_BCFX;
- + if (length > req->req.length - req->req.actual)
- + length = req->req.length - req->req.actual;
- + }
- + } else {
- + buffer = req->req.buf + req->req.actual;
- + if (req->req.length - req->req.actual > ep->ep.maxpacket)
- + length = ep->ep.maxpacket;
- + else
- + length = req->req.length - req->req.actual;
- + }
- +
- + d = dma_map_single(dev, buffer, length,
- + ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- +
- + if (dma_mapping_error(dev, d)) {
- + pr_err("dma_mapping_error\n");
- + return;
- + }
- +
- + fotg210_enable_dma(ep, d, length);
- +
- + /* check if dma is done */
- + fotg210_wait_dma_done(ep);
- +
- + fotg210_disable_dma(ep);
- +
- + /* update actual transfer length */
- + req->req.actual += length;
- +
- + dma_unmap_single(dev, d, length, DMA_TO_DEVICE);
- +}
- +
- +static void fotg210_ep0_queue(struct fotg210_ep *ep,
- + struct fotg210_request *req)
- +{
- + if (!req->req.length) {
- + fotg210_done(ep, req, 0);
- + return;
- + }
- + if (ep->dir_in) { /* if IN */
- + fotg210_start_dma(ep, req);
- + if (req->req.length == req->req.actual)
- + fotg210_done(ep, req, 0);
- + } else { /* OUT */
- + u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR0);
- +
- + value &= ~DMISGR0_MCX_OUT_INT;
- + iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR0);
- + }
- +}
- +
- +static int fotg210_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
- + gfp_t gfp_flags)
- +{
- + struct fotg210_ep *ep;
- + struct fotg210_request *req;
- + unsigned long flags;
- + int request = 0;
- +
- + ep = container_of(_ep, struct fotg210_ep, ep);
- + req = container_of(_req, struct fotg210_request, req);
- +
- + if (ep->fotg210->gadget.speed == USB_SPEED_UNKNOWN)
- + return -ESHUTDOWN;
- +
- + spin_lock_irqsave(&ep->fotg210->lock, flags);
- +
- + if (list_empty(&ep->queue))
- + request = 1;
- +
- + list_add_tail(&req->queue, &ep->queue);
- +
- + req->req.actual = 0;
- + req->req.status = -EINPROGRESS;
- +
- + if (!ep->epnum) /* ep0 */
- + fotg210_ep0_queue(ep, req);
- + else if (request && !ep->stall)
- + fotg210_enable_fifo_int(ep);
- +
- + spin_unlock_irqrestore(&ep->fotg210->lock, flags);
- +
- + return 0;
- +}
- +
- +static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
- +{
- + struct fotg210_ep *ep;
- + struct fotg210_request *req;
- + unsigned long flags;
- +
- + ep = container_of(_ep, struct fotg210_ep, ep);
- + req = container_of(_req, struct fotg210_request, req);
- +
- + spin_lock_irqsave(&ep->fotg210->lock, flags);
- + if (!list_empty(&ep->queue))
- + fotg210_done(ep, req, -ECONNRESET);
- + spin_unlock_irqrestore(&ep->fotg210->lock, flags);
- +
- + return 0;
- +}
- +
- +static void fotg210_set_epnstall(struct fotg210_ep *ep)
- +{
- + struct fotg210_udc *fotg210 = ep->fotg210;
- + u32 value;
- + void __iomem *reg;
- +
- + /* check if IN FIFO is empty before stall */
- + if (ep->dir_in) {
- + do {
- + value = ioread32(fotg210->reg + FOTG210_DCFESR);
- + } while (!(value & DCFESR_FIFO_EMPTY(ep->epnum - 1)));
- + }
- +
- + reg = (ep->dir_in) ?
- + fotg210->reg + FOTG210_INEPMPSR(ep->epnum) :
- + fotg210->reg + FOTG210_OUTEPMPSR(ep->epnum);
- + value = ioread32(reg);
- + value |= INOUTEPMPSR_STL_EP;
- + iowrite32(value, reg);
- +}
- +
- +static void fotg210_clear_epnstall(struct fotg210_ep *ep)
- +{
- + struct fotg210_udc *fotg210 = ep->fotg210;
- + u32 value;
- + void __iomem *reg;
- +
- + reg = (ep->dir_in) ?
- + fotg210->reg + FOTG210_INEPMPSR(ep->epnum) :
- + fotg210->reg + FOTG210_OUTEPMPSR(ep->epnum);
- + value = ioread32(reg);
- + value &= ~INOUTEPMPSR_STL_EP;
- + iowrite32(value, reg);
- +}
- +
- +static int fotg210_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge)
- +{
- + struct fotg210_ep *ep;
- + struct fotg210_udc *fotg210;
- + unsigned long flags;
- +
- + ep = container_of(_ep, struct fotg210_ep, ep);
- +
- + fotg210 = ep->fotg210;
- +
- + spin_lock_irqsave(&ep->fotg210->lock, flags);
- +
- + if (value) {
- + fotg210_set_epnstall(ep);
- + ep->stall = 1;
- + if (wedge)
- + ep->wedged = 1;
- + } else {
- + fotg210_reset_tseq(fotg210, ep->epnum);
- + fotg210_clear_epnstall(ep);
- + ep->stall = 0;
- + ep->wedged = 0;
- + if (!list_empty(&ep->queue))
- + fotg210_enable_fifo_int(ep);
- + }
- +
- + spin_unlock_irqrestore(&ep->fotg210->lock, flags);
- + return 0;
- +}
- +
- +static int fotg210_ep_set_halt(struct usb_ep *_ep, int value)
- +{
- + return fotg210_set_halt_and_wedge(_ep, value, 0);
- +}
- +
- +static int fotg210_ep_set_wedge(struct usb_ep *_ep)
- +{
- + return fotg210_set_halt_and_wedge(_ep, 1, 1);
- +}
- +
- +static void fotg210_ep_fifo_flush(struct usb_ep *_ep)
- +{
- +}
- +
- +static const struct usb_ep_ops fotg210_ep_ops = {
- + .enable = fotg210_ep_enable,
- + .disable = fotg210_ep_disable,
- +
- + .alloc_request = fotg210_ep_alloc_request,
- + .free_request = fotg210_ep_free_request,
- +
- + .queue = fotg210_ep_queue,
- + .dequeue = fotg210_ep_dequeue,
- +
- + .set_halt = fotg210_ep_set_halt,
- + .fifo_flush = fotg210_ep_fifo_flush,
- + .set_wedge = fotg210_ep_set_wedge,
- +};
- +
- +static void fotg210_clear_tx0byte(struct fotg210_udc *fotg210)
- +{
- + u32 value = ioread32(fotg210->reg + FOTG210_TX0BYTE);
- +
- + value &= ~(TX0BYTE_EP1 | TX0BYTE_EP2 | TX0BYTE_EP3
- + | TX0BYTE_EP4);
- + iowrite32(value, fotg210->reg + FOTG210_TX0BYTE);
- +}
- +
- +static void fotg210_clear_rx0byte(struct fotg210_udc *fotg210)
- +{
- + u32 value = ioread32(fotg210->reg + FOTG210_RX0BYTE);
- +
- + value &= ~(RX0BYTE_EP1 | RX0BYTE_EP2 | RX0BYTE_EP3
- + | RX0BYTE_EP4);
- + iowrite32(value, fotg210->reg + FOTG210_RX0BYTE);
- +}
- +
- +/* read 8-byte setup packet only */
- +static void fotg210_rdsetupp(struct fotg210_udc *fotg210,
- + u8 *buffer)
- +{
- + int i = 0;
- + u8 *tmp = buffer;
- + u32 data;
- + u32 length = 8;
- +
- + iowrite32(DMATFNR_ACC_CXF, fotg210->reg + FOTG210_DMATFNR);
- +
- + for (i = (length >> 2); i > 0; i--) {
- + data = ioread32(fotg210->reg + FOTG210_CXPORT);
- + *tmp = data & 0xFF;
- + *(tmp + 1) = (data >> 8) & 0xFF;
- + *(tmp + 2) = (data >> 16) & 0xFF;
- + *(tmp + 3) = (data >> 24) & 0xFF;
- + tmp = tmp + 4;
- + }
- +
- + switch (length % 4) {
- + case 1:
- + data = ioread32(fotg210->reg + FOTG210_CXPORT);
- + *tmp = data & 0xFF;
- + break;
- + case 2:
- + data = ioread32(fotg210->reg + FOTG210_CXPORT);
- + *tmp = data & 0xFF;
- + *(tmp + 1) = (data >> 8) & 0xFF;
- + break;
- + case 3:
- + data = ioread32(fotg210->reg + FOTG210_CXPORT);
- + *tmp = data & 0xFF;
- + *(tmp + 1) = (data >> 8) & 0xFF;
- + *(tmp + 2) = (data >> 16) & 0xFF;
- + break;
- + default:
- + break;
- + }
- +
- + iowrite32(DMATFNR_DISDMA, fotg210->reg + FOTG210_DMATFNR);
- +}
- +
- +static void fotg210_set_configuration(struct fotg210_udc *fotg210)
- +{
- + u32 value = ioread32(fotg210->reg + FOTG210_DAR);
- +
- + value |= DAR_AFT_CONF;
- + iowrite32(value, fotg210->reg + FOTG210_DAR);
- +}
- +
- +static void fotg210_set_dev_addr(struct fotg210_udc *fotg210, u32 addr)
- +{
- + u32 value = ioread32(fotg210->reg + FOTG210_DAR);
- +
- + value |= (addr & 0x7F);
- + iowrite32(value, fotg210->reg + FOTG210_DAR);
- +}
- +
- +static void fotg210_set_cxstall(struct fotg210_udc *fotg210)
- +{
- + u32 value = ioread32(fotg210->reg + FOTG210_DCFESR);
- +
- + value |= DCFESR_CX_STL;
- + iowrite32(value, fotg210->reg + FOTG210_DCFESR);
- +}
- +
- +static void fotg210_request_error(struct fotg210_udc *fotg210)
- +{
- + fotg210_set_cxstall(fotg210);
- + pr_err("request error!!\n");
- +}
- +
- +static void fotg210_set_address(struct fotg210_udc *fotg210,
- + struct usb_ctrlrequest *ctrl)
- +{
- + if (le16_to_cpu(ctrl->wValue) >= 0x0100) {
- + fotg210_request_error(fotg210);
- + } else {
- + fotg210_set_dev_addr(fotg210, le16_to_cpu(ctrl->wValue));
- + fotg210_set_cxdone(fotg210);
- + }
- +}
- +
- +static void fotg210_set_feature(struct fotg210_udc *fotg210,
- + struct usb_ctrlrequest *ctrl)
- +{
- + switch (ctrl->bRequestType & USB_RECIP_MASK) {
- + case USB_RECIP_DEVICE:
- + fotg210_set_cxdone(fotg210);
- + break;
- + case USB_RECIP_INTERFACE:
- + fotg210_set_cxdone(fotg210);
- + break;
- + case USB_RECIP_ENDPOINT: {
- + u8 epnum;
- + epnum = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK;
- + if (epnum)
- + fotg210_set_epnstall(fotg210->ep[epnum]);
- + else
- + fotg210_set_cxstall(fotg210);
- + fotg210_set_cxdone(fotg210);
- + }
- + break;
- + default:
- + fotg210_request_error(fotg210);
- + break;
- + }
- +}
- +
- +static void fotg210_clear_feature(struct fotg210_udc *fotg210,
- + struct usb_ctrlrequest *ctrl)
- +{
- + struct fotg210_ep *ep =
- + fotg210->ep[ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK];
- +
- + switch (ctrl->bRequestType & USB_RECIP_MASK) {
- + case USB_RECIP_DEVICE:
- + fotg210_set_cxdone(fotg210);
- + break;
- + case USB_RECIP_INTERFACE:
- + fotg210_set_cxdone(fotg210);
- + break;
- + case USB_RECIP_ENDPOINT:
- + if (ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK) {
- + if (ep->wedged) {
- + fotg210_set_cxdone(fotg210);
- + break;
- + }
- + if (ep->stall)
- + fotg210_set_halt_and_wedge(&ep->ep, 0, 0);
- + }
- + fotg210_set_cxdone(fotg210);
- + break;
- + default:
- + fotg210_request_error(fotg210);
- + break;
- + }
- +}
- +
- +static int fotg210_is_epnstall(struct fotg210_ep *ep)
- +{
- + struct fotg210_udc *fotg210 = ep->fotg210;
- + u32 value;
- + void __iomem *reg;
- +
- + reg = (ep->dir_in) ?
- + fotg210->reg + FOTG210_INEPMPSR(ep->epnum) :
- + fotg210->reg + FOTG210_OUTEPMPSR(ep->epnum);
- + value = ioread32(reg);
- + return value & INOUTEPMPSR_STL_EP ? 1 : 0;
- +}
- +
- +/* For EP0 requests triggered by this driver (currently GET_STATUS response) */
- +static void fotg210_ep0_complete(struct usb_ep *_ep, struct usb_request *req)
- +{
- + struct fotg210_ep *ep;
- + struct fotg210_udc *fotg210;
- +
- + ep = container_of(_ep, struct fotg210_ep, ep);
- + fotg210 = ep->fotg210;
- +
- + if (req->status || req->actual != req->length) {
- + dev_warn(&fotg210->gadget.dev, "EP0 request failed: %d\n", req->status);
- + }
- +}
- +
- +static void fotg210_get_status(struct fotg210_udc *fotg210,
- + struct usb_ctrlrequest *ctrl)
- +{
- + u8 epnum;
- +
- + switch (ctrl->bRequestType & USB_RECIP_MASK) {
- + case USB_RECIP_DEVICE:
- + fotg210->ep0_data = cpu_to_le16(1 << USB_DEVICE_SELF_POWERED);
- + break;
- + case USB_RECIP_INTERFACE:
- + fotg210->ep0_data = cpu_to_le16(0);
- + break;
- + case USB_RECIP_ENDPOINT:
- + epnum = ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK;
- + if (epnum)
- + fotg210->ep0_data =
- + cpu_to_le16(fotg210_is_epnstall(fotg210->ep[epnum])
- + << USB_ENDPOINT_HALT);
- + else
- + fotg210_request_error(fotg210);
- + break;
- +
- + default:
- + fotg210_request_error(fotg210);
- + return; /* exit */
- + }
- +
- + fotg210->ep0_req->buf = &fotg210->ep0_data;
- + fotg210->ep0_req->length = 2;
- +
- + spin_unlock(&fotg210->lock);
- + fotg210_ep_queue(fotg210->gadget.ep0, fotg210->ep0_req, GFP_ATOMIC);
- + spin_lock(&fotg210->lock);
- +}
- +
- +static int fotg210_setup_packet(struct fotg210_udc *fotg210,
- + struct usb_ctrlrequest *ctrl)
- +{
- + u8 *p = (u8 *)ctrl;
- + u8 ret = 0;
- +
- + fotg210_rdsetupp(fotg210, p);
- +
- + fotg210->ep[0]->dir_in = ctrl->bRequestType & USB_DIR_IN;
- +
- + if (fotg210->gadget.speed == USB_SPEED_UNKNOWN) {
- + u32 value = ioread32(fotg210->reg + FOTG210_DMCR);
- + fotg210->gadget.speed = value & DMCR_HS_EN ?
- + USB_SPEED_HIGH : USB_SPEED_FULL;
- + }
- +
- + /* check request */
- + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
- + switch (ctrl->bRequest) {
- + case USB_REQ_GET_STATUS:
- + fotg210_get_status(fotg210, ctrl);
- + break;
- + case USB_REQ_CLEAR_FEATURE:
- + fotg210_clear_feature(fotg210, ctrl);
- + break;
- + case USB_REQ_SET_FEATURE:
- + fotg210_set_feature(fotg210, ctrl);
- + break;
- + case USB_REQ_SET_ADDRESS:
- + fotg210_set_address(fotg210, ctrl);
- + break;
- + case USB_REQ_SET_CONFIGURATION:
- + fotg210_set_configuration(fotg210);
- + ret = 1;
- + break;
- + default:
- + ret = 1;
- + break;
- + }
- + } else {
- + ret = 1;
- + }
- +
- + return ret;
- +}
- +
- +static void fotg210_ep0out(struct fotg210_udc *fotg210)
- +{
- + struct fotg210_ep *ep = fotg210->ep[0];
- +
- + if (!list_empty(&ep->queue) && !ep->dir_in) {
- + struct fotg210_request *req;
- +
- + req = list_first_entry(&ep->queue,
- + struct fotg210_request, queue);
- +
- + if (req->req.length)
- + fotg210_start_dma(ep, req);
- +
- + if ((req->req.length - req->req.actual) < ep->ep.maxpacket)
- + fotg210_done(ep, req, 0);
- + } else {
- + pr_err("%s : empty queue\n", __func__);
- + }
- +}
- +
- +static void fotg210_ep0in(struct fotg210_udc *fotg210)
- +{
- + struct fotg210_ep *ep = fotg210->ep[0];
- +
- + if ((!list_empty(&ep->queue)) && (ep->dir_in)) {
- + struct fotg210_request *req;
- +
- + req = list_entry(ep->queue.next,
- + struct fotg210_request, queue);
- +
- + if (req->req.length)
- + fotg210_start_dma(ep, req);
- +
- + if (req->req.actual == req->req.length)
- + fotg210_done(ep, req, 0);
- + } else {
- + fotg210_set_cxdone(fotg210);
- + }
- +}
- +
- +static void fotg210_clear_comabt_int(struct fotg210_udc *fotg210)
- +{
- + u32 value = ioread32(fotg210->reg + FOTG210_DISGR0);
- +
- + value &= ~DISGR0_CX_COMABT_INT;
- + iowrite32(value, fotg210->reg + FOTG210_DISGR0);
- +}
- +
- +static void fotg210_in_fifo_handler(struct fotg210_ep *ep)
- +{
- + struct fotg210_request *req = list_entry(ep->queue.next,
- + struct fotg210_request, queue);
- +
- + if (req->req.length)
- + fotg210_start_dma(ep, req);
- + fotg210_done(ep, req, 0);
- +}
- +
- +static void fotg210_out_fifo_handler(struct fotg210_ep *ep)
- +{
- + struct fotg210_request *req = list_entry(ep->queue.next,
- + struct fotg210_request, queue);
- + int disgr1 = ioread32(ep->fotg210->reg + FOTG210_DISGR1);
- +
- + fotg210_start_dma(ep, req);
- +
- + /* Complete the request when it's full or a short packet arrived.
- + * Like other drivers, short_not_ok isn't handled.
- + */
- +
- + if (req->req.length == req->req.actual ||
- + (disgr1 & DISGR1_SPK_INT(ep->epnum - 1)))
- + fotg210_done(ep, req, 0);
- +}
- +
- +static irqreturn_t fotg210_irq(int irq, void *_fotg210)
- +{
- + struct fotg210_udc *fotg210 = _fotg210;
- + u32 int_grp = ioread32(fotg210->reg + FOTG210_DIGR);
- + u32 int_msk = ioread32(fotg210->reg + FOTG210_DMIGR);
- +
- + int_grp &= ~int_msk;
- +
- + spin_lock(&fotg210->lock);
- +
- + if (int_grp & DIGR_INT_G2) {
- + void __iomem *reg = fotg210->reg + FOTG210_DISGR2;
- + u32 int_grp2 = ioread32(reg);
- + u32 int_msk2 = ioread32(fotg210->reg + FOTG210_DMISGR2);
- + u32 value;
- +
- + int_grp2 &= ~int_msk2;
- +
- + if (int_grp2 & DISGR2_USBRST_INT) {
- + usb_gadget_udc_reset(&fotg210->gadget,
- + fotg210->driver);
- + value = ioread32(reg);
- + value &= ~DISGR2_USBRST_INT;
- + iowrite32(value, reg);
- + pr_info("fotg210 udc reset\n");
- + }
- + if (int_grp2 & DISGR2_SUSP_INT) {
- + value = ioread32(reg);
- + value &= ~DISGR2_SUSP_INT;
- + iowrite32(value, reg);
- + pr_info("fotg210 udc suspend\n");
- + }
- + if (int_grp2 & DISGR2_RESM_INT) {
- + value = ioread32(reg);
- + value &= ~DISGR2_RESM_INT;
- + iowrite32(value, reg);
- + pr_info("fotg210 udc resume\n");
- + }
- + if (int_grp2 & DISGR2_ISO_SEQ_ERR_INT) {
- + value = ioread32(reg);
- + value &= ~DISGR2_ISO_SEQ_ERR_INT;
- + iowrite32(value, reg);
- + pr_info("fotg210 iso sequence error\n");
- + }
- + if (int_grp2 & DISGR2_ISO_SEQ_ABORT_INT) {
- + value = ioread32(reg);
- + value &= ~DISGR2_ISO_SEQ_ABORT_INT;
- + iowrite32(value, reg);
- + pr_info("fotg210 iso sequence abort\n");
- + }
- + if (int_grp2 & DISGR2_TX0BYTE_INT) {
- + fotg210_clear_tx0byte(fotg210);
- + value = ioread32(reg);
- + value &= ~DISGR2_TX0BYTE_INT;
- + iowrite32(value, reg);
- + pr_info("fotg210 transferred 0 byte\n");
- + }
- + if (int_grp2 & DISGR2_RX0BYTE_INT) {
- + fotg210_clear_rx0byte(fotg210);
- + value = ioread32(reg);
- + value &= ~DISGR2_RX0BYTE_INT;
- + iowrite32(value, reg);
- + pr_info("fotg210 received 0 byte\n");
- + }
- + if (int_grp2 & DISGR2_DMA_ERROR) {
- + value = ioread32(reg);
- + value &= ~DISGR2_DMA_ERROR;
- + iowrite32(value, reg);
- + }
- + }
- +
- + if (int_grp & DIGR_INT_G0) {
- + void __iomem *reg = fotg210->reg + FOTG210_DISGR0;
- + u32 int_grp0 = ioread32(reg);
- + u32 int_msk0 = ioread32(fotg210->reg + FOTG210_DMISGR0);
- + struct usb_ctrlrequest ctrl;
- +
- + int_grp0 &= ~int_msk0;
- +
- + /* the highest priority in this source register */
- + if (int_grp0 & DISGR0_CX_COMABT_INT) {
- + fotg210_clear_comabt_int(fotg210);
- + pr_info("fotg210 CX command abort\n");
- + }
- +
- + if (int_grp0 & DISGR0_CX_SETUP_INT) {
- + if (fotg210_setup_packet(fotg210, &ctrl)) {
- + spin_unlock(&fotg210->lock);
- + if (fotg210->driver->setup(&fotg210->gadget,
- + &ctrl) < 0)
- + fotg210_set_cxstall(fotg210);
- + spin_lock(&fotg210->lock);
- + }
- + }
- + if (int_grp0 & DISGR0_CX_COMEND_INT)
- + pr_info("fotg210 cmd end\n");
- +
- + if (int_grp0 & DISGR0_CX_IN_INT)
- + fotg210_ep0in(fotg210);
- +
- + if (int_grp0 & DISGR0_CX_OUT_INT)
- + fotg210_ep0out(fotg210);
- +
- + if (int_grp0 & DISGR0_CX_COMFAIL_INT) {
- + fotg210_set_cxstall(fotg210);
- + pr_info("fotg210 ep0 fail\n");
- + }
- + }
- +
- + if (int_grp & DIGR_INT_G1) {
- + void __iomem *reg = fotg210->reg + FOTG210_DISGR1;
- + u32 int_grp1 = ioread32(reg);
- + u32 int_msk1 = ioread32(fotg210->reg + FOTG210_DMISGR1);
- + int fifo;
- +
- + int_grp1 &= ~int_msk1;
- +
- + for (fifo = 0; fifo < FOTG210_MAX_FIFO_NUM; fifo++) {
- + if (int_grp1 & DISGR1_IN_INT(fifo))
- + fotg210_in_fifo_handler(fotg210->ep[fifo + 1]);
- +
- + if ((int_grp1 & DISGR1_OUT_INT(fifo)) ||
- + (int_grp1 & DISGR1_SPK_INT(fifo)))
- + fotg210_out_fifo_handler(fotg210->ep[fifo + 1]);
- + }
- + }
- +
- + spin_unlock(&fotg210->lock);
- +
- + return IRQ_HANDLED;
- +}
- +
- +static void fotg210_disable_unplug(struct fotg210_udc *fotg210)
- +{
- + u32 reg = ioread32(fotg210->reg + FOTG210_PHYTMSR);
- +
- + reg &= ~PHYTMSR_UNPLUG;
- + iowrite32(reg, fotg210->reg + FOTG210_PHYTMSR);
- +}
- +
- +static int fotg210_udc_start(struct usb_gadget *g,
- + struct usb_gadget_driver *driver)
- +{
- + struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
- + u32 value;
- +
- + /* hook up the driver */
- + fotg210->driver = driver;
- +
- + /* enable device global interrupt */
- + value = ioread32(fotg210->reg + FOTG210_DMCR);
- + value |= DMCR_GLINT_EN;
- + iowrite32(value, fotg210->reg + FOTG210_DMCR);
- +
- + return 0;
- +}
- +
- +static void fotg210_init(struct fotg210_udc *fotg210)
- +{
- + u32 value;
- +
- + /* disable global interrupt and set int polarity to active high */
- + iowrite32(GMIR_MHC_INT | GMIR_MOTG_INT | GMIR_INT_POLARITY,
- + fotg210->reg + FOTG210_GMIR);
- +
- + /* disable device global interrupt */
- + value = ioread32(fotg210->reg + FOTG210_DMCR);
- + value &= ~DMCR_GLINT_EN;
- + iowrite32(value, fotg210->reg + FOTG210_DMCR);
- +
- + /* enable only grp2 irqs we handle */
- + iowrite32(~(DISGR2_DMA_ERROR | DISGR2_RX0BYTE_INT | DISGR2_TX0BYTE_INT
- + | DISGR2_ISO_SEQ_ABORT_INT | DISGR2_ISO_SEQ_ERR_INT
- + | DISGR2_RESM_INT | DISGR2_SUSP_INT | DISGR2_USBRST_INT),
- + fotg210->reg + FOTG210_DMISGR2);
- +
- + /* disable all fifo interrupt */
- + iowrite32(~(u32)0, fotg210->reg + FOTG210_DMISGR1);
- +
- + /* disable cmd end */
- + value = ioread32(fotg210->reg + FOTG210_DMISGR0);
- + value |= DMISGR0_MCX_COMEND;
- + iowrite32(value, fotg210->reg + FOTG210_DMISGR0);
- +}
- +
- +static int fotg210_udc_stop(struct usb_gadget *g)
- +{
- + struct fotg210_udc *fotg210 = gadget_to_fotg210(g);
- + unsigned long flags;
- +
- + spin_lock_irqsave(&fotg210->lock, flags);
- +
- + fotg210_init(fotg210);
- + fotg210->driver = NULL;
- +
- + spin_unlock_irqrestore(&fotg210->lock, flags);
- +
- + return 0;
- +}
- +
- +static const struct usb_gadget_ops fotg210_gadget_ops = {
- + .udc_start = fotg210_udc_start,
- + .udc_stop = fotg210_udc_stop,
- +};
- +
- +static int fotg210_udc_remove(struct platform_device *pdev)
- +{
- + struct fotg210_udc *fotg210 = platform_get_drvdata(pdev);
- + int i;
- +
- + usb_del_gadget_udc(&fotg210->gadget);
- + iounmap(fotg210->reg);
- + free_irq(platform_get_irq(pdev, 0), fotg210);
- +
- + fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req);
- + for (i = 0; i < FOTG210_MAX_NUM_EP; i++)
- + kfree(fotg210->ep[i]);
- + kfree(fotg210);
- +
- + return 0;
- +}
- +
- +static int fotg210_udc_probe(struct platform_device *pdev)
- +{
- + struct resource *res, *ires;
- + struct fotg210_udc *fotg210 = NULL;
- + struct fotg210_ep *_ep[FOTG210_MAX_NUM_EP];
- + int ret = 0;
- + int i;
- +
- + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- + if (!res) {
- + pr_err("platform_get_resource error.\n");
- + return -ENODEV;
- + }
- +
- + ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- + if (!ires) {
- + pr_err("platform_get_resource IORESOURCE_IRQ error.\n");
- + return -ENODEV;
- + }
- +
- + ret = -ENOMEM;
- +
- + /* initialize udc */
- + fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL);
- + if (fotg210 == NULL)
- + goto err;
- +
- + for (i = 0; i < FOTG210_MAX_NUM_EP; i++) {
- + _ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL);
- + if (_ep[i] == NULL)
- + goto err_alloc;
- + fotg210->ep[i] = _ep[i];
- + }
- +
- + fotg210->reg = ioremap(res->start, resource_size(res));
- + if (fotg210->reg == NULL) {
- + pr_err("ioremap error.\n");
- + goto err_alloc;
- + }
- +
- + spin_lock_init(&fotg210->lock);
- +
- + platform_set_drvdata(pdev, fotg210);
- +
- + fotg210->gadget.ops = &fotg210_gadget_ops;
- +
- + fotg210->gadget.max_speed = USB_SPEED_HIGH;
- + fotg210->gadget.dev.parent = &pdev->dev;
- + fotg210->gadget.dev.dma_mask = pdev->dev.dma_mask;
- + fotg210->gadget.name = udc_name;
- +
- + INIT_LIST_HEAD(&fotg210->gadget.ep_list);
- +
- + for (i = 0; i < FOTG210_MAX_NUM_EP; i++) {
- + struct fotg210_ep *ep = fotg210->ep[i];
- +
- + if (i) {
- + INIT_LIST_HEAD(&fotg210->ep[i]->ep.ep_list);
- + list_add_tail(&fotg210->ep[i]->ep.ep_list,
- + &fotg210->gadget.ep_list);
- + }
- + ep->fotg210 = fotg210;
- + INIT_LIST_HEAD(&ep->queue);
- + ep->ep.name = fotg210_ep_name[i];
- + ep->ep.ops = &fotg210_ep_ops;
- + usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);
- +
- + if (i == 0) {
- + ep->ep.caps.type_control = true;
- + } else {
- + ep->ep.caps.type_iso = true;
- + ep->ep.caps.type_bulk = true;
- + ep->ep.caps.type_int = true;
- + }
- +
- + ep->ep.caps.dir_in = true;
- + ep->ep.caps.dir_out = true;
- + }
- + usb_ep_set_maxpacket_limit(&fotg210->ep[0]->ep, 0x40);
- + fotg210->gadget.ep0 = &fotg210->ep[0]->ep;
- + INIT_LIST_HEAD(&fotg210->gadget.ep0->ep_list);
- +
- + fotg210->ep0_req = fotg210_ep_alloc_request(&fotg210->ep[0]->ep,
- + GFP_KERNEL);
- + if (fotg210->ep0_req == NULL)
- + goto err_map;
- +
- + fotg210->ep0_req->complete = fotg210_ep0_complete;
- +
- + fotg210_init(fotg210);
- +
- + fotg210_disable_unplug(fotg210);
- +
- + ret = request_irq(ires->start, fotg210_irq, IRQF_SHARED,
- + udc_name, fotg210);
- + if (ret < 0) {
- + pr_err("request_irq error (%d)\n", ret);
- + goto err_req;
- + }
- +
- + ret = usb_add_gadget_udc(&pdev->dev, &fotg210->gadget);
- + if (ret)
- + goto err_add_udc;
- +
- + dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
- +
- + return 0;
- +
- +err_add_udc:
- + free_irq(ires->start, fotg210);
- +
- +err_req:
- + fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req);
- +
- +err_map:
- + iounmap(fotg210->reg);
- +
- +err_alloc:
- + for (i = 0; i < FOTG210_MAX_NUM_EP; i++)
- + kfree(fotg210->ep[i]);
- + kfree(fotg210);
- +
- +err:
- + return ret;
- +}
- +
- +static struct platform_driver fotg210_driver = {
- + .driver = {
- + .name = udc_name,
- + },
- + .probe = fotg210_udc_probe,
- + .remove = fotg210_udc_remove,
- +};
- +
- +module_platform_driver(fotg210_driver);
- +
- +MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <[email protected]>");
- +MODULE_LICENSE("GPL");
- +MODULE_DESCRIPTION(DRIVER_DESC);
- --- a/drivers/usb/gadget/udc/Kconfig
- +++ b/drivers/usb/gadget/udc/Kconfig
- @@ -108,17 +108,6 @@ config USB_FUSB300
- help
- Faraday usb device controller FUSB300 driver
-
- -config USB_FOTG210_UDC
- - depends on HAS_DMA
- - tristate "Faraday FOTG210 USB Peripheral Controller"
- - help
- - Faraday USB2.0 OTG controller which can be configured as
- - high speed or full speed USB device. This driver supppors
- - Bulk Transfer so far.
- -
- - Say "y" to link the driver statically, or "m" to build a
- - dynamically linked module called "fotg210_udc".
- -
- config USB_GR_UDC
- tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver"
- depends on HAS_DMA
- --- a/drivers/usb/gadget/udc/Makefile
- +++ b/drivers/usb/gadget/udc/Makefile
- @@ -34,7 +34,6 @@ obj-$(CONFIG_USB_EG20T) += pch_udc.o
- obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
- mv_udc-y := mv_udc_core.o
- obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
- -obj-$(CONFIG_USB_FOTG210_UDC) += fotg210-udc.o
- obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
- obj-$(CONFIG_USB_GR_UDC) += gr_udc.o
- obj-$(CONFIG_USB_GADGET_XILINX) += udc-xilinx.o
- --- a/drivers/usb/host/Kconfig
- +++ b/drivers/usb/host/Kconfig
- @@ -389,17 +389,6 @@ config USB_ISP1362_HCD
- To compile this driver as a module, choose M here: the
- module will be called isp1362-hcd.
-
- -config USB_FOTG210_HCD
- - tristate "FOTG210 HCD support"
- - depends on USB && HAS_DMA && HAS_IOMEM
- - help
- - Faraday FOTG210 is an OTG controller which can be configured as
- - an USB2.0 host. It is designed to meet USB2.0 EHCI specification
- - with minor modification.
- -
- - To compile this driver as a module, choose M here: the
- - module will be called fotg210-hcd.
- -
- config USB_MAX3421_HCD
- tristate "MAX3421 HCD (USB-over-SPI) support"
- depends on USB && SPI
- --- a/drivers/usb/host/Makefile
- +++ b/drivers/usb/host/Makefile
- @@ -84,6 +84,5 @@ obj-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
- obj-$(CONFIG_USB_EHCI_MV) += ehci-mv.o
- obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
- obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
- -obj-$(CONFIG_USB_FOTG210_HCD) += fotg210-hcd.o
- obj-$(CONFIG_USB_MAX3421_HCD) += max3421-hcd.o
- obj-$(CONFIG_USB_XEN_HCD) += xen-hcd.o
- --- /dev/null
- +++ b/drivers/usb/fotg210/fotg210-hcd.h
- @@ -0,0 +1,688 @@
- +/* SPDX-License-Identifier: GPL-2.0 */
- +#ifndef __LINUX_FOTG210_H
- +#define __LINUX_FOTG210_H
- +
- +#include <linux/usb/ehci-dbgp.h>
- +
- +/* definitions used for the EHCI driver */
- +
- +/*
- + * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
- + * __leXX (normally) or __beXX (given FOTG210_BIG_ENDIAN_DESC), depending on
- + * the host controller implementation.
- + *
- + * To facilitate the strongest possible byte-order checking from "sparse"
- + * and so on, we use __leXX unless that's not practical.
- + */
- +#define __hc32 __le32
- +#define __hc16 __le16
- +
- +/* statistics can be kept for tuning/monitoring */
- +struct fotg210_stats {
- + /* irq usage */
- + unsigned long normal;
- + unsigned long error;
- + unsigned long iaa;
- + unsigned long lost_iaa;
- +
- + /* termination of urbs from core */
- + unsigned long complete;
- + unsigned long unlink;
- +};
- +
- +/* fotg210_hcd->lock guards shared data against other CPUs:
- + * fotg210_hcd: async, unlink, periodic (and shadow), ...
- + * usb_host_endpoint: hcpriv
- + * fotg210_qh: qh_next, qtd_list
- + * fotg210_qtd: qtd_list
- + *
- + * Also, hold this lock when talking to HC registers or
- + * when updating hw_* fields in shared qh/qtd/... structures.
- + */
- +
- +#define FOTG210_MAX_ROOT_PORTS 1 /* see HCS_N_PORTS */
- +
- +/*
- + * fotg210_rh_state values of FOTG210_RH_RUNNING or above mean that the
- + * controller may be doing DMA. Lower values mean there's no DMA.
- + */
- +enum fotg210_rh_state {
- + FOTG210_RH_HALTED,
- + FOTG210_RH_SUSPENDED,
- + FOTG210_RH_RUNNING,
- + FOTG210_RH_STOPPING
- +};
- +
- +/*
- + * Timer events, ordered by increasing delay length.
- + * Always update event_delays_ns[] and event_handlers[] (defined in
- + * ehci-timer.c) in parallel with this list.
- + */
- +enum fotg210_hrtimer_event {
- + FOTG210_HRTIMER_POLL_ASS, /* Poll for async schedule off */
- + FOTG210_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */
- + FOTG210_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */
- + FOTG210_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
- + FOTG210_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */
- + FOTG210_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */
- + FOTG210_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */
- + FOTG210_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
- + FOTG210_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */
- + FOTG210_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */
- + FOTG210_HRTIMER_NUM_EVENTS /* Must come last */
- +};
- +#define FOTG210_HRTIMER_NO_EVENT 99
- +
- +struct fotg210_hcd { /* one per controller */
- + /* timing support */
- + enum fotg210_hrtimer_event next_hrtimer_event;
- + unsigned enabled_hrtimer_events;
- + ktime_t hr_timeouts[FOTG210_HRTIMER_NUM_EVENTS];
- + struct hrtimer hrtimer;
- +
- + int PSS_poll_count;
- + int ASS_poll_count;
- + int died_poll_count;
- +
- + /* glue to PCI and HCD framework */
- + struct fotg210_caps __iomem *caps;
- + struct fotg210_regs __iomem *regs;
- + struct ehci_dbg_port __iomem *debug;
- +
- + __u32 hcs_params; /* cached register copy */
- + spinlock_t lock;
- + enum fotg210_rh_state rh_state;
- +
- + /* general schedule support */
- + bool scanning:1;
- + bool need_rescan:1;
- + bool intr_unlinking:1;
- + bool async_unlinking:1;
- + bool shutdown:1;
- + struct fotg210_qh *qh_scan_next;
- +
- + /* async schedule support */
- + struct fotg210_qh *async;
- + struct fotg210_qh *dummy; /* For AMD quirk use */
- + struct fotg210_qh *async_unlink;
- + struct fotg210_qh *async_unlink_last;
- + struct fotg210_qh *async_iaa;
- + unsigned async_unlink_cycle;
- + unsigned async_count; /* async activity count */
- +
- + /* periodic schedule support */
- +#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
- + unsigned periodic_size;
- + __hc32 *periodic; /* hw periodic table */
- + dma_addr_t periodic_dma;
- + struct list_head intr_qh_list;
- + unsigned i_thresh; /* uframes HC might cache */
- +
- + union fotg210_shadow *pshadow; /* mirror hw periodic table */
- + struct fotg210_qh *intr_unlink;
- + struct fotg210_qh *intr_unlink_last;
- + unsigned intr_unlink_cycle;
- + unsigned now_frame; /* frame from HC hardware */
- + unsigned next_frame; /* scan periodic, start here */
- + unsigned intr_count; /* intr activity count */
- + unsigned isoc_count; /* isoc activity count */
- + unsigned periodic_count; /* periodic activity count */
- + /* max periodic time per uframe */
- + unsigned uframe_periodic_max;
- +
- +
- + /* list of itds completed while now_frame was still active */
- + struct list_head cached_itd_list;
- + struct fotg210_itd *last_itd_to_free;
- +
- + /* per root hub port */
- + unsigned long reset_done[FOTG210_MAX_ROOT_PORTS];
- +
- + /* bit vectors (one bit per port)
- + * which ports were already suspended at the start of a bus suspend
- + */
- + unsigned long bus_suspended;
- +
- + /* which ports are edicated to the companion controller */
- + unsigned long companion_ports;
- +
- + /* which ports are owned by the companion during a bus suspend */
- + unsigned long owned_ports;
- +
- + /* which ports have the change-suspend feature turned on */
- + unsigned long port_c_suspend;
- +
- + /* which ports are suspended */
- + unsigned long suspended_ports;
- +
- + /* which ports have started to resume */
- + unsigned long resuming_ports;
- +
- + /* per-HC memory pools (could be per-bus, but ...) */
- + struct dma_pool *qh_pool; /* qh per active urb */
- + struct dma_pool *qtd_pool; /* one or more per qh */
- + struct dma_pool *itd_pool; /* itd per iso urb */
- +
- + unsigned random_frame;
- + unsigned long next_statechange;
- + ktime_t last_periodic_enable;
- + u32 command;
- +
- + /* SILICON QUIRKS */
- + unsigned need_io_watchdog:1;
- + unsigned fs_i_thresh:1; /* Intel iso scheduling */
- +
- + u8 sbrn; /* packed release number */
- +
- + /* irq statistics */
- +#ifdef FOTG210_STATS
- + struct fotg210_stats stats;
- +# define INCR(x) ((x)++)
- +#else
- +# define INCR(x) do {} while (0)
- +#endif
- +
- + /* silicon clock */
- + struct clk *pclk;
- +};
- +
- +/* convert between an HCD pointer and the corresponding FOTG210_HCD */
- +static inline struct fotg210_hcd *hcd_to_fotg210(struct usb_hcd *hcd)
- +{
- + return (struct fotg210_hcd *)(hcd->hcd_priv);
- +}
- +static inline struct usb_hcd *fotg210_to_hcd(struct fotg210_hcd *fotg210)
- +{
- + return container_of((void *) fotg210, struct usb_hcd, hcd_priv);
- +}
- +
- +/*-------------------------------------------------------------------------*/
- +
- +/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
- +
- +/* Section 2.2 Host Controller Capability Registers */
- +struct fotg210_caps {
- + /* these fields are specified as 8 and 16 bit registers,
- + * but some hosts can't perform 8 or 16 bit PCI accesses.
- + * some hosts treat caplength and hciversion as parts of a 32-bit
- + * register, others treat them as two separate registers, this
- + * affects the memory map for big endian controllers.
- + */
- + u32 hc_capbase;
- +#define HC_LENGTH(fotg210, p) (0x00ff&((p) >> /* bits 7:0 / offset 00h */ \
- + (fotg210_big_endian_capbase(fotg210) ? 24 : 0)))
- +#define HC_VERSION(fotg210, p) (0xffff&((p) >> /* bits 31:16 / offset 02h */ \
- + (fotg210_big_endian_capbase(fotg210) ? 0 : 16)))
- + u32 hcs_params; /* HCSPARAMS - offset 0x4 */
- +#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
- +
- + u32 hcc_params; /* HCCPARAMS - offset 0x8 */
- +#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
- +#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
- + u8 portroute[8]; /* nibbles for routing - offset 0xC */
- +};
- +
- +
- +/* Section 2.3 Host Controller Operational Registers */
- +struct fotg210_regs {
- +
- + /* USBCMD: offset 0x00 */
- + u32 command;
- +
- +/* EHCI 1.1 addendum */
- +/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
- +#define CMD_PARK (1<<11) /* enable "park" on async qh */
- +#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
- +#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
- +#define CMD_ASE (1<<5) /* async schedule enable */
- +#define CMD_PSE (1<<4) /* periodic schedule enable */
- +/* 3:2 is periodic frame list size */
- +#define CMD_RESET (1<<1) /* reset HC not bus */
- +#define CMD_RUN (1<<0) /* start/stop HC */
- +
- + /* USBSTS: offset 0x04 */
- + u32 status;
- +#define STS_ASS (1<<15) /* Async Schedule Status */
- +#define STS_PSS (1<<14) /* Periodic Schedule Status */
- +#define STS_RECL (1<<13) /* Reclamation */
- +#define STS_HALT (1<<12) /* Not running (any reason) */
- +/* some bits reserved */
- + /* these STS_* flags are also intr_enable bits (USBINTR) */
- +#define STS_IAA (1<<5) /* Interrupted on async advance */
- +#define STS_FATAL (1<<4) /* such as some PCI access errors */
- +#define STS_FLR (1<<3) /* frame list rolled over */
- +#define STS_PCD (1<<2) /* port change detect */
- +#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
- +#define STS_INT (1<<0) /* "normal" completion (short, ...) */
- +
- + /* USBINTR: offset 0x08 */
- + u32 intr_enable;
- +
- + /* FRINDEX: offset 0x0C */
- + u32 frame_index; /* current microframe number */
- + /* CTRLDSSEGMENT: offset 0x10 */
- + u32 segment; /* address bits 63:32 if needed */
- + /* PERIODICLISTBASE: offset 0x14 */
- + u32 frame_list; /* points to periodic list */
- + /* ASYNCLISTADDR: offset 0x18 */
- + u32 async_next; /* address of next async queue head */
- +
- + u32 reserved1;
- + /* PORTSC: offset 0x20 */
- + u32 port_status;
- +/* 31:23 reserved */
- +#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */
- +#define PORT_RESET (1<<8) /* reset port */
- +#define PORT_SUSPEND (1<<7) /* suspend port */
- +#define PORT_RESUME (1<<6) /* resume it */
- +#define PORT_PEC (1<<3) /* port enable change */
- +#define PORT_PE (1<<2) /* port enable */
- +#define PORT_CSC (1<<1) /* connect status change */
- +#define PORT_CONNECT (1<<0) /* device connected */
- +#define PORT_RWC_BITS (PORT_CSC | PORT_PEC)
- + u32 reserved2[19];
- +
- + /* OTGCSR: offet 0x70 */
- + u32 otgcsr;
- +#define OTGCSR_HOST_SPD_TYP (3 << 22)
- +#define OTGCSR_A_BUS_DROP (1 << 5)
- +#define OTGCSR_A_BUS_REQ (1 << 4)
- +
- + /* OTGISR: offset 0x74 */
- + u32 otgisr;
- +#define OTGISR_OVC (1 << 10)
- +
- + u32 reserved3[15];
- +
- + /* GMIR: offset 0xB4 */
- + u32 gmir;
- +#define GMIR_INT_POLARITY (1 << 3) /*Active High*/
- +#define GMIR_MHC_INT (1 << 2)
- +#define GMIR_MOTG_INT (1 << 1)
- +#define GMIR_MDEV_INT (1 << 0)
- +};
- +
- +/*-------------------------------------------------------------------------*/
- +
- +#define QTD_NEXT(fotg210, dma) cpu_to_hc32(fotg210, (u32)dma)
- +
- +/*
- + * EHCI Specification 0.95 Section 3.5
- + * QTD: describe data transfer components (buffer, direction, ...)
- + * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
- + *
- + * These are associated only with "QH" (Queue Head) structures,
- + * used with control, bulk, and interrupt transfers.
- + */
- +struct fotg210_qtd {
- + /* first part defined by EHCI spec */
- + __hc32 hw_next; /* see EHCI 3.5.1 */
- + __hc32 hw_alt_next; /* see EHCI 3.5.2 */
- + __hc32 hw_token; /* see EHCI 3.5.3 */
- +#define QTD_TOGGLE (1 << 31) /* data toggle */
- +#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
- +#define QTD_IOC (1 << 15) /* interrupt on complete */
- +#define QTD_CERR(tok) (((tok)>>10) & 0x3)
- +#define QTD_PID(tok) (((tok)>>8) & 0x3)
- +#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
- +#define QTD_STS_HALT (1 << 6) /* halted on error */
- +#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
- +#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
- +#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
- +#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
- +#define QTD_STS_STS (1 << 1) /* split transaction state */
- +#define QTD_STS_PING (1 << 0) /* issue PING? */
- +
- +#define ACTIVE_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_ACTIVE)
- +#define HALT_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_HALT)
- +#define STATUS_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_STS)
- +
- + __hc32 hw_buf[5]; /* see EHCI 3.5.4 */
- + __hc32 hw_buf_hi[5]; /* Appendix B */
- +
- + /* the rest is HCD-private */
- + dma_addr_t qtd_dma; /* qtd address */
- + struct list_head qtd_list; /* sw qtd list */
- + struct urb *urb; /* qtd's urb */
- + size_t length; /* length of buffer */
- +} __aligned(32);
- +
- +/* mask NakCnt+T in qh->hw_alt_next */
- +#define QTD_MASK(fotg210) cpu_to_hc32(fotg210, ~0x1f)
- +
- +#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
- +
- +/*-------------------------------------------------------------------------*/
- +
- +/* type tag from {qh,itd,fstn}->hw_next */
- +#define Q_NEXT_TYPE(fotg210, dma) ((dma) & cpu_to_hc32(fotg210, 3 << 1))
- +
- +/*
- + * Now the following defines are not converted using the
- + * cpu_to_le32() macro anymore, since we have to support
- + * "dynamic" switching between be and le support, so that the driver
- + * can be used on one system with SoC EHCI controller using big-endian
- + * descriptors as well as a normal little-endian PCI EHCI controller.
- + */
- +/* values for that type tag */
- +#define Q_TYPE_ITD (0 << 1)
- +#define Q_TYPE_QH (1 << 1)
- +#define Q_TYPE_SITD (2 << 1)
- +#define Q_TYPE_FSTN (3 << 1)
- +
- +/* next async queue entry, or pointer to interrupt/periodic QH */
- +#define QH_NEXT(fotg210, dma) \
- + (cpu_to_hc32(fotg210, (((u32)dma)&~0x01f)|Q_TYPE_QH))
- +
- +/* for periodic/async schedules and qtd lists, mark end of list */
- +#define FOTG210_LIST_END(fotg210) \
- + cpu_to_hc32(fotg210, 1) /* "null pointer" to hw */
- +
- +/*
- + * Entries in periodic shadow table are pointers to one of four kinds
- + * of data structure. That's dictated by the hardware; a type tag is
- + * encoded in the low bits of the hardware's periodic schedule. Use
- + * Q_NEXT_TYPE to get the tag.
- + *
- + * For entries in the async schedule, the type tag always says "qh".
- + */
- +union fotg210_shadow {
- + struct fotg210_qh *qh; /* Q_TYPE_QH */
- + struct fotg210_itd *itd; /* Q_TYPE_ITD */
- + struct fotg210_fstn *fstn; /* Q_TYPE_FSTN */
- + __hc32 *hw_next; /* (all types) */
- + void *ptr;
- +};
- +
- +/*-------------------------------------------------------------------------*/
- +
- +/*
- + * EHCI Specification 0.95 Section 3.6
- + * QH: describes control/bulk/interrupt endpoints
- + * See Fig 3-7 "Queue Head Structure Layout".
- + *
- + * These appear in both the async and (for interrupt) periodic schedules.
- + */
- +
- +/* first part defined by EHCI spec */
- +struct fotg210_qh_hw {
- + __hc32 hw_next; /* see EHCI 3.6.1 */
- + __hc32 hw_info1; /* see EHCI 3.6.2 */
- +#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */
- +#define QH_HEAD (1 << 15) /* Head of async reclamation list */
- +#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */
- +#define QH_HIGH_SPEED (2 << 12) /* Endpoint speed */
- +#define QH_LOW_SPEED (1 << 12)
- +#define QH_FULL_SPEED (0 << 12)
- +#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */
- + __hc32 hw_info2; /* see EHCI 3.6.2 */
- +#define QH_SMASK 0x000000ff
- +#define QH_CMASK 0x0000ff00
- +#define QH_HUBADDR 0x007f0000
- +#define QH_HUBPORT 0x3f800000
- +#define QH_MULT 0xc0000000
- + __hc32 hw_current; /* qtd list - see EHCI 3.6.4 */
- +
- + /* qtd overlay (hardware parts of a struct fotg210_qtd) */
- + __hc32 hw_qtd_next;
- + __hc32 hw_alt_next;
- + __hc32 hw_token;
- + __hc32 hw_buf[5];
- + __hc32 hw_buf_hi[5];
- +} __aligned(32);
- +
- +struct fotg210_qh {
- + struct fotg210_qh_hw *hw; /* Must come first */
- + /* the rest is HCD-private */
- + dma_addr_t qh_dma; /* address of qh */
- + union fotg210_shadow qh_next; /* ptr to qh; or periodic */
- + struct list_head qtd_list; /* sw qtd list */
- + struct list_head intr_node; /* list of intr QHs */
- + struct fotg210_qtd *dummy;
- + struct fotg210_qh *unlink_next; /* next on unlink list */
- +
- + unsigned unlink_cycle;
- +
- + u8 needs_rescan; /* Dequeue during giveback */
- + u8 qh_state;
- +#define QH_STATE_LINKED 1 /* HC sees this */
- +#define QH_STATE_UNLINK 2 /* HC may still see this */
- +#define QH_STATE_IDLE 3 /* HC doesn't see this */
- +#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */
- +#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
- +
- + u8 xacterrs; /* XactErr retry counter */
- +#define QH_XACTERR_MAX 32 /* XactErr retry limit */
- +
- + /* periodic schedule info */
- + u8 usecs; /* intr bandwidth */
- + u8 gap_uf; /* uframes split/csplit gap */
- + u8 c_usecs; /* ... split completion bw */
- + u16 tt_usecs; /* tt downstream bandwidth */
- + unsigned short period; /* polling interval */
- + unsigned short start; /* where polling starts */
- +#define NO_FRAME ((unsigned short)~0) /* pick new start */
- +
- + struct usb_device *dev; /* access to TT */
- + unsigned is_out:1; /* bulk or intr OUT */
- + unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
- +};
- +
- +/*-------------------------------------------------------------------------*/
- +
- +/* description of one iso transaction (up to 3 KB data if highspeed) */
- +struct fotg210_iso_packet {
- + /* These will be copied to iTD when scheduling */
- + u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */
- + __hc32 transaction; /* itd->hw_transaction[i] |= */
- + u8 cross; /* buf crosses pages */
- + /* for full speed OUT splits */
- + u32 buf1;
- +};
- +
- +/* temporary schedule data for packets from iso urbs (both speeds)
- + * each packet is one logical usb transaction to the device (not TT),
- + * beginning at stream->next_uframe
- + */
- +struct fotg210_iso_sched {
- + struct list_head td_list;
- + unsigned span;
- + struct fotg210_iso_packet packet[];
- +};
- +
- +/*
- + * fotg210_iso_stream - groups all (s)itds for this endpoint.
- + * acts like a qh would, if EHCI had them for ISO.
- + */
- +struct fotg210_iso_stream {
- + /* first field matches fotg210_hq, but is NULL */
- + struct fotg210_qh_hw *hw;
- +
- + u8 bEndpointAddress;
- + u8 highspeed;
- + struct list_head td_list; /* queued itds */
- + struct list_head free_list; /* list of unused itds */
- + struct usb_device *udev;
- + struct usb_host_endpoint *ep;
- +
- + /* output of (re)scheduling */
- + int next_uframe;
- + __hc32 splits;
- +
- + /* the rest is derived from the endpoint descriptor,
- + * trusting urb->interval == f(epdesc->bInterval) and
- + * including the extra info for hw_bufp[0..2]
- + */
- + u8 usecs, c_usecs;
- + u16 interval;
- + u16 tt_usecs;
- + u16 maxp;
- + u16 raw_mask;
- + unsigned bandwidth;
- +
- + /* This is used to initialize iTD's hw_bufp fields */
- + __hc32 buf0;
- + __hc32 buf1;
- + __hc32 buf2;
- +
- + /* this is used to initialize sITD's tt info */
- + __hc32 address;
- +};
- +
- +/*-------------------------------------------------------------------------*/
- +
- +/*
- + * EHCI Specification 0.95 Section 3.3
- + * Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
- + *
- + * Schedule records for high speed iso xfers
- + */
- +struct fotg210_itd {
- + /* first part defined by EHCI spec */
- + __hc32 hw_next; /* see EHCI 3.3.1 */
- + __hc32 hw_transaction[8]; /* see EHCI 3.3.2 */
- +#define FOTG210_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
- +#define FOTG210_ISOC_BUF_ERR (1<<30) /* Data buffer error */
- +#define FOTG210_ISOC_BABBLE (1<<29) /* babble detected */
- +#define FOTG210_ISOC_XACTERR (1<<28) /* XactErr - transaction error */
- +#define FOTG210_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff)
- +#define FOTG210_ITD_IOC (1 << 15) /* interrupt on complete */
- +
- +#define ITD_ACTIVE(fotg210) cpu_to_hc32(fotg210, FOTG210_ISOC_ACTIVE)
- +
- + __hc32 hw_bufp[7]; /* see EHCI 3.3.3 */
- + __hc32 hw_bufp_hi[7]; /* Appendix B */
- +
- + /* the rest is HCD-private */
- + dma_addr_t itd_dma; /* for this itd */
- + union fotg210_shadow itd_next; /* ptr to periodic q entry */
- +
- + struct urb *urb;
- + struct fotg210_iso_stream *stream; /* endpoint's queue */
- + struct list_head itd_list; /* list of stream's itds */
- +
- + /* any/all hw_transactions here may be used by that urb */
- + unsigned frame; /* where scheduled */
- + unsigned pg;
- + unsigned index[8]; /* in urb->iso_frame_desc */
- +} __aligned(32);
- +
- +/*-------------------------------------------------------------------------*/
- +
- +/*
- + * EHCI Specification 0.96 Section 3.7
- + * Periodic Frame Span Traversal Node (FSTN)
- + *
- + * Manages split interrupt transactions (using TT) that span frame boundaries
- + * into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN
- + * makes the HC jump (back) to a QH to scan for fs/ls QH completions until
- + * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
- + */
- +struct fotg210_fstn {
- + __hc32 hw_next; /* any periodic q entry */
- + __hc32 hw_prev; /* qh or FOTG210_LIST_END */
- +
- + /* the rest is HCD-private */
- + dma_addr_t fstn_dma;
- + union fotg210_shadow fstn_next; /* ptr to periodic q entry */
- +} __aligned(32);
- +
- +/*-------------------------------------------------------------------------*/
- +
- +/* Prepare the PORTSC wakeup flags during controller suspend/resume */
- +
- +#define fotg210_prepare_ports_for_controller_suspend(fotg210, do_wakeup) \
- + fotg210_adjust_port_wakeup_flags(fotg210, true, do_wakeup)
- +
- +#define fotg210_prepare_ports_for_controller_resume(fotg210) \
- + fotg210_adjust_port_wakeup_flags(fotg210, false, false)
- +
- +/*-------------------------------------------------------------------------*/
- +
- +/*
- + * Some EHCI controllers have a Transaction Translator built into the
- + * root hub. This is a non-standard feature. Each controller will need
- + * to add code to the following inline functions, and call them as
- + * needed (mostly in root hub code).
- + */
- +
- +static inline unsigned int
- +fotg210_get_speed(struct fotg210_hcd *fotg210, unsigned int portsc)
- +{
- + return (readl(&fotg210->regs->otgcsr)
- + & OTGCSR_HOST_SPD_TYP) >> 22;
- +}
- +
- +/* Returns the speed of a device attached to a port on the root hub. */
- +static inline unsigned int
- +fotg210_port_speed(struct fotg210_hcd *fotg210, unsigned int portsc)
- +{
- + switch (fotg210_get_speed(fotg210, portsc)) {
- + case 0:
- + return 0;
- + case 1:
- + return USB_PORT_STAT_LOW_SPEED;
- + case 2:
- + default:
- + return USB_PORT_STAT_HIGH_SPEED;
- + }
- +}
- +
- +/*-------------------------------------------------------------------------*/
- +
- +#define fotg210_has_fsl_portno_bug(e) (0)
- +
- +/*
- + * While most USB host controllers implement their registers in
- + * little-endian format, a minority (celleb companion chip) implement
- + * them in big endian format.
- + *
- + * This attempts to support either format at compile time without a
- + * runtime penalty, or both formats with the additional overhead
- + * of checking a flag bit.
- + *
- + */
- +
- +#define fotg210_big_endian_mmio(e) 0
- +#define fotg210_big_endian_capbase(e) 0
- +
- +static inline unsigned int fotg210_readl(const struct fotg210_hcd *fotg210,
- + __u32 __iomem *regs)
- +{
- + return readl(regs);
- +}
- +
- +static inline void fotg210_writel(const struct fotg210_hcd *fotg210,
- + const unsigned int val, __u32 __iomem *regs)
- +{
- + writel(val, regs);
- +}
- +
- +/* cpu to fotg210 */
- +static inline __hc32 cpu_to_hc32(const struct fotg210_hcd *fotg210, const u32 x)
- +{
- + return cpu_to_le32(x);
- +}
- +
- +/* fotg210 to cpu */
- +static inline u32 hc32_to_cpu(const struct fotg210_hcd *fotg210, const __hc32 x)
- +{
- + return le32_to_cpu(x);
- +}
- +
- +static inline u32 hc32_to_cpup(const struct fotg210_hcd *fotg210,
- + const __hc32 *x)
- +{
- + return le32_to_cpup(x);
- +}
- +
- +/*-------------------------------------------------------------------------*/
- +
- +static inline unsigned fotg210_read_frame_index(struct fotg210_hcd *fotg210)
- +{
- + return fotg210_readl(fotg210, &fotg210->regs->frame_index);
- +}
- +
- +/*-------------------------------------------------------------------------*/
- +
- +#endif /* __LINUX_FOTG210_H */
- --- /dev/null
- +++ b/drivers/usb/fotg210/fotg210-udc.h
- @@ -0,0 +1,249 @@
- +// SPDX-License-Identifier: GPL-2.0+
- +/*
- + * Faraday FOTG210 USB OTG controller
- + *
- + * Copyright (C) 2013 Faraday Technology Corporation
- + * Author: Yuan-Hsin Chen <[email protected]>
- + */
- +
- +#include <linux/kernel.h>
- +
- +#define FOTG210_MAX_NUM_EP 5 /* ep0...ep4 */
- +#define FOTG210_MAX_FIFO_NUM 4 /* fifo0...fifo4 */
- +
- +/* Global Mask of HC/OTG/DEV interrupt Register(0xC4) */
- +#define FOTG210_GMIR 0xC4
- +#define GMIR_INT_POLARITY 0x8 /*Active High*/
- +#define GMIR_MHC_INT 0x4
- +#define GMIR_MOTG_INT 0x2
- +#define GMIR_MDEV_INT 0x1
- +
- +/* Device Main Control Register(0x100) */
- +#define FOTG210_DMCR 0x100
- +#define DMCR_HS_EN (1 << 6)
- +#define DMCR_CHIP_EN (1 << 5)
- +#define DMCR_SFRST (1 << 4)
- +#define DMCR_GOSUSP (1 << 3)
- +#define DMCR_GLINT_EN (1 << 2)
- +#define DMCR_HALF_SPEED (1 << 1)
- +#define DMCR_CAP_RMWAKUP (1 << 0)
- +
- +/* Device Address Register(0x104) */
- +#define FOTG210_DAR 0x104
- +#define DAR_AFT_CONF (1 << 7)
- +
- +/* Device Test Register(0x108) */
- +#define FOTG210_DTR 0x108
- +#define DTR_TST_CLRFF (1 << 0)
- +
- +/* PHY Test Mode Selector register(0x114) */
- +#define FOTG210_PHYTMSR 0x114
- +#define PHYTMSR_TST_PKT (1 << 4)
- +#define PHYTMSR_TST_SE0NAK (1 << 3)
- +#define PHYTMSR_TST_KSTA (1 << 2)
- +#define PHYTMSR_TST_JSTA (1 << 1)
- +#define PHYTMSR_UNPLUG (1 << 0)
- +
- +/* Cx configuration and FIFO Empty Status register(0x120) */
- +#define FOTG210_DCFESR 0x120
- +#define DCFESR_FIFO_EMPTY(fifo) (1 << 8 << (fifo))
- +#define DCFESR_CX_EMP (1 << 5)
- +#define DCFESR_CX_CLR (1 << 3)
- +#define DCFESR_CX_STL (1 << 2)
- +#define DCFESR_TST_PKDONE (1 << 1)
- +#define DCFESR_CX_DONE (1 << 0)
- +
- +/* Device IDLE Counter Register(0x124) */
- +#define FOTG210_DICR 0x124
- +
- +/* Device Mask of Interrupt Group Register (0x130) */
- +#define FOTG210_DMIGR 0x130
- +#define DMIGR_MINT_G0 (1 << 0)
- +
- +/* Device Mask of Interrupt Source Group 0(0x134) */
- +#define FOTG210_DMISGR0 0x134
- +#define DMISGR0_MCX_COMEND (1 << 3)
- +#define DMISGR0_MCX_OUT_INT (1 << 2)
- +#define DMISGR0_MCX_IN_INT (1 << 1)
- +#define DMISGR0_MCX_SETUP_INT (1 << 0)
- +
- +/* Device Mask of Interrupt Source Group 1 Register(0x138)*/
- +#define FOTG210_DMISGR1 0x138
- +#define DMISGR1_MF3_IN_INT (1 << 19)
- +#define DMISGR1_MF2_IN_INT (1 << 18)
- +#define DMISGR1_MF1_IN_INT (1 << 17)
- +#define DMISGR1_MF0_IN_INT (1 << 16)
- +#define DMISGR1_MF_IN_INT(fifo) (1 << (16 + (fifo)))
- +#define DMISGR1_MF3_SPK_INT (1 << 7)
- +#define DMISGR1_MF3_OUT_INT (1 << 6)
- +#define DMISGR1_MF2_SPK_INT (1 << 5)
- +#define DMISGR1_MF2_OUT_INT (1 << 4)
- +#define DMISGR1_MF1_SPK_INT (1 << 3)
- +#define DMISGR1_MF1_OUT_INT (1 << 2)
- +#define DMISGR1_MF0_SPK_INT (1 << 1)
- +#define DMISGR1_MF0_OUT_INT (1 << 0)
- +#define DMISGR1_MF_OUTSPK_INT(fifo) (0x3 << (fifo) * 2)
- +
- +/* Device Mask of Interrupt Source Group 2 Register (0x13C) */
- +#define FOTG210_DMISGR2 0x13C
- +#define DMISGR2_MDMA_ERROR (1 << 8)
- +#define DMISGR2_MDMA_CMPLT (1 << 7)
- +
- +/* Device Interrupt group Register (0x140) */
- +#define FOTG210_DIGR 0x140
- +#define DIGR_INT_G2 (1 << 2)
- +#define DIGR_INT_G1 (1 << 1)
- +#define DIGR_INT_G0 (1 << 0)
- +
- +/* Device Interrupt Source Group 0 Register (0x144) */
- +#define FOTG210_DISGR0 0x144
- +#define DISGR0_CX_COMABT_INT (1 << 5)
- +#define DISGR0_CX_COMFAIL_INT (1 << 4)
- +#define DISGR0_CX_COMEND_INT (1 << 3)
- +#define DISGR0_CX_OUT_INT (1 << 2)
- +#define DISGR0_CX_IN_INT (1 << 1)
- +#define DISGR0_CX_SETUP_INT (1 << 0)
- +
- +/* Device Interrupt Source Group 1 Register (0x148) */
- +#define FOTG210_DISGR1 0x148
- +#define DISGR1_OUT_INT(fifo) (1 << ((fifo) * 2))
- +#define DISGR1_SPK_INT(fifo) (1 << 1 << ((fifo) * 2))
- +#define DISGR1_IN_INT(fifo) (1 << 16 << (fifo))
- +
- +/* Device Interrupt Source Group 2 Register (0x14C) */
- +#define FOTG210_DISGR2 0x14C
- +#define DISGR2_DMA_ERROR (1 << 8)
- +#define DISGR2_DMA_CMPLT (1 << 7)
- +#define DISGR2_RX0BYTE_INT (1 << 6)
- +#define DISGR2_TX0BYTE_INT (1 << 5)
- +#define DISGR2_ISO_SEQ_ABORT_INT (1 << 4)
- +#define DISGR2_ISO_SEQ_ERR_INT (1 << 3)
- +#define DISGR2_RESM_INT (1 << 2)
- +#define DISGR2_SUSP_INT (1 << 1)
- +#define DISGR2_USBRST_INT (1 << 0)
- +
- +/* Device Receive Zero-Length Data Packet Register (0x150)*/
- +#define FOTG210_RX0BYTE 0x150
- +#define RX0BYTE_EP8 (1 << 7)
- +#define RX0BYTE_EP7 (1 << 6)
- +#define RX0BYTE_EP6 (1 << 5)
- +#define RX0BYTE_EP5 (1 << 4)
- +#define RX0BYTE_EP4 (1 << 3)
- +#define RX0BYTE_EP3 (1 << 2)
- +#define RX0BYTE_EP2 (1 << 1)
- +#define RX0BYTE_EP1 (1 << 0)
- +
- +/* Device Transfer Zero-Length Data Packet Register (0x154)*/
- +#define FOTG210_TX0BYTE 0x154
- +#define TX0BYTE_EP8 (1 << 7)
- +#define TX0BYTE_EP7 (1 << 6)
- +#define TX0BYTE_EP6 (1 << 5)
- +#define TX0BYTE_EP5 (1 << 4)
- +#define TX0BYTE_EP4 (1 << 3)
- +#define TX0BYTE_EP3 (1 << 2)
- +#define TX0BYTE_EP2 (1 << 1)
- +#define TX0BYTE_EP1 (1 << 0)
- +
- +/* Device IN Endpoint x MaxPacketSize Register(0x160+4*(x-1)) */
- +#define FOTG210_INEPMPSR(ep) (0x160 + 4 * ((ep) - 1))
- +#define INOUTEPMPSR_MPS(mps) ((mps) & 0x2FF)
- +#define INOUTEPMPSR_STL_EP (1 << 11)
- +#define INOUTEPMPSR_RESET_TSEQ (1 << 12)
- +
- +/* Device OUT Endpoint x MaxPacketSize Register(0x180+4*(x-1)) */
- +#define FOTG210_OUTEPMPSR(ep) (0x180 + 4 * ((ep) - 1))
- +
- +/* Device Endpoint 1~4 Map Register (0x1A0) */
- +#define FOTG210_EPMAP 0x1A0
- +#define EPMAP_FIFONO(ep, dir) \
- + ((((ep) - 1) << ((ep) - 1) * 8) << ((dir) ? 0 : 4))
- +#define EPMAP_FIFONOMSK(ep, dir) \
- + ((3 << ((ep) - 1) * 8) << ((dir) ? 0 : 4))
- +
- +/* Device FIFO Map Register (0x1A8) */
- +#define FOTG210_FIFOMAP 0x1A8
- +#define FIFOMAP_DIROUT(fifo) (0x0 << 4 << (fifo) * 8)
- +#define FIFOMAP_DIRIN(fifo) (0x1 << 4 << (fifo) * 8)
- +#define FIFOMAP_BIDIR(fifo) (0x2 << 4 << (fifo) * 8)
- +#define FIFOMAP_NA(fifo) (0x3 << 4 << (fifo) * 8)
- +#define FIFOMAP_EPNO(ep) ((ep) << ((ep) - 1) * 8)
- +#define FIFOMAP_EPNOMSK(ep) (0xF << ((ep) - 1) * 8)
- +
- +/* Device FIFO Confuguration Register (0x1AC) */
- +#define FOTG210_FIFOCF 0x1AC
- +#define FIFOCF_TYPE(type, fifo) ((type) << (fifo) * 8)
- +#define FIFOCF_BLK_SIN(fifo) (0x0 << (fifo) * 8 << 2)
- +#define FIFOCF_BLK_DUB(fifo) (0x1 << (fifo) * 8 << 2)
- +#define FIFOCF_BLK_TRI(fifo) (0x2 << (fifo) * 8 << 2)
- +#define FIFOCF_BLKSZ_512(fifo) (0x0 << (fifo) * 8 << 4)
- +#define FIFOCF_BLKSZ_1024(fifo) (0x1 << (fifo) * 8 << 4)
- +#define FIFOCF_FIFO_EN(fifo) (0x1 << (fifo) * 8 << 5)
- +
- +/* Device FIFO n Instruction and Byte Count Register (0x1B0+4*n) */
- +#define FOTG210_FIBCR(fifo) (0x1B0 + (fifo) * 4)
- +#define FIBCR_BCFX 0x7FF
- +#define FIBCR_FFRST (1 << 12)
- +
- +/* Device DMA Target FIFO Number Register (0x1C0) */
- +#define FOTG210_DMATFNR 0x1C0
- +#define DMATFNR_ACC_CXF (1 << 4)
- +#define DMATFNR_ACC_F3 (1 << 3)
- +#define DMATFNR_ACC_F2 (1 << 2)
- +#define DMATFNR_ACC_F1 (1 << 1)
- +#define DMATFNR_ACC_F0 (1 << 0)
- +#define DMATFNR_ACC_FN(fifo) (1 << (fifo))
- +#define DMATFNR_DISDMA 0
- +
- +/* Device DMA Controller Parameter setting 1 Register (0x1C8) */
- +#define FOTG210_DMACPSR1 0x1C8
- +#define DMACPSR1_DMA_LEN(len) (((len) & 0xFFFF) << 8)
- +#define DMACPSR1_DMA_ABORT (1 << 3)
- +#define DMACPSR1_DMA_TYPE(dir_in) (((dir_in) ? 1 : 0) << 1)
- +#define DMACPSR1_DMA_START (1 << 0)
- +
- +/* Device DMA Controller Parameter setting 2 Register (0x1CC) */
- +#define FOTG210_DMACPSR2 0x1CC
- +
- +/* Device DMA Controller Parameter setting 3 Register (0x1CC) */
- +#define FOTG210_CXPORT 0x1D0
- +
- +struct fotg210_request {
- + struct usb_request req;
- + struct list_head queue;
- +};
- +
- +struct fotg210_ep {
- + struct usb_ep ep;
- + struct fotg210_udc *fotg210;
- +
- + struct list_head queue;
- + unsigned stall:1;
- + unsigned wedged:1;
- + unsigned use_dma:1;
- +
- + unsigned char epnum;
- + unsigned char type;
- + unsigned char dir_in;
- + unsigned int maxp;
- + const struct usb_endpoint_descriptor *desc;
- +};
- +
- +struct fotg210_udc {
- + spinlock_t lock; /* protect the struct */
- + void __iomem *reg;
- +
- + unsigned long irq_trigger;
- +
- + struct usb_gadget gadget;
- + struct usb_gadget_driver *driver;
- +
- + struct fotg210_ep *ep[FOTG210_MAX_NUM_EP];
- +
- + struct usb_request *ep0_req; /* for internal request */
- + __le16 ep0_data;
- + u8 ep0_dir; /* 0/0x80 out/in */
- +
- + u8 reenum; /* if re-enumeration */
- +};
- +
- +#define gadget_to_fotg210(g) container_of((g), struct fotg210_udc, gadget)
- --- a/drivers/usb/gadget/udc/fotg210.h
- +++ /dev/null
- @@ -1,249 +0,0 @@
- -// SPDX-License-Identifier: GPL-2.0+
- -/*
- - * Faraday FOTG210 USB OTG controller
- - *
- - * Copyright (C) 2013 Faraday Technology Corporation
- - * Author: Yuan-Hsin Chen <[email protected]>
- - */
- -
- -#include <linux/kernel.h>
- -
- -#define FOTG210_MAX_NUM_EP 5 /* ep0...ep4 */
- -#define FOTG210_MAX_FIFO_NUM 4 /* fifo0...fifo4 */
- -
- -/* Global Mask of HC/OTG/DEV interrupt Register(0xC4) */
- -#define FOTG210_GMIR 0xC4
- -#define GMIR_INT_POLARITY 0x8 /*Active High*/
- -#define GMIR_MHC_INT 0x4
- -#define GMIR_MOTG_INT 0x2
- -#define GMIR_MDEV_INT 0x1
- -
- -/* Device Main Control Register(0x100) */
- -#define FOTG210_DMCR 0x100
- -#define DMCR_HS_EN (1 << 6)
- -#define DMCR_CHIP_EN (1 << 5)
- -#define DMCR_SFRST (1 << 4)
- -#define DMCR_GOSUSP (1 << 3)
- -#define DMCR_GLINT_EN (1 << 2)
- -#define DMCR_HALF_SPEED (1 << 1)
- -#define DMCR_CAP_RMWAKUP (1 << 0)
- -
- -/* Device Address Register(0x104) */
- -#define FOTG210_DAR 0x104
- -#define DAR_AFT_CONF (1 << 7)
- -
- -/* Device Test Register(0x108) */
- -#define FOTG210_DTR 0x108
- -#define DTR_TST_CLRFF (1 << 0)
- -
- -/* PHY Test Mode Selector register(0x114) */
- -#define FOTG210_PHYTMSR 0x114
- -#define PHYTMSR_TST_PKT (1 << 4)
- -#define PHYTMSR_TST_SE0NAK (1 << 3)
- -#define PHYTMSR_TST_KSTA (1 << 2)
- -#define PHYTMSR_TST_JSTA (1 << 1)
- -#define PHYTMSR_UNPLUG (1 << 0)
- -
- -/* Cx configuration and FIFO Empty Status register(0x120) */
- -#define FOTG210_DCFESR 0x120
- -#define DCFESR_FIFO_EMPTY(fifo) (1 << 8 << (fifo))
- -#define DCFESR_CX_EMP (1 << 5)
- -#define DCFESR_CX_CLR (1 << 3)
- -#define DCFESR_CX_STL (1 << 2)
- -#define DCFESR_TST_PKDONE (1 << 1)
- -#define DCFESR_CX_DONE (1 << 0)
- -
- -/* Device IDLE Counter Register(0x124) */
- -#define FOTG210_DICR 0x124
- -
- -/* Device Mask of Interrupt Group Register (0x130) */
- -#define FOTG210_DMIGR 0x130
- -#define DMIGR_MINT_G0 (1 << 0)
- -
- -/* Device Mask of Interrupt Source Group 0(0x134) */
- -#define FOTG210_DMISGR0 0x134
- -#define DMISGR0_MCX_COMEND (1 << 3)
- -#define DMISGR0_MCX_OUT_INT (1 << 2)
- -#define DMISGR0_MCX_IN_INT (1 << 1)
- -#define DMISGR0_MCX_SETUP_INT (1 << 0)
- -
- -/* Device Mask of Interrupt Source Group 1 Register(0x138)*/
- -#define FOTG210_DMISGR1 0x138
- -#define DMISGR1_MF3_IN_INT (1 << 19)
- -#define DMISGR1_MF2_IN_INT (1 << 18)
- -#define DMISGR1_MF1_IN_INT (1 << 17)
- -#define DMISGR1_MF0_IN_INT (1 << 16)
- -#define DMISGR1_MF_IN_INT(fifo) (1 << (16 + (fifo)))
- -#define DMISGR1_MF3_SPK_INT (1 << 7)
- -#define DMISGR1_MF3_OUT_INT (1 << 6)
- -#define DMISGR1_MF2_SPK_INT (1 << 5)
- -#define DMISGR1_MF2_OUT_INT (1 << 4)
- -#define DMISGR1_MF1_SPK_INT (1 << 3)
- -#define DMISGR1_MF1_OUT_INT (1 << 2)
- -#define DMISGR1_MF0_SPK_INT (1 << 1)
- -#define DMISGR1_MF0_OUT_INT (1 << 0)
- -#define DMISGR1_MF_OUTSPK_INT(fifo) (0x3 << (fifo) * 2)
- -
- -/* Device Mask of Interrupt Source Group 2 Register (0x13C) */
- -#define FOTG210_DMISGR2 0x13C
- -#define DMISGR2_MDMA_ERROR (1 << 8)
- -#define DMISGR2_MDMA_CMPLT (1 << 7)
- -
- -/* Device Interrupt group Register (0x140) */
- -#define FOTG210_DIGR 0x140
- -#define DIGR_INT_G2 (1 << 2)
- -#define DIGR_INT_G1 (1 << 1)
- -#define DIGR_INT_G0 (1 << 0)
- -
- -/* Device Interrupt Source Group 0 Register (0x144) */
- -#define FOTG210_DISGR0 0x144
- -#define DISGR0_CX_COMABT_INT (1 << 5)
- -#define DISGR0_CX_COMFAIL_INT (1 << 4)
- -#define DISGR0_CX_COMEND_INT (1 << 3)
- -#define DISGR0_CX_OUT_INT (1 << 2)
- -#define DISGR0_CX_IN_INT (1 << 1)
- -#define DISGR0_CX_SETUP_INT (1 << 0)
- -
- -/* Device Interrupt Source Group 1 Register (0x148) */
- -#define FOTG210_DISGR1 0x148
- -#define DISGR1_OUT_INT(fifo) (1 << ((fifo) * 2))
- -#define DISGR1_SPK_INT(fifo) (1 << 1 << ((fifo) * 2))
- -#define DISGR1_IN_INT(fifo) (1 << 16 << (fifo))
- -
- -/* Device Interrupt Source Group 2 Register (0x14C) */
- -#define FOTG210_DISGR2 0x14C
- -#define DISGR2_DMA_ERROR (1 << 8)
- -#define DISGR2_DMA_CMPLT (1 << 7)
- -#define DISGR2_RX0BYTE_INT (1 << 6)
- -#define DISGR2_TX0BYTE_INT (1 << 5)
- -#define DISGR2_ISO_SEQ_ABORT_INT (1 << 4)
- -#define DISGR2_ISO_SEQ_ERR_INT (1 << 3)
- -#define DISGR2_RESM_INT (1 << 2)
- -#define DISGR2_SUSP_INT (1 << 1)
- -#define DISGR2_USBRST_INT (1 << 0)
- -
- -/* Device Receive Zero-Length Data Packet Register (0x150)*/
- -#define FOTG210_RX0BYTE 0x150
- -#define RX0BYTE_EP8 (1 << 7)
- -#define RX0BYTE_EP7 (1 << 6)
- -#define RX0BYTE_EP6 (1 << 5)
- -#define RX0BYTE_EP5 (1 << 4)
- -#define RX0BYTE_EP4 (1 << 3)
- -#define RX0BYTE_EP3 (1 << 2)
- -#define RX0BYTE_EP2 (1 << 1)
- -#define RX0BYTE_EP1 (1 << 0)
- -
- -/* Device Transfer Zero-Length Data Packet Register (0x154)*/
- -#define FOTG210_TX0BYTE 0x154
- -#define TX0BYTE_EP8 (1 << 7)
- -#define TX0BYTE_EP7 (1 << 6)
- -#define TX0BYTE_EP6 (1 << 5)
- -#define TX0BYTE_EP5 (1 << 4)
- -#define TX0BYTE_EP4 (1 << 3)
- -#define TX0BYTE_EP3 (1 << 2)
- -#define TX0BYTE_EP2 (1 << 1)
- -#define TX0BYTE_EP1 (1 << 0)
- -
- -/* Device IN Endpoint x MaxPacketSize Register(0x160+4*(x-1)) */
- -#define FOTG210_INEPMPSR(ep) (0x160 + 4 * ((ep) - 1))
- -#define INOUTEPMPSR_MPS(mps) ((mps) & 0x2FF)
- -#define INOUTEPMPSR_STL_EP (1 << 11)
- -#define INOUTEPMPSR_RESET_TSEQ (1 << 12)
- -
- -/* Device OUT Endpoint x MaxPacketSize Register(0x180+4*(x-1)) */
- -#define FOTG210_OUTEPMPSR(ep) (0x180 + 4 * ((ep) - 1))
- -
- -/* Device Endpoint 1~4 Map Register (0x1A0) */
- -#define FOTG210_EPMAP 0x1A0
- -#define EPMAP_FIFONO(ep, dir) \
- - ((((ep) - 1) << ((ep) - 1) * 8) << ((dir) ? 0 : 4))
- -#define EPMAP_FIFONOMSK(ep, dir) \
- - ((3 << ((ep) - 1) * 8) << ((dir) ? 0 : 4))
- -
- -/* Device FIFO Map Register (0x1A8) */
- -#define FOTG210_FIFOMAP 0x1A8
- -#define FIFOMAP_DIROUT(fifo) (0x0 << 4 << (fifo) * 8)
- -#define FIFOMAP_DIRIN(fifo) (0x1 << 4 << (fifo) * 8)
- -#define FIFOMAP_BIDIR(fifo) (0x2 << 4 << (fifo) * 8)
- -#define FIFOMAP_NA(fifo) (0x3 << 4 << (fifo) * 8)
- -#define FIFOMAP_EPNO(ep) ((ep) << ((ep) - 1) * 8)
- -#define FIFOMAP_EPNOMSK(ep) (0xF << ((ep) - 1) * 8)
- -
- -/* Device FIFO Confuguration Register (0x1AC) */
- -#define FOTG210_FIFOCF 0x1AC
- -#define FIFOCF_TYPE(type, fifo) ((type) << (fifo) * 8)
- -#define FIFOCF_BLK_SIN(fifo) (0x0 << (fifo) * 8 << 2)
- -#define FIFOCF_BLK_DUB(fifo) (0x1 << (fifo) * 8 << 2)
- -#define FIFOCF_BLK_TRI(fifo) (0x2 << (fifo) * 8 << 2)
- -#define FIFOCF_BLKSZ_512(fifo) (0x0 << (fifo) * 8 << 4)
- -#define FIFOCF_BLKSZ_1024(fifo) (0x1 << (fifo) * 8 << 4)
- -#define FIFOCF_FIFO_EN(fifo) (0x1 << (fifo) * 8 << 5)
- -
- -/* Device FIFO n Instruction and Byte Count Register (0x1B0+4*n) */
- -#define FOTG210_FIBCR(fifo) (0x1B0 + (fifo) * 4)
- -#define FIBCR_BCFX 0x7FF
- -#define FIBCR_FFRST (1 << 12)
- -
- -/* Device DMA Target FIFO Number Register (0x1C0) */
- -#define FOTG210_DMATFNR 0x1C0
- -#define DMATFNR_ACC_CXF (1 << 4)
- -#define DMATFNR_ACC_F3 (1 << 3)
- -#define DMATFNR_ACC_F2 (1 << 2)
- -#define DMATFNR_ACC_F1 (1 << 1)
- -#define DMATFNR_ACC_F0 (1 << 0)
- -#define DMATFNR_ACC_FN(fifo) (1 << (fifo))
- -#define DMATFNR_DISDMA 0
- -
- -/* Device DMA Controller Parameter setting 1 Register (0x1C8) */
- -#define FOTG210_DMACPSR1 0x1C8
- -#define DMACPSR1_DMA_LEN(len) (((len) & 0xFFFF) << 8)
- -#define DMACPSR1_DMA_ABORT (1 << 3)
- -#define DMACPSR1_DMA_TYPE(dir_in) (((dir_in) ? 1 : 0) << 1)
- -#define DMACPSR1_DMA_START (1 << 0)
- -
- -/* Device DMA Controller Parameter setting 2 Register (0x1CC) */
- -#define FOTG210_DMACPSR2 0x1CC
- -
- -/* Device DMA Controller Parameter setting 3 Register (0x1CC) */
- -#define FOTG210_CXPORT 0x1D0
- -
- -struct fotg210_request {
- - struct usb_request req;
- - struct list_head queue;
- -};
- -
- -struct fotg210_ep {
- - struct usb_ep ep;
- - struct fotg210_udc *fotg210;
- -
- - struct list_head queue;
- - unsigned stall:1;
- - unsigned wedged:1;
- - unsigned use_dma:1;
- -
- - unsigned char epnum;
- - unsigned char type;
- - unsigned char dir_in;
- - unsigned int maxp;
- - const struct usb_endpoint_descriptor *desc;
- -};
- -
- -struct fotg210_udc {
- - spinlock_t lock; /* protect the struct */
- - void __iomem *reg;
- -
- - unsigned long irq_trigger;
- -
- - struct usb_gadget gadget;
- - struct usb_gadget_driver *driver;
- -
- - struct fotg210_ep *ep[FOTG210_MAX_NUM_EP];
- -
- - struct usb_request *ep0_req; /* for internal request */
- - __le16 ep0_data;
- - u8 ep0_dir; /* 0/0x80 out/in */
- -
- - u8 reenum; /* if re-enumeration */
- -};
- -
- -#define gadget_to_fotg210(g) container_of((g), struct fotg210_udc, gadget)
- --- a/drivers/usb/host/fotg210.h
- +++ /dev/null
- @@ -1,688 +0,0 @@
- -/* SPDX-License-Identifier: GPL-2.0 */
- -#ifndef __LINUX_FOTG210_H
- -#define __LINUX_FOTG210_H
- -
- -#include <linux/usb/ehci-dbgp.h>
- -
- -/* definitions used for the EHCI driver */
- -
- -/*
- - * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
- - * __leXX (normally) or __beXX (given FOTG210_BIG_ENDIAN_DESC), depending on
- - * the host controller implementation.
- - *
- - * To facilitate the strongest possible byte-order checking from "sparse"
- - * and so on, we use __leXX unless that's not practical.
- - */
- -#define __hc32 __le32
- -#define __hc16 __le16
- -
- -/* statistics can be kept for tuning/monitoring */
- -struct fotg210_stats {
- - /* irq usage */
- - unsigned long normal;
- - unsigned long error;
- - unsigned long iaa;
- - unsigned long lost_iaa;
- -
- - /* termination of urbs from core */
- - unsigned long complete;
- - unsigned long unlink;
- -};
- -
- -/* fotg210_hcd->lock guards shared data against other CPUs:
- - * fotg210_hcd: async, unlink, periodic (and shadow), ...
- - * usb_host_endpoint: hcpriv
- - * fotg210_qh: qh_next, qtd_list
- - * fotg210_qtd: qtd_list
- - *
- - * Also, hold this lock when talking to HC registers or
- - * when updating hw_* fields in shared qh/qtd/... structures.
- - */
- -
- -#define FOTG210_MAX_ROOT_PORTS 1 /* see HCS_N_PORTS */
- -
- -/*
- - * fotg210_rh_state values of FOTG210_RH_RUNNING or above mean that the
- - * controller may be doing DMA. Lower values mean there's no DMA.
- - */
- -enum fotg210_rh_state {
- - FOTG210_RH_HALTED,
- - FOTG210_RH_SUSPENDED,
- - FOTG210_RH_RUNNING,
- - FOTG210_RH_STOPPING
- -};
- -
- -/*
- - * Timer events, ordered by increasing delay length.
- - * Always update event_delays_ns[] and event_handlers[] (defined in
- - * ehci-timer.c) in parallel with this list.
- - */
- -enum fotg210_hrtimer_event {
- - FOTG210_HRTIMER_POLL_ASS, /* Poll for async schedule off */
- - FOTG210_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */
- - FOTG210_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */
- - FOTG210_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
- - FOTG210_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */
- - FOTG210_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */
- - FOTG210_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */
- - FOTG210_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
- - FOTG210_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */
- - FOTG210_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */
- - FOTG210_HRTIMER_NUM_EVENTS /* Must come last */
- -};
- -#define FOTG210_HRTIMER_NO_EVENT 99
- -
- -struct fotg210_hcd { /* one per controller */
- - /* timing support */
- - enum fotg210_hrtimer_event next_hrtimer_event;
- - unsigned enabled_hrtimer_events;
- - ktime_t hr_timeouts[FOTG210_HRTIMER_NUM_EVENTS];
- - struct hrtimer hrtimer;
- -
- - int PSS_poll_count;
- - int ASS_poll_count;
- - int died_poll_count;
- -
- - /* glue to PCI and HCD framework */
- - struct fotg210_caps __iomem *caps;
- - struct fotg210_regs __iomem *regs;
- - struct ehci_dbg_port __iomem *debug;
- -
- - __u32 hcs_params; /* cached register copy */
- - spinlock_t lock;
- - enum fotg210_rh_state rh_state;
- -
- - /* general schedule support */
- - bool scanning:1;
- - bool need_rescan:1;
- - bool intr_unlinking:1;
- - bool async_unlinking:1;
- - bool shutdown:1;
- - struct fotg210_qh *qh_scan_next;
- -
- - /* async schedule support */
- - struct fotg210_qh *async;
- - struct fotg210_qh *dummy; /* For AMD quirk use */
- - struct fotg210_qh *async_unlink;
- - struct fotg210_qh *async_unlink_last;
- - struct fotg210_qh *async_iaa;
- - unsigned async_unlink_cycle;
- - unsigned async_count; /* async activity count */
- -
- - /* periodic schedule support */
- -#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
- - unsigned periodic_size;
- - __hc32 *periodic; /* hw periodic table */
- - dma_addr_t periodic_dma;
- - struct list_head intr_qh_list;
- - unsigned i_thresh; /* uframes HC might cache */
- -
- - union fotg210_shadow *pshadow; /* mirror hw periodic table */
- - struct fotg210_qh *intr_unlink;
- - struct fotg210_qh *intr_unlink_last;
- - unsigned intr_unlink_cycle;
- - unsigned now_frame; /* frame from HC hardware */
- - unsigned next_frame; /* scan periodic, start here */
- - unsigned intr_count; /* intr activity count */
- - unsigned isoc_count; /* isoc activity count */
- - unsigned periodic_count; /* periodic activity count */
- - /* max periodic time per uframe */
- - unsigned uframe_periodic_max;
- -
- -
- - /* list of itds completed while now_frame was still active */
- - struct list_head cached_itd_list;
- - struct fotg210_itd *last_itd_to_free;
- -
- - /* per root hub port */
- - unsigned long reset_done[FOTG210_MAX_ROOT_PORTS];
- -
- - /* bit vectors (one bit per port)
- - * which ports were already suspended at the start of a bus suspend
- - */
- - unsigned long bus_suspended;
- -
- - /* which ports are edicated to the companion controller */
- - unsigned long companion_ports;
- -
- - /* which ports are owned by the companion during a bus suspend */
- - unsigned long owned_ports;
- -
- - /* which ports have the change-suspend feature turned on */
- - unsigned long port_c_suspend;
- -
- - /* which ports are suspended */
- - unsigned long suspended_ports;
- -
- - /* which ports have started to resume */
- - unsigned long resuming_ports;
- -
- - /* per-HC memory pools (could be per-bus, but ...) */
- - struct dma_pool *qh_pool; /* qh per active urb */
- - struct dma_pool *qtd_pool; /* one or more per qh */
- - struct dma_pool *itd_pool; /* itd per iso urb */
- -
- - unsigned random_frame;
- - unsigned long next_statechange;
- - ktime_t last_periodic_enable;
- - u32 command;
- -
- - /* SILICON QUIRKS */
- - unsigned need_io_watchdog:1;
- - unsigned fs_i_thresh:1; /* Intel iso scheduling */
- -
- - u8 sbrn; /* packed release number */
- -
- - /* irq statistics */
- -#ifdef FOTG210_STATS
- - struct fotg210_stats stats;
- -# define INCR(x) ((x)++)
- -#else
- -# define INCR(x) do {} while (0)
- -#endif
- -
- - /* silicon clock */
- - struct clk *pclk;
- -};
- -
- -/* convert between an HCD pointer and the corresponding FOTG210_HCD */
- -static inline struct fotg210_hcd *hcd_to_fotg210(struct usb_hcd *hcd)
- -{
- - return (struct fotg210_hcd *)(hcd->hcd_priv);
- -}
- -static inline struct usb_hcd *fotg210_to_hcd(struct fotg210_hcd *fotg210)
- -{
- - return container_of((void *) fotg210, struct usb_hcd, hcd_priv);
- -}
- -
- -/*-------------------------------------------------------------------------*/
- -
- -/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
- -
- -/* Section 2.2 Host Controller Capability Registers */
- -struct fotg210_caps {
- - /* these fields are specified as 8 and 16 bit registers,
- - * but some hosts can't perform 8 or 16 bit PCI accesses.
- - * some hosts treat caplength and hciversion as parts of a 32-bit
- - * register, others treat them as two separate registers, this
- - * affects the memory map for big endian controllers.
- - */
- - u32 hc_capbase;
- -#define HC_LENGTH(fotg210, p) (0x00ff&((p) >> /* bits 7:0 / offset 00h */ \
- - (fotg210_big_endian_capbase(fotg210) ? 24 : 0)))
- -#define HC_VERSION(fotg210, p) (0xffff&((p) >> /* bits 31:16 / offset 02h */ \
- - (fotg210_big_endian_capbase(fotg210) ? 0 : 16)))
- - u32 hcs_params; /* HCSPARAMS - offset 0x4 */
- -#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
- -
- - u32 hcc_params; /* HCCPARAMS - offset 0x8 */
- -#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
- -#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
- - u8 portroute[8]; /* nibbles for routing - offset 0xC */
- -};
- -
- -
- -/* Section 2.3 Host Controller Operational Registers */
- -struct fotg210_regs {
- -
- - /* USBCMD: offset 0x00 */
- - u32 command;
- -
- -/* EHCI 1.1 addendum */
- -/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
- -#define CMD_PARK (1<<11) /* enable "park" on async qh */
- -#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
- -#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
- -#define CMD_ASE (1<<5) /* async schedule enable */
- -#define CMD_PSE (1<<4) /* periodic schedule enable */
- -/* 3:2 is periodic frame list size */
- -#define CMD_RESET (1<<1) /* reset HC not bus */
- -#define CMD_RUN (1<<0) /* start/stop HC */
- -
- - /* USBSTS: offset 0x04 */
- - u32 status;
- -#define STS_ASS (1<<15) /* Async Schedule Status */
- -#define STS_PSS (1<<14) /* Periodic Schedule Status */
- -#define STS_RECL (1<<13) /* Reclamation */
- -#define STS_HALT (1<<12) /* Not running (any reason) */
- -/* some bits reserved */
- - /* these STS_* flags are also intr_enable bits (USBINTR) */
- -#define STS_IAA (1<<5) /* Interrupted on async advance */
- -#define STS_FATAL (1<<4) /* such as some PCI access errors */
- -#define STS_FLR (1<<3) /* frame list rolled over */
- -#define STS_PCD (1<<2) /* port change detect */
- -#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
- -#define STS_INT (1<<0) /* "normal" completion (short, ...) */
- -
- - /* USBINTR: offset 0x08 */
- - u32 intr_enable;
- -
- - /* FRINDEX: offset 0x0C */
- - u32 frame_index; /* current microframe number */
- - /* CTRLDSSEGMENT: offset 0x10 */
- - u32 segment; /* address bits 63:32 if needed */
- - /* PERIODICLISTBASE: offset 0x14 */
- - u32 frame_list; /* points to periodic list */
- - /* ASYNCLISTADDR: offset 0x18 */
- - u32 async_next; /* address of next async queue head */
- -
- - u32 reserved1;
- - /* PORTSC: offset 0x20 */
- - u32 port_status;
- -/* 31:23 reserved */
- -#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */
- -#define PORT_RESET (1<<8) /* reset port */
- -#define PORT_SUSPEND (1<<7) /* suspend port */
- -#define PORT_RESUME (1<<6) /* resume it */
- -#define PORT_PEC (1<<3) /* port enable change */
- -#define PORT_PE (1<<2) /* port enable */
- -#define PORT_CSC (1<<1) /* connect status change */
- -#define PORT_CONNECT (1<<0) /* device connected */
- -#define PORT_RWC_BITS (PORT_CSC | PORT_PEC)
- - u32 reserved2[19];
- -
- - /* OTGCSR: offet 0x70 */
- - u32 otgcsr;
- -#define OTGCSR_HOST_SPD_TYP (3 << 22)
- -#define OTGCSR_A_BUS_DROP (1 << 5)
- -#define OTGCSR_A_BUS_REQ (1 << 4)
- -
- - /* OTGISR: offset 0x74 */
- - u32 otgisr;
- -#define OTGISR_OVC (1 << 10)
- -
- - u32 reserved3[15];
- -
- - /* GMIR: offset 0xB4 */
- - u32 gmir;
- -#define GMIR_INT_POLARITY (1 << 3) /*Active High*/
- -#define GMIR_MHC_INT (1 << 2)
- -#define GMIR_MOTG_INT (1 << 1)
- -#define GMIR_MDEV_INT (1 << 0)
- -};
- -
- -/*-------------------------------------------------------------------------*/
- -
- -#define QTD_NEXT(fotg210, dma) cpu_to_hc32(fotg210, (u32)dma)
- -
- -/*
- - * EHCI Specification 0.95 Section 3.5
- - * QTD: describe data transfer components (buffer, direction, ...)
- - * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
- - *
- - * These are associated only with "QH" (Queue Head) structures,
- - * used with control, bulk, and interrupt transfers.
- - */
- -struct fotg210_qtd {
- - /* first part defined by EHCI spec */
- - __hc32 hw_next; /* see EHCI 3.5.1 */
- - __hc32 hw_alt_next; /* see EHCI 3.5.2 */
- - __hc32 hw_token; /* see EHCI 3.5.3 */
- -#define QTD_TOGGLE (1 << 31) /* data toggle */
- -#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
- -#define QTD_IOC (1 << 15) /* interrupt on complete */
- -#define QTD_CERR(tok) (((tok)>>10) & 0x3)
- -#define QTD_PID(tok) (((tok)>>8) & 0x3)
- -#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
- -#define QTD_STS_HALT (1 << 6) /* halted on error */
- -#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
- -#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
- -#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
- -#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
- -#define QTD_STS_STS (1 << 1) /* split transaction state */
- -#define QTD_STS_PING (1 << 0) /* issue PING? */
- -
- -#define ACTIVE_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_ACTIVE)
- -#define HALT_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_HALT)
- -#define STATUS_BIT(fotg210) cpu_to_hc32(fotg210, QTD_STS_STS)
- -
- - __hc32 hw_buf[5]; /* see EHCI 3.5.4 */
- - __hc32 hw_buf_hi[5]; /* Appendix B */
- -
- - /* the rest is HCD-private */
- - dma_addr_t qtd_dma; /* qtd address */
- - struct list_head qtd_list; /* sw qtd list */
- - struct urb *urb; /* qtd's urb */
- - size_t length; /* length of buffer */
- -} __aligned(32);
- -
- -/* mask NakCnt+T in qh->hw_alt_next */
- -#define QTD_MASK(fotg210) cpu_to_hc32(fotg210, ~0x1f)
- -
- -#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
- -
- -/*-------------------------------------------------------------------------*/
- -
- -/* type tag from {qh,itd,fstn}->hw_next */
- -#define Q_NEXT_TYPE(fotg210, dma) ((dma) & cpu_to_hc32(fotg210, 3 << 1))
- -
- -/*
- - * Now the following defines are not converted using the
- - * cpu_to_le32() macro anymore, since we have to support
- - * "dynamic" switching between be and le support, so that the driver
- - * can be used on one system with SoC EHCI controller using big-endian
- - * descriptors as well as a normal little-endian PCI EHCI controller.
- - */
- -/* values for that type tag */
- -#define Q_TYPE_ITD (0 << 1)
- -#define Q_TYPE_QH (1 << 1)
- -#define Q_TYPE_SITD (2 << 1)
- -#define Q_TYPE_FSTN (3 << 1)
- -
- -/* next async queue entry, or pointer to interrupt/periodic QH */
- -#define QH_NEXT(fotg210, dma) \
- - (cpu_to_hc32(fotg210, (((u32)dma)&~0x01f)|Q_TYPE_QH))
- -
- -/* for periodic/async schedules and qtd lists, mark end of list */
- -#define FOTG210_LIST_END(fotg210) \
- - cpu_to_hc32(fotg210, 1) /* "null pointer" to hw */
- -
- -/*
- - * Entries in periodic shadow table are pointers to one of four kinds
- - * of data structure. That's dictated by the hardware; a type tag is
- - * encoded in the low bits of the hardware's periodic schedule. Use
- - * Q_NEXT_TYPE to get the tag.
- - *
- - * For entries in the async schedule, the type tag always says "qh".
- - */
- -union fotg210_shadow {
- - struct fotg210_qh *qh; /* Q_TYPE_QH */
- - struct fotg210_itd *itd; /* Q_TYPE_ITD */
- - struct fotg210_fstn *fstn; /* Q_TYPE_FSTN */
- - __hc32 *hw_next; /* (all types) */
- - void *ptr;
- -};
- -
- -/*-------------------------------------------------------------------------*/
- -
- -/*
- - * EHCI Specification 0.95 Section 3.6
- - * QH: describes control/bulk/interrupt endpoints
- - * See Fig 3-7 "Queue Head Structure Layout".
- - *
- - * These appear in both the async and (for interrupt) periodic schedules.
- - */
- -
- -/* first part defined by EHCI spec */
- -struct fotg210_qh_hw {
- - __hc32 hw_next; /* see EHCI 3.6.1 */
- - __hc32 hw_info1; /* see EHCI 3.6.2 */
- -#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */
- -#define QH_HEAD (1 << 15) /* Head of async reclamation list */
- -#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */
- -#define QH_HIGH_SPEED (2 << 12) /* Endpoint speed */
- -#define QH_LOW_SPEED (1 << 12)
- -#define QH_FULL_SPEED (0 << 12)
- -#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */
- - __hc32 hw_info2; /* see EHCI 3.6.2 */
- -#define QH_SMASK 0x000000ff
- -#define QH_CMASK 0x0000ff00
- -#define QH_HUBADDR 0x007f0000
- -#define QH_HUBPORT 0x3f800000
- -#define QH_MULT 0xc0000000
- - __hc32 hw_current; /* qtd list - see EHCI 3.6.4 */
- -
- - /* qtd overlay (hardware parts of a struct fotg210_qtd) */
- - __hc32 hw_qtd_next;
- - __hc32 hw_alt_next;
- - __hc32 hw_token;
- - __hc32 hw_buf[5];
- - __hc32 hw_buf_hi[5];
- -} __aligned(32);
- -
- -struct fotg210_qh {
- - struct fotg210_qh_hw *hw; /* Must come first */
- - /* the rest is HCD-private */
- - dma_addr_t qh_dma; /* address of qh */
- - union fotg210_shadow qh_next; /* ptr to qh; or periodic */
- - struct list_head qtd_list; /* sw qtd list */
- - struct list_head intr_node; /* list of intr QHs */
- - struct fotg210_qtd *dummy;
- - struct fotg210_qh *unlink_next; /* next on unlink list */
- -
- - unsigned unlink_cycle;
- -
- - u8 needs_rescan; /* Dequeue during giveback */
- - u8 qh_state;
- -#define QH_STATE_LINKED 1 /* HC sees this */
- -#define QH_STATE_UNLINK 2 /* HC may still see this */
- -#define QH_STATE_IDLE 3 /* HC doesn't see this */
- -#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */
- -#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
- -
- - u8 xacterrs; /* XactErr retry counter */
- -#define QH_XACTERR_MAX 32 /* XactErr retry limit */
- -
- - /* periodic schedule info */
- - u8 usecs; /* intr bandwidth */
- - u8 gap_uf; /* uframes split/csplit gap */
- - u8 c_usecs; /* ... split completion bw */
- - u16 tt_usecs; /* tt downstream bandwidth */
- - unsigned short period; /* polling interval */
- - unsigned short start; /* where polling starts */
- -#define NO_FRAME ((unsigned short)~0) /* pick new start */
- -
- - struct usb_device *dev; /* access to TT */
- - unsigned is_out:1; /* bulk or intr OUT */
- - unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
- -};
- -
- -/*-------------------------------------------------------------------------*/
- -
- -/* description of one iso transaction (up to 3 KB data if highspeed) */
- -struct fotg210_iso_packet {
- - /* These will be copied to iTD when scheduling */
- - u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */
- - __hc32 transaction; /* itd->hw_transaction[i] |= */
- - u8 cross; /* buf crosses pages */
- - /* for full speed OUT splits */
- - u32 buf1;
- -};
- -
- -/* temporary schedule data for packets from iso urbs (both speeds)
- - * each packet is one logical usb transaction to the device (not TT),
- - * beginning at stream->next_uframe
- - */
- -struct fotg210_iso_sched {
- - struct list_head td_list;
- - unsigned span;
- - struct fotg210_iso_packet packet[];
- -};
- -
- -/*
- - * fotg210_iso_stream - groups all (s)itds for this endpoint.
- - * acts like a qh would, if EHCI had them for ISO.
- - */
- -struct fotg210_iso_stream {
- - /* first field matches fotg210_hq, but is NULL */
- - struct fotg210_qh_hw *hw;
- -
- - u8 bEndpointAddress;
- - u8 highspeed;
- - struct list_head td_list; /* queued itds */
- - struct list_head free_list; /* list of unused itds */
- - struct usb_device *udev;
- - struct usb_host_endpoint *ep;
- -
- - /* output of (re)scheduling */
- - int next_uframe;
- - __hc32 splits;
- -
- - /* the rest is derived from the endpoint descriptor,
- - * trusting urb->interval == f(epdesc->bInterval) and
- - * including the extra info for hw_bufp[0..2]
- - */
- - u8 usecs, c_usecs;
- - u16 interval;
- - u16 tt_usecs;
- - u16 maxp;
- - u16 raw_mask;
- - unsigned bandwidth;
- -
- - /* This is used to initialize iTD's hw_bufp fields */
- - __hc32 buf0;
- - __hc32 buf1;
- - __hc32 buf2;
- -
- - /* this is used to initialize sITD's tt info */
- - __hc32 address;
- -};
- -
- -/*-------------------------------------------------------------------------*/
- -
- -/*
- - * EHCI Specification 0.95 Section 3.3
- - * Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
- - *
- - * Schedule records for high speed iso xfers
- - */
- -struct fotg210_itd {
- - /* first part defined by EHCI spec */
- - __hc32 hw_next; /* see EHCI 3.3.1 */
- - __hc32 hw_transaction[8]; /* see EHCI 3.3.2 */
- -#define FOTG210_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
- -#define FOTG210_ISOC_BUF_ERR (1<<30) /* Data buffer error */
- -#define FOTG210_ISOC_BABBLE (1<<29) /* babble detected */
- -#define FOTG210_ISOC_XACTERR (1<<28) /* XactErr - transaction error */
- -#define FOTG210_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff)
- -#define FOTG210_ITD_IOC (1 << 15) /* interrupt on complete */
- -
- -#define ITD_ACTIVE(fotg210) cpu_to_hc32(fotg210, FOTG210_ISOC_ACTIVE)
- -
- - __hc32 hw_bufp[7]; /* see EHCI 3.3.3 */
- - __hc32 hw_bufp_hi[7]; /* Appendix B */
- -
- - /* the rest is HCD-private */
- - dma_addr_t itd_dma; /* for this itd */
- - union fotg210_shadow itd_next; /* ptr to periodic q entry */
- -
- - struct urb *urb;
- - struct fotg210_iso_stream *stream; /* endpoint's queue */
- - struct list_head itd_list; /* list of stream's itds */
- -
- - /* any/all hw_transactions here may be used by that urb */
- - unsigned frame; /* where scheduled */
- - unsigned pg;
- - unsigned index[8]; /* in urb->iso_frame_desc */
- -} __aligned(32);
- -
- -/*-------------------------------------------------------------------------*/
- -
- -/*
- - * EHCI Specification 0.96 Section 3.7
- - * Periodic Frame Span Traversal Node (FSTN)
- - *
- - * Manages split interrupt transactions (using TT) that span frame boundaries
- - * into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN
- - * makes the HC jump (back) to a QH to scan for fs/ls QH completions until
- - * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
- - */
- -struct fotg210_fstn {
- - __hc32 hw_next; /* any periodic q entry */
- - __hc32 hw_prev; /* qh or FOTG210_LIST_END */
- -
- - /* the rest is HCD-private */
- - dma_addr_t fstn_dma;
- - union fotg210_shadow fstn_next; /* ptr to periodic q entry */
- -} __aligned(32);
- -
- -/*-------------------------------------------------------------------------*/
- -
- -/* Prepare the PORTSC wakeup flags during controller suspend/resume */
- -
- -#define fotg210_prepare_ports_for_controller_suspend(fotg210, do_wakeup) \
- - fotg210_adjust_port_wakeup_flags(fotg210, true, do_wakeup)
- -
- -#define fotg210_prepare_ports_for_controller_resume(fotg210) \
- - fotg210_adjust_port_wakeup_flags(fotg210, false, false)
- -
- -/*-------------------------------------------------------------------------*/
- -
- -/*
- - * Some EHCI controllers have a Transaction Translator built into the
- - * root hub. This is a non-standard feature. Each controller will need
- - * to add code to the following inline functions, and call them as
- - * needed (mostly in root hub code).
- - */
- -
- -static inline unsigned int
- -fotg210_get_speed(struct fotg210_hcd *fotg210, unsigned int portsc)
- -{
- - return (readl(&fotg210->regs->otgcsr)
- - & OTGCSR_HOST_SPD_TYP) >> 22;
- -}
- -
- -/* Returns the speed of a device attached to a port on the root hub. */
- -static inline unsigned int
- -fotg210_port_speed(struct fotg210_hcd *fotg210, unsigned int portsc)
- -{
- - switch (fotg210_get_speed(fotg210, portsc)) {
- - case 0:
- - return 0;
- - case 1:
- - return USB_PORT_STAT_LOW_SPEED;
- - case 2:
- - default:
- - return USB_PORT_STAT_HIGH_SPEED;
- - }
- -}
- -
- -/*-------------------------------------------------------------------------*/
- -
- -#define fotg210_has_fsl_portno_bug(e) (0)
- -
- -/*
- - * While most USB host controllers implement their registers in
- - * little-endian format, a minority (celleb companion chip) implement
- - * them in big endian format.
- - *
- - * This attempts to support either format at compile time without a
- - * runtime penalty, or both formats with the additional overhead
- - * of checking a flag bit.
- - *
- - */
- -
- -#define fotg210_big_endian_mmio(e) 0
- -#define fotg210_big_endian_capbase(e) 0
- -
- -static inline unsigned int fotg210_readl(const struct fotg210_hcd *fotg210,
- - __u32 __iomem *regs)
- -{
- - return readl(regs);
- -}
- -
- -static inline void fotg210_writel(const struct fotg210_hcd *fotg210,
- - const unsigned int val, __u32 __iomem *regs)
- -{
- - writel(val, regs);
- -}
- -
- -/* cpu to fotg210 */
- -static inline __hc32 cpu_to_hc32(const struct fotg210_hcd *fotg210, const u32 x)
- -{
- - return cpu_to_le32(x);
- -}
- -
- -/* fotg210 to cpu */
- -static inline u32 hc32_to_cpu(const struct fotg210_hcd *fotg210, const __hc32 x)
- -{
- - return le32_to_cpu(x);
- -}
- -
- -static inline u32 hc32_to_cpup(const struct fotg210_hcd *fotg210,
- - const __hc32 *x)
- -{
- - return le32_to_cpup(x);
- -}
- -
- -/*-------------------------------------------------------------------------*/
- -
- -static inline unsigned fotg210_read_frame_index(struct fotg210_hcd *fotg210)
- -{
- - return fotg210_readl(fotg210, &fotg210->regs->frame_index);
- -}
- -
- -/*-------------------------------------------------------------------------*/
- -
- -#endif /* __LINUX_FOTG210_H */
|