1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380 |
- /*
- * Copyright 2013-2014 Andrew Smith - BlackArrow Ltd
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version. See COPYING for more details.
- */
- #include "config.h"
- #include "compat.h"
- #include "miner.h"
- #include "klist.h"
- #include <ctype.h>
- #include <math.h>
- #ifndef LINUX
- static void minion_detect(__maybe_unused bool hotplug)
- {
- }
- #else
- #include <unistd.h>
- #include <linux/spi/spidev.h>
- #include <sys/ioctl.h>
- #include <sys/stat.h>
- #include <sys/mman.h>
- #include <fcntl.h>
- #include <poll.h>
- // Define this to 1 to enable interrupt code and enable no_nonce
- #define ENABLE_INT_NONO 0
- // Define this to 1 if compiling on RockChip and not on RPi
- #define MINION_ROCKCHIP 0
- // The code is always in - this just decides if it does it
- static bool minreread = false;
- #if MINION_ROCKCHIP == 1
- #define MINION_POWERCYCLE_GPIO 173
- #define MINION_CHIP_OFF "1"
- #define MINION_CHIP_ON "0"
- #define MINION_CHIP_DELAY 100
- #endif
- // Power cycle if the xff_list is full and the tail is less than
- // this long ago
- #define MINION_POWER_TIME 60
- /*
- * Use pins for board selection
- * If disabled, it will test chips just as 'pin 0'
- * but never do any gpio - the equivalent of the previous 'no pins' code
- */
- static bool usepins = false;
- #define MINION_PAGE_SIZE 4096
- #define BCM2835_BASE 0x20000000
- #define BCM2835_GPIO_BASE (BCM2835_BASE + 0x200000)
- #define BCM2835_GPIO_SET0 0x001c // GPIO Pin Output Set 0
- #define BCM2835_GPIO_CLR0 0x0028 // GPIO Pin Output Clear 0
- #define BCM2835_GPIO_FSEL0 0x0000
- #define BCM2835_GPIO_FSEL_INPUT 0b000
- #define BCM2835_GPIO_FSEL_OUTPUT 0b001
- #define BCM2835_GPIO_FSEL_MASK 0b111
- #define BCM2835_PIN_HIGH 0x1
- #define BCM2835_PIN_LOW 0x0
- static const char *minion_memory = "/dev/mem";
- static int minion_memory_addr = BCM2835_GPIO_BASE;
- #define MINION_SPI_BUS 0
- #define MINION_SPI_CHIP 0
- #if MINION_ROCKCHIP == 0
- #define MINION_SPI_SPEED 8000000
- #else
- #define MINION_SPI_SPEED 500000
- #endif
- #define MINION_SPI_BUFSIZ 1024
- static struct minion_select_pins {
- int pin;
- int wpi;
- char *name;
- int bcm; // this is what we use
- } minionPins[] = {
- { 24, 10, "CE0", 8, },
- { 26, 11, "CE1", 7, },
- { 16, 4, "GPIO4", 23, },
- { 22, 6, "GPIO6", 25, },
- { 12, 1, "GPIO1", 18, },
- { 18, 5, "GPIO5", 24, },
- { 11, 0, "GPIO0", 17, },
- { 13, 2, "GPIO2", 27, },
- { 15, 3, "GPIO3", 22, },
- { 7, 7, "GPIO7", 4, }
- /* The rest on the RPi
- { 3, 8, "SDA", 2, }
- { 5, 9, "SCL", 3, }
- { 19, 12, "MOSI", 10, }
- { 21, 13, "MISO", 9, }
- { 23, 14, "SCLK", 11, }
- { 8, 15, "TxD", 14, }
- { 10, 16, "RxD", 15, }
- */
- };
- /*
- * uS delays for GPIO pin access
- */
- #define MINION_PIN_BEFORE cgsleep_us(33)
- #define MINION_PIN_SLEEP cgsleep_us(133)
- #define MINION_PIN_AFTER
- #define MINION_PIN_COUNT (sizeof(minionPins)/ \
- sizeof(struct minion_select_pins))
- #define CHIP_PIN(_chip) (minioninfo->chip_pin[_chip])
- #define MINION_MIN_CHIP 0
- #define MINION_MAX_CHIP 11
- #define MINION_CHIP_PER_PIN (1 + MINION_MAX_CHIP - MINION_MIN_CHIP)
- #define MINION_CHIPS (MINION_PIN_COUNT * MINION_CHIP_PER_PIN)
- #define MINION_CORES 99
- #define FAKE_CORE MINION_CORES
- /*
- * TODO: These will need adjusting for final hardware
- * Look them up and calculate them?
- */
- #define MINION_QUE_MAX 64
- #define MINION_QUE_HIGH 48
- #define MINION_QUE_SEND 16
- #define MINION_QUE_LOW 8
- #define MINION_FFL " - from %s %s() line %d"
- #define MINION_FFL_HERE __FILE__, __func__, __LINE__
- #define MINION_FFL_PASS file, func, line
- #define MINION_FFL_ARGS __maybe_unused const char *file, \
- __maybe_unused const char *func, \
- __maybe_unused const int line
- #define minion_txrx(_task) _minion_txrx(minioncgpu, minioninfo, _task, MINION_FFL_HERE)
- #define MINION_SYS_REGS 0x00
- #define MINION_CORE_REGS 0x10
- #define MINION_RES_BUF 0x20
- #define MINION_CMD_QUE 0x30
- #define MINION_NONCE_RANGES 0x70
- #define DATA_SIZ (sizeof(uint32_t))
- // All SYS data sizes are DATA_SIZ
- #define MINION_SYS_CHIP_SIG 0x00
- #define MINION_SYS_CHIP_STA 0x01
- #define MINION_SYS_SPI_LED 0x02
- #define MINION_SYS_TEMP_CTL 0x03
- #define MINION_SYS_FREQ_CTL 0x04
- #define MINION_SYS_NONCE_LED 0x05
- #define MINION_SYS_MISC_CTL 0x06
- #define MINION_SYS_RSTN_CTL 0x07
- #define MINION_SYS_INT_ENA 0x08
- #define MINION_SYS_INT_CLR 0x09
- #define MINION_SYS_INT_STA 0x0a
- #define MINION_SYS_FIFO_STA 0x0b
- #define MINION_SYS_QUE_TRIG 0x0c
- #define MINION_SYS_BUF_TRIG 0x0d
- #define MINION_SYS_IDLE_CNT 0x0e
- // How many 32 bit reports make up all the cores - 99 cores = 4 reps
- #define MINION_CORE_REPS (int)((((MINION_CORES-1) >> 5) & 0xff) + 1)
- // All SYS data sizes are DATA_SIZ
- #define MINION_SYS_SIZ DATA_SIZ
- // Header Pin 18 = GPIO5 = BCM 24
- #define MINION_GPIO_RESULT_INT_PIN 24
- // RockChip is pin 172 ...
- #define MINION_GPIO_SYS "/sys/class/gpio"
- #define MINION_GPIO_ENA "/export"
- #define MINION_GPIO_ENA_VAL "%d"
- #define MINION_GPIO_DIS "/unexport"
- #define MINION_GPIO_PIN "/gpio%d"
- #define MINION_GPIO_DIR "/direction"
- #define MINION_GPIO_DIR_READ "in"
- #define MINION_GPIO_DIR_WRITE "out"
- #define MINION_GPIO_EDGE "/edge"
- #define MINION_GPIO_EDGE_NONE "none"
- #define MINION_GPIO_EDGE_RISING "rising"
- #define MINION_GPIO_EDGE_FALLING "falling"
- #define MINION_GPIO_EDGE_BOTH "both"
- #define MINION_GPIO_ACT "/active_low"
- #define MINION_GPIO_ACT_LO "1"
- #define MINION_GPIO_ACT_HI "0"
- #define MINION_GPIO_VALUE "/value"
- #define MINION_RESULT_INT 0x01
- #define MINION_RESULT_FULL_INT 0x02
- #define MINION_CMD_INT 0x04
- #define MINION_CMD_FULL_INT 0x08
- #define MINION_TEMP_LOW_INT 0x10
- #define MINION_TEMP_HI_INT 0x20
- #define MINION_ALL_INT MINION_RESULT_INT | \
- MINION_RESULT_FULL_INT | \
- MINION_CMD_INT | \
- MINION_CMD_FULL_INT | \
- MINION_TEMP_LOW_INT | \
- MINION_TEMP_HI_INT
- #define RSTN_CTL_RESET_CORES 0x01
- #define RSTN_CTL_FLUSH_RESULTS 0x02
- #define RSTN_CTL_FLUSH_CMD_QUEUE 0x04
- #define RSTN_CTL_SPI_SW_RSTN 0x08
- #define RSTN_CTL_SHA_MGR_RESET 0x10
- // Init
- #define SYS_RSTN_CTL_INIT (RSTN_CTL_RESET_CORES | \
- RSTN_CTL_FLUSH_RESULTS | \
- RSTN_CTL_FLUSH_CMD_QUEUE | \
- RSTN_CTL_SPI_SW_RSTN | \
- RSTN_CTL_SHA_MGR_RESET)
- // Block change
- #define SYS_RSTN_CTL_FLUSH (RSTN_CTL_RESET_CORES | \
- RSTN_CTL_SPI_SW_RSTN | \
- RSTN_CTL_FLUSH_CMD_QUEUE)
- #if ENABLE_INT_NONO
- // enable 'no nonce' report
- #define SYS_MISC_CTL_DEFAULT 0x04
- #else
- #define SYS_MISC_CTL_DEFAULT 0x00
- #endif
- // Temperature returned by MINION_SYS_CHIP_STA 0x01 STA_TEMP()
- #define MINION_TEMP_40 0
- #define MINION_TEMP_60 1
- #define MINION_TEMP_80 3
- #define MINION_TEMP_100 7
- #define MINION_TEMP_OVER 15
- static const char *min_temp_40 = "<40";
- static const char *min_temp_60 = "40-60";
- static const char *min_temp_80 = "60-80";
- static const char *min_temp_100 = "80-100";
- static const char *min_temp_over = ">100";
- static const char *min_temp_invalid = "?";
- /*
- * Temperature for MINION_SYS_TEMP_CTL 0x03 temp_thres [0:3]
- * i.e. it starts at 120 and goes up in steps of 5 to 160
- */
- #define MINION_TEMP_CTL_MIN 1
- #define MINION_TEMP_CTL_MAX 9
- #define MINION_TEMP_CTL_BITS 0x0f
- #define MINION_TEMP_CTL_DEF 135
- #define MINION_TEMP_CTL_STEP 5
- #define MINION_TEMP_CTL_MIN_VALUE 120
- #define MINION_TEMP_CTL_MAX_VALUE (MINION_TEMP_CTL_MIN_VALUE + \
- (MINION_TEMP_CTL_STEP * \
- (MINION_TEMP_CTL_MAX - MINION_TEMP_CTL_MIN)))
- #define MINION_TEMP_DISABLE "disable"
- #define MINION_TEMP_CTL_DISABLE -1
- #define MINION_TEMP_CTL_DISABLE_VALUE 0x20
- // CORE data size is DATA_SIZ
- #define MINION_CORE_ENA0_31 0x10
- #define MINION_CORE_ENA32_63 0x11
- #define MINION_CORE_ENA64_95 0x12
- #define MINION_CORE_ENA96_98 0x13
- #define MINION_CORE_ACT0_31 0x14
- #define MINION_CORE_ACT32_63 0x15
- #define MINION_CORE_ACT64_95 0x16
- #define MINION_CORE_ACT96_98 0x17
- // All CORE data sizes are DATA_SIZ
- #define MINION_CORE_SIZ DATA_SIZ
- #define MINION_CORE_ALL "all"
- // RES data size is minion_result
- #define MINION_RES_DATA 0x20
- #define MINION_RES_PEEK 0x21
- // QUE data size is minion_que
- #define MINION_QUE_0 0x30
- #define MINION_QUE_R 0x31
- // RANGE data sizes are DATA_SIZ
- #define MINION_NONCE_START 0x70
- #define MINION_NONCE_RANGE 0x71
- // This must be >= max txsiz + max rxsiz
- #define MINION_BUFSIZ 1024
- #define u8tou32(_c, _off) (((uint8_t *)(_c))[(_off)+0] + \
- ((uint8_t *)(_c))[(_off)+1] * 0x100 + \
- ((uint8_t *)(_c))[(_off)+2] * 0x10000 + \
- ((uint8_t *)(_c))[(_off)+3] * 0x1000000 )
- #define MINION_ADDR_WRITE 0x7f
- #define MINION_ADDR_READ 0x80
- #define READ_ADDR(_reg) ((_reg) | MINION_ADDR_READ)
- #define WRITE_ADDR(_reg) ((_reg) & MINION_ADDR_WRITE)
- #define IS_ADDR_READ(_reg) (((_reg) & MINION_ADDR_READ) == MINION_ADDR_READ)
- #define IS_ADDR_WRITE(_reg) (((_reg) & MINION_ADDR_READ) == 0)
- #define SET_HEAD_WRITE(_h, _reg) ((_h)->reg) = WRITE_ADDR(_reg)
- #define SET_HEAD_READ(_h, _reg) ((_h)->reg) = READ_ADDR(_reg)
- #define SET_HEAD_SIZ(_h, _siz) \
- do { \
- ((_h)->siz)[0] = (uint8_t)((_siz) & 0xff); \
- ((_h)->siz)[1] = (uint8_t)(((_siz) & 0xff00) >> 8); \
- } while (0)
- struct minion_header {
- uint8_t chipid;
- uint8_t reg;
- uint8_t siz[2];
- uint8_t data[4]; // placeholder
- };
- #define HSIZE() (sizeof(struct minion_header) - 4)
- #define MINION_NOCHIP_SIG 0x00000000
- #define MINION_NOCHIP_SIG2 0xffffffff
- #define MINION_CHIP_SIG 0xb1ac8a44
- /*
- * Number of times to try and get the SIG with each chip,
- * if the chip returns neither of the above values
- * TODO: maybe need some reset between tries, to handle a shift value?
- */
- #define MINION_SIG_TRIES 3
- /*
- * TODO: Finding these means the chip is there - but how to fix it?
- * The extra &'s are to ensure there is no sign bit issue since
- * the sign bit carry in a C bit-shift is compiler dependent
- */
- #define MINION_CHIP_SIG_SHIFT1 (((MINION_CHIP_SIG & 0x0000ffff) << 16) & 0xffff0000)
- #define MINION_CHIP_SIG_SHIFT2 (((MINION_CHIP_SIG & 0x00ffffff) << 8) & 0xffffff00)
- #define MINION_CHIP_SIG_SHIFT3 (((MINION_CHIP_SIG & 0xffffff00) >> 8) & 0x00ffffff)
- #define MINION_CHIP_SIG_SHIFT4 (((MINION_CHIP_SIG & 0xffff0000) >> 16) & 0x0000ffff)
- #define MINION_SPI_LED_ON 0xa5a5
- #define MINION_SPI_LED_OFF 0x0
- // Time since first nonce/last reset before turning on the LED
- #define MINION_LED_TEST_TIME 600
- #define MINION_FREQ_MIN 100
- #define MINION_FREQ_DEF 1200
- #define MINION_FREQ_MAX 1400
- #define MINION_FREQ_FACTOR 100
- #define MINION_FREQ_RESET_STEP MINION_FREQ_FACTOR
- #define MINION_FREQ_FACTOR_MIN 1
- #define MINION_FREQ_FACTOR_MAX 14
- static uint32_t minion_freq[] = {
- 0x0,
- 0x205032, // 1 = 100Mhz
- 0x203042, // 2 = 200Mhz
- 0x20204B, // 3 = 300Mhz
- 0x201042, // 4 = 400Mhz
- 0x201053, // 5 = 500Mhz
- 0x200032, // 6 = 600Mhz
- 0x20003A, // 7 = 700Mhz
- 0x200042, // 8 = 800Mhz
- 0x20004B, // 9 = 900Mhz
- 0x200053, // 10 = 1000Mhz
- 0x21005B, // 11 = 1100Mhz
- 0x210064, // 12 = 1200Mhz
- 0x21006C, // 13 = 1300Mhz
- 0x210074 // 14 = 1400Mhz
- };
- // When hash rate falls below this in the history hash rate, reset it
- #define MINION_RESET_PERCENT 75.0
- // When hash rate falls below this after the longer test time
- #define MINION_RESET2_PERCENT 85.0
- // After the above resets, delay sending work for:
- #define MINION_RESET_DELAY_s 0.088
- #define STA_TEMP(_sta) ((uint16_t)((_sta)[3] & 0x1f))
- #define STA_CORES(_sta) ((uint16_t)((_sta)[2]))
- #define STA_FREQ(_sta) ((uint32_t)((_sta)[1]) * 0x100 + (uint32_t)((_sta)[0]))
- // Randomly between 1s and 2s per chip
- #define MINION_STATS_UPDATE_TIME_mS 1000
- #define MINION_STATS_UPDATE_RAND_mS 1000
- // Don't report it more than once every ... 5s
- #define MINION_IDLE_MESSAGE_ms 5000
- struct minion_status {
- uint16_t temp;
- uint16_t cores;
- uint32_t freq;
- uint32_t quework;
- uint32_t chipwork;
- uint32_t realwork; // FIFO_STA
- struct timeval last;
- bool overheat;
- bool islow;
- bool tohigh;
- int lowcount;
- uint32_t overheats;
- struct timeval lastoverheat;
- struct timeval lastrecover;
- double overheattime;
- uint32_t tempsent;
- uint32_t idle;
- uint32_t last_rpt_idle;
- struct timeval idle_rpt;
- struct timeval first_nonce;
- uint64_t from_first_good;
- };
- #define ENABLE_CORE(_core, _n) ((_core[_n >> 3]) |= (1 << (_n % 8)))
- #define CORE_IDLE(_core, _n) ((_core[_n >> 3]) & (1 << (_n % 8)))
- #define FIFO_RES(_fifo, _off) ((_fifo)[(_off) + 0])
- #define FIFO_CMD(_fifo, _off) ((_fifo)[(_off) + 1])
- #define RES_GOLD(_res) ((((_res)->status[3]) & 0x80) == 0)
- #define RES_CHIPID(_res) (((_res)->status[3]) & 0x1f)
- #define RES_CORE(_res) ((_res)->status[2])
- #define RES_TASK(_res) ((int)((_res)->status[1]) * 0x100 + (int)((_res)->status[0]))
- #define RES_NONCE(_res) u8tou32((_res)->nonce, 0)
- /*
- * This is only valid since we avoid using task_id 0 for work
- * However, it isn't really necessary since we only request
- * the number of results the result buffer says it has
- * However, it is a simple failsafe
- */
- #define IS_RESULT(_res) ((_res)->status[1] || (_res)->status[0])
- struct minion_result {
- uint8_t status[DATA_SIZ];
- uint8_t nonce[DATA_SIZ];
- };
- #define MINION_RES_DATA_SIZ sizeof(struct minion_result)
- /*
- * (MINION_SPI_BUFSIZ - HSIZE()) / MINION_RES_DATA_SIZ
- * less a little bit to round it out
- */
- #define MINION_MAX_RES 120
- #define MIDSTATE_BYTES 32
- #define MERKLE7_OFFSET 64
- #define MERKLE_BYTES 12
- #define MINION_MAX_TASK_ID 0xffff
- struct minion_que {
- uint8_t task_id[2];
- uint8_t reserved[2];
- uint8_t midstate[MIDSTATE_BYTES];
- uint8_t merkle7[DATA_SIZ];
- uint8_t ntime[DATA_SIZ];
- uint8_t bits[DATA_SIZ];
- };
- /*
- * Max time to wait before checking the task list
- * Required, since only urgent tasks trigger an immediate check
- * TODO: ? for 2TH/s
- */
- #define MINION_TASK_mS 8
- /*
- * Max time to wait before checking the result list for nonces
- * This can be long since it's only a failsafe
- * cgsem_post is always sent if there are nonces ready to check
- */
- #define MINION_NONCE_mS 888
- // Number of results to make a GPIO interrupt
- //#define MINION_RESULT_INT_SIZE 1
- #define MINION_RESULT_INT_SIZE 2
- /*
- * Max time to wait before checking for results
- * The interrupt doesn't occur until MINION_RESULT_INT_SIZE results are found
- * See comment in minion_spi_reply() at poll()
- */
- #define MINION_REPLY_mS 88
- /*
- * Max time to wait before returning the amount of work done
- * A result interrupt will send a trigger for this also
- * See comment in minion_scanwork()
- * This avoids the cgminer master work loop spinning doing nothing
- */
- #define MINION_SCAN_mS 88
- // *** Work lists: generated, queued for a chip, sent to chip
- typedef struct work_item {
- struct work *work;
- uint32_t task_id;
- struct timeval sent;
- int nonces;
- bool urgent;
- bool stale; // if stale, don't decrement que/chipwork when discarded
- bool rolled;
- int errors; // uncertain since the error could mean task_id is wrong
- struct timeval created; // when work was generated
- uint64_t ioseq;
- } WORK_ITEM;
- #define ALLOC_WORK_ITEMS 4096
- #define LIMIT_WORK_ITEMS 0
- // *** Task queue ready to be sent
- typedef struct task_item {
- uint64_t tid;
- uint8_t chip;
- bool write;
- uint8_t address;
- uint32_t task_id;
- uint32_t wsiz;
- uint32_t osiz;
- uint32_t rsiz;
- uint8_t wbuf[MINION_BUFSIZ];
- uint8_t obuf[MINION_BUFSIZ];
- uint8_t rbuf[MINION_BUFSIZ];
- int reply;
- bool urgent;
- uint8_t work_state;
- struct work *work;
- K_ITEM *witem;
- uint64_t ioseq;
- } TASK_ITEM;
- #define ALLOC_TASK_ITEMS 256
- #define LIMIT_TASK_ITEMS 0
- // *** Results queue ready to be checked
- typedef struct res_item {
- int chip;
- int core;
- uint32_t task_id;
- uint32_t nonce;
- struct timeval when;
- /*
- * Only once per task_id if no nonces were found
- * Sent with core = 0
- * However, currently it always sends it at the end of every task
- * TODO: code assumes it doesn't - change later when we
- * see what the final hardware does (minor code performance gain)
- */
- bool no_nonce;
- // If we requested the result twice:
- bool another;
- uint32_t task_id2;
- uint32_t nonce2;
- } RES_ITEM;
- #define ALLOC_RES_ITEMS 256
- #define LIMIT_RES_ITEMS 0
- // *** Per chip nonce history
- typedef struct hist_item {
- struct timeval when;
- } HIST_ITEM;
- #define ALLOC_HIST_ITEMS 4096
- #define LIMIT_HIST_ITEMS 0
- // How much history to keep (5min)
- #define MINION_HISTORY_s 300
- // History required to decide a reset at MINION_FREQ_DEF Mhz
- #define MINION_RESET_s 10
- // How many times to reset before changing Freq
- // This doesn't include the secondary higher % check
- #define MINION_RESET_COUNT 6
- // To enable the 2nd check
- static bool second_check = true;
- // Longer time lapse to expect the higher %
- // This intercepts a slow GHs drop earlier
- #define MINION_RESET2_s 60
- #if (MINION_RESET_s > MINION_HISTORY_s)
- #error "MINION_RESET_s can't be greater than MINION_HISTORY_s"
- #endif
- #define FREQ_DELAY(freq) ((float)(MINION_RESET_s * MINION_FREQ_DEF) / (freq))
- #if (MINION_RESET2_s > MINION_HISTORY_s)
- #error "MINION_RESET2_s can't be greater than MINION_HISTORY_s"
- #endif
- // FREQ2_DELAY(MINION_FREQ_MIN) = FREQ2_FACTOR * MINION_RESET2_s
- #define FREQ2_FACTOR 1.5
- #define FREQ2_DELAY(freq) ((1.0 + (float)((freq - MINION_FREQ_DEF) * (1 - FREQ2_FACTOR)) / \
- (float)(MINION_FREQ_DEF - MINION_FREQ_MIN)) * MINION_RESET2_s)
- #if (MINION_RESET2_s <= MINION_RESET_s)
- #error "MINION_RESET2_s must be greater than MINION_RESET_s"
- #endif
- /* If there was no reset for this long, clear the reset history
- * (except the last one) since this means the current clock is ok
- * with rare resets */
- #define MINION_CLR_s 300
- #if (MINION_CLR_s <= MINION_RESET2_s)
- #error "MINION_CLR_s must be greater than MINION_RESET2_s"
- #endif
- // History must be always generated for the reset check
- #define MINION_MAX_RESET_CHECK 2
- /* Floating point reset settings required for the code to work properly
- * Basically: RESET2 must be after RESET and CLR must be after RESET2 */
- static void define_test()
- {
- float test;
- if (MINION_RESET2_PERCENT <= MINION_RESET_PERCENT) {
- quithere(1, "MINION_RESET2_PERCENT=%f must be "
- "> MINION_RESET_PERCENT=%f",
- MINION_RESET2_PERCENT, MINION_RESET_PERCENT);
- }
- test = FREQ_DELAY(MINION_FREQ_MIN);
- if (test >= MINION_HISTORY_s) {
- quithere(1, "FREQ_DELAY(MINION_FREQ_MIN)=%f must be "
- "< MINION_HISTORY_s=%d",
- test, MINION_HISTORY_s);
- }
- if (MINION_CLR_s <= test) {
- quithere(1, "MINION_CLR_s=%d must be > "
- "FREQ_DELAY(MINION_FREQ_MIN)=%f",
- MINION_CLR_s, test);
- }
- if (FREQ2_FACTOR <= 1.0)
- quithere(1, "FREQ2_FACTOR=%f must be > 1.0", FREQ2_FACTOR);
- test = FREQ2_DELAY(MINION_FREQ_MIN);
- if (test >= MINION_HISTORY_s) {
- quithere(1, "FREQ2_DELAY(MINION_FREQ_MIN)=%f must be "
- "< MINION_HISTORY_s=%d",
- test, MINION_HISTORY_s);
- }
- if (MINION_CLR_s <= test) {
- quithere(1, "MINION_CLR_s=%d must be > "
- "FREQ2_DELAY(MINION_FREQ_MIN)=%f",
- MINION_CLR_s, test);
- }
- }
- // *** Chip freq/MHs performance history
- typedef struct perf_item {
- double elapsed;
- uint64_t nonces;
- uint32_t freq;
- double ghs;
- struct timeval when;
- } PERF_ITEM;
- #define ALLOC_PERF_ITEMS 128
- #define LIMIT_PERF_ITEMS 0
- // *** 0xff error history
- typedef struct xff_item {
- time_t when;
- } XFF_ITEM;
- #define ALLOC_XFF_ITEMS 100
- #define LIMIT_XFF_ITEMS 100
- #define DATA_WORK(_item) ((WORK_ITEM *)(_item->data))
- #define DATA_TASK(_item) ((TASK_ITEM *)(_item->data))
- #define DATA_RES(_item) ((RES_ITEM *)(_item->data))
- #define DATA_HIST(_item) ((HIST_ITEM *)(_item->data))
- #define DATA_PERF(_item) ((PERF_ITEM *)(_item->data))
- #define DATA_XFF(_item) ((XFF_ITEM *)(_item->data))
- // Set this to 1 to enable iostats processing
- // N.B. it slows down mining
- #define DO_IO_STATS 0
- #if DO_IO_STATS
- #define IO_STAT_NOW(_tv) cgtime(_tv)
- #define IO_STAT_STORE(_sta, _fin, _lsta, _lfin, _tsd, _buf, _siz, _reply, _ioc) \
- do { \
- double _diff, _ldiff, _lwdiff, _1time; \
- int _off; \
- _diff = us_tdiff(_fin, _sta); \
- _ldiff = us_tdiff(_lfin, _lsta); \
- _lwdiff = us_tdiff(_sta, _lsta); \
- _1time = us_tdiff(_tsd, _lfin); \
- _off = (int)(_buf[1]) + (_reply >= 0 ? 0 : 0x100); \
- minioninfo->summary.count++; \
- minioninfo->summary.tsd += _1time; \
- minioninfo->iostats[_off].count++; \
- minioninfo->iostats[_off].tsd += _1time; \
- if (_diff <= 0) { \
- minioninfo->summary.zero_delay++; \
- minioninfo->iostats[_off].zero_delay++; \
- } else { \
- minioninfo->summary.total_delay += _diff; \
- if (minioninfo->summary.max_delay < _diff) \
- minioninfo->summary.max_delay = _diff; \
- if (minioninfo->summary.min_delay == 0 || \
- minioninfo->summary.min_delay > _diff) \
- minioninfo->summary.min_delay = _diff; \
- minioninfo->iostats[_off].total_delay += _diff; \
- if (minioninfo->iostats[_off].max_delay < _diff) \
- minioninfo->iostats[_off].max_delay = _diff; \
- if (minioninfo->iostats[_off].min_delay == 0 || \
- minioninfo->iostats[_off].min_delay > _diff) \
- minioninfo->iostats[_off].min_delay = _diff; \
- } \
- if (_ldiff <= 0) { \
- minioninfo->summary.zero_dlock++; \
- minioninfo->iostats[_off].zero_dlock++; \
- } else { \
- minioninfo->summary.total_dlock += _ldiff; \
- if (minioninfo->summary.max_dlock < _ldiff) \
- minioninfo->summary.max_dlock = _ldiff; \
- if (minioninfo->summary.min_dlock == 0 || \
- minioninfo->summary.min_dlock > _ldiff) \
- minioninfo->summary.min_dlock = _ldiff; \
- minioninfo->iostats[_off].total_dlock += _ldiff; \
- if (minioninfo->iostats[_off].max_dlock < _ldiff) \
- minioninfo->iostats[_off].max_dlock = _ldiff; \
- if (minioninfo->iostats[_off].min_dlock == 0 || \
- minioninfo->iostats[_off].min_dlock > _ldiff) \
- minioninfo->iostats[_off].min_dlock = _ldiff; \
- } \
- minioninfo->summary.total_dlwait += _lwdiff; \
- minioninfo->iostats[_off].total_dlwait += _lwdiff; \
- if (_siz == 0) { \
- minioninfo->summary.zero_bytes++; \
- minioninfo->iostats[_off].zero_bytes++; \
- } else { \
- minioninfo->summary.total_bytes += _siz; \
- if (minioninfo->summary.max_bytes < _siz) \
- minioninfo->summary.max_bytes = _siz; \
- if (minioninfo->summary.min_bytes == 0 || \
- minioninfo->summary.min_bytes > _siz) \
- minioninfo->summary.min_bytes = _siz; \
- minioninfo->iostats[_off].total_bytes += _siz; \
- if (minioninfo->iostats[_off].max_bytes < _siz) \
- minioninfo->iostats[_off].max_bytes = _siz; \
- if (minioninfo->iostats[_off].min_bytes == 0 || \
- minioninfo->iostats[_off].min_bytes > _siz) \
- minioninfo->iostats[_off].min_bytes = _siz; \
- } \
- } while (0);
- typedef struct iostat {
- uint64_t count; // total ioctl()
- double total_delay; // total elapsed ioctl()
- double min_delay;
- double max_delay;
- uint64_t zero_delay; // how many had <= 0 delay
- // Above but including locking
- double total_dlock;
- double min_dlock;
- double max_dlock;
- uint64_t zero_dlock;
- // Total time waiting to get lock
- double total_dlwait;
- // these 3 fields are ignored for now since all are '1'
- uint64_t total_ioc; // SPI_IOC_MESSAGE(x)
- uint64_t min_ioc;
- uint64_t max_ioc;
- uint64_t total_bytes; // ioctl() bytes
- uint64_t min_bytes;
- uint64_t max_bytes;
- uint64_t zero_bytes; // how many had siz == 0
- double tsd; // total doing one extra cgtime() each time
- } IOSTAT;
- #else
- #define IO_STAT_NOW(_tv)
- #define IO_STAT_STORE(_sta, _fin, _lsta, _lfin, _tsd, _buf, _siz, _reply, _ioc)
- #endif
- static double time_bands[] = { 0.1, 0.5, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0 };
- #define TIME_BANDS ((int)(sizeof(time_bands)/sizeof(double)))
- struct minion_info {
- struct thr_info *thr;
- struct thr_info spiw_thr;
- struct thr_info spir_thr;
- struct thr_info res_thr;
- pthread_mutex_t spi_lock;
- pthread_mutex_t sta_lock;
- cgsem_t task_ready;
- cgsem_t nonce_ready;
- cgsem_t scan_work;
- volatile unsigned *gpio;
- int spifd;
- char gpiointvalue[64];
- int gpiointfd;
- // I/O or seconds
- bool spi_reset_io;
- int spi_reset_count;
- time_t last_spi_reset;
- uint64_t spi_resets;
- // TODO: need to track disabled chips - done?
- int chips;
- bool has_chip[MINION_CHIPS];
- int init_temp[MINION_CHIPS];
- uint8_t init_cores[MINION_CHIPS][DATA_SIZ*MINION_CORE_REPS];
- uint8_t chipid[MINION_CHIPS]; // Chip Number
- int chip_pin[MINION_CHIPS];
- uint64_t ioseq;
- uint32_t next_task_id;
- // Stats
- uint64_t chip_nonces[MINION_CHIPS];
- uint64_t chip_nononces[MINION_CHIPS];
- uint64_t chip_good[MINION_CHIPS];
- uint64_t chip_bad[MINION_CHIPS];
- uint64_t chip_err[MINION_CHIPS];
- uint64_t chip_dup[MINION_CHIPS];
- uint64_t core_good[MINION_CHIPS][MINION_CORES+1];
- uint64_t core_bad[MINION_CHIPS][MINION_CORES+1];
- uint32_t chip_core_ena[MINION_CORE_REPS][MINION_CHIPS];
- uint32_t chip_core_act[MINION_CORE_REPS][MINION_CHIPS];
- struct minion_status chip_status[MINION_CHIPS];
- uint64_t interrupts;
- uint64_t result_interrupts;
- uint64_t command_interrupts;
- char last_interrupt[64];
- pthread_mutex_t nonce_lock;
- uint64_t new_nonces;
- uint64_t ok_nonces;
- uint64_t untested_nonces;
- uint64_t tested_nonces;
- uint64_t work_unrolled;
- uint64_t work_rolled;
- uint64_t spi_errors;
- uint64_t fifo_spi_errors[MINION_CHIPS];
- uint64_t res_spi_errors[MINION_CHIPS];
- uint64_t use_res2[MINION_CHIPS];
- uint64_t tasks_failed[MINION_CHIPS];
- uint64_t tasks_recovered[MINION_CHIPS];
- uint64_t nonces_failed[MINION_CHIPS];
- uint64_t nonces_recovered[MINION_CHIPS];
- struct timeval last_reset[MINION_CHIPS];
- double do_reset[MINION_CHIPS];
- bool flag_reset[MINION_CHIPS];
- // Work items
- K_LIST *wfree_list;
- K_STORE *wwork_list;
- K_STORE *wstale_list;
- K_STORE *wque_list[MINION_CHIPS];
- K_STORE *wchip_list[MINION_CHIPS];
- uint64_t wwork_flushed;
- uint64_t wque_flushed;
- uint64_t wchip_staled;
- // Task list
- K_LIST *tfree_list;
- K_STORE *task_list;
- K_STORE *treply_list;
- uint64_t next_tid;
- // Nonce replies
- K_LIST *rfree_list;
- K_STORE *rnonce_list;
- struct timeval last_did;
- // Nonce history
- K_LIST *hfree_list;
- K_STORE *hchip_list[MINION_CHIPS];
- int history_gen;
- struct timeval chip_chk;
- struct timeval chip_rpt;
- double history_ghs[MINION_CHIPS];
- // Point in history for MINION_RESET_s
- int reset_time[MINION_CHIPS];
- K_ITEM *reset_mark[MINION_CHIPS];
- int reset_count[MINION_CHIPS];
- // Point in history for MINION_RESET2_s
- int reset2_time[MINION_CHIPS];
- K_ITEM *reset2_mark[MINION_CHIPS];
- int reset2_count[MINION_CHIPS];
- // Performance history
- K_LIST *pfree_list;
- K_STORE *p_list[MINION_CHIPS];
- // 0xff history
- K_LIST *xfree_list;
- K_STORE *xff_list;
- time_t last_power_cycle;
- uint64_t power_cycles;
- time_t last_xff;
- uint64_t xffs;
- uint64_t last_displayed_xff;
- // Gets reset to zero each time it is used in reporting
- int res_err_count[MINION_CHIPS];
- #if DO_IO_STATS
- // Total
- IOSTAT summary;
- // Two for each command plus wasted extras i.e. direct/fast lookup
- // No error uses 0x0 to 0xff, error uses 0x100 to 0x1ff
- IOSTAT iostats[0x200];
- #endif
- // Stats on how long work is waiting to move from wwork_list to wque_list
- uint64_t que_work;
- double que_time;
- double que_min;
- double que_max;
- uint64_t que_bands[TIME_BANDS+1];
- // From wwork_list to txrx
- uint64_t wt_work;
- double wt_time;
- double wt_min;
- double wt_max;
- uint64_t wt_bands[TIME_BANDS+1];
- bool lednow[MINION_CHIPS];
- bool setled[MINION_CHIPS];
- // When changing the frequency don't modify 'anything'
- bool changing[MINION_CHIPS];
- int init_freq[MINION_CHIPS];
- int want_freq[MINION_CHIPS];
- uint32_t freqsent[MINION_CHIPS];
- struct timeval lastfreq[MINION_CHIPS];
- int freqms[MINION_CHIPS];
- bool initialised;
- };
- #if MINION_ROCKCHIP == 1
- static bool minion_toggle_gpio(struct cgpu_info *minioncgpu, int gpionum)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- char pindir[64], ena[64], pin[8], dir[64];
- char gpiointvalue[64];
- struct stat st;
- int file, err, chip;
- ssize_t ret;
- snprintf(pindir, sizeof(pindir), MINION_GPIO_SYS MINION_GPIO_PIN, gpionum);
- memset(&st, 0, sizeof(st));
- if (stat(pindir, &st) == 0) { // already exists
- if (!S_ISDIR(st.st_mode)) {
- applog(LOG_ERR, "%s: failed1 to enable GPIO pin %d"
- " - not a directory",
- minioncgpu->drv->dname, gpionum);
- return false;
- }
- } else {
- snprintf(ena, sizeof(ena), MINION_GPIO_SYS MINION_GPIO_ENA);
- file = open(ena, O_WRONLY | O_SYNC);
- if (file == -1) {
- applog(LOG_ERR, "%s: failed2 to export GPIO pin %d (%d)"
- " - you need to be root?",
- minioncgpu->drv->dname,
- gpionum, errno);
- return false;
- }
- snprintf(pin, sizeof(pin), MINION_GPIO_ENA_VAL, gpionum);
- ret = write(file, pin, (size_t)strlen(pin));
- if (ret != (ssize_t)strlen(pin)) {
- if (ret < 0)
- err = errno;
- else
- err = (int)ret;
- close(file);
- applog(LOG_ERR, "%s: failed3 to export GPIO pin %d (%d:%d)",
- minioncgpu->drv->dname,
- gpionum, err, (int)strlen(pin));
- return false;
- }
- close(file);
- // Check again if it exists
- memset(&st, 0, sizeof(st));
- if (stat(pindir, &st) != 0) {
- applog(LOG_ERR, "%s: failed4 to export GPIO pin %d (%d)",
- minioncgpu->drv->dname,
- gpionum, errno);
- return false;
- }
- }
- // Set the pin attributes
- // Direction
- snprintf(dir, sizeof(dir), MINION_GPIO_SYS MINION_GPIO_PIN MINION_GPIO_DIR, gpionum);
- file = open(dir, O_WRONLY | O_SYNC);
- if (file == -1) {
- applog(LOG_ERR, "%s: failed5 to configure GPIO pin %d (%d)"
- " - you need to be root?",
- minioncgpu->drv->dname,
- gpionum, errno);
- return false;
- }
- ret = write(file, MINION_GPIO_DIR_WRITE, sizeof(MINION_GPIO_DIR_WRITE)-1);
- if (ret != sizeof(MINION_GPIO_DIR_WRITE)-1) {
- if (ret < 0)
- err = errno;
- else
- err = (int)ret;
- close(file);
- applog(LOG_ERR, "%s: failed6 to configure GPIO pin %d (%d:%d)",
- minioncgpu->drv->dname, gpionum,
- err, (int)sizeof(MINION_GPIO_DIR_WRITE)-1);
- return false;
- }
- close(file);
- // Open it
- snprintf(gpiointvalue, sizeof(gpiointvalue),
- MINION_GPIO_SYS MINION_GPIO_PIN MINION_GPIO_VALUE,
- gpionum);
- int fd = open(gpiointvalue, O_WRONLY);
- if (fd == -1) {
- applog(LOG_ERR, "%s: failed7 to access GPIO pin %d (%d)",
- minioncgpu->drv->dname,
- gpionum, errno);
- return false;
- }
- ret = write(fd, MINION_CHIP_OFF, sizeof(MINION_CHIP_OFF)-1);
- if (ret != sizeof(MINION_CHIP_OFF)-1) {
- close(fd);
- applog(LOG_ERR, "%s: failed8 to toggle off GPIO pin %d (%d:%d)",
- minioncgpu->drv->dname,
- gpionum, (int)ret, errno);
- return false;
- }
- cgsleep_ms(MINION_CHIP_DELAY);
- ret = write(fd, MINION_CHIP_ON, sizeof(MINION_CHIP_ON)-1);
- if (ret != sizeof(MINION_CHIP_OFF)-1) {
- close(fd);
- applog(LOG_ERR, "%s: failed9 to toggle on GPIO pin %d (%d:%d)",
- minioncgpu->drv->dname,
- gpionum, (int)ret, errno);
- return false;
- }
- close(fd);
- minioninfo->last_power_cycle = time(NULL);
- minioninfo->power_cycles++;
- // Reset all chip led counters
- for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
- if (minioninfo->has_chip[chip])
- minioninfo->chip_status[chip].first_nonce.tv_sec = 0L;
- }
- return true;
- }
- #endif
- static void ready_work(struct cgpu_info *minioncgpu, struct work *work, bool rolled)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- K_ITEM *item = NULL;
- K_WLOCK(minioninfo->wfree_list);
- item = k_unlink_head(minioninfo->wfree_list);
- DATA_WORK(item)->work = work;
- DATA_WORK(item)->task_id = 0;
- memset(&(DATA_WORK(item)->sent), 0, sizeof(DATA_WORK(item)->sent));
- DATA_WORK(item)->nonces = 0;
- DATA_WORK(item)->urgent = false;
- DATA_WORK(item)->rolled = rolled;
- DATA_WORK(item)->errors = 0;
- cgtime(&(DATA_WORK(item)->created));
- k_add_head(minioninfo->wwork_list, item);
- K_WUNLOCK(minioninfo->wfree_list);
- }
- static bool oldest_nonce(struct cgpu_info *minioncgpu, int *chip, int *core, uint32_t *task_id,
- uint32_t *nonce, bool *no_nonce, struct timeval *when,
- bool *another, uint32_t *task_id2, uint32_t *nonce2)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- K_ITEM *item = NULL;
- bool found = false;
- K_WLOCK(minioninfo->rnonce_list);
- item = k_unlink_tail(minioninfo->rnonce_list);
- if (item) {
- found = true;
- *chip = DATA_RES(item)->chip;
- *core = DATA_RES(item)->core;
- *task_id = DATA_RES(item)->task_id;
- *nonce = DATA_RES(item)->nonce;
- *no_nonce = DATA_RES(item)->no_nonce;
- memcpy(when, &(DATA_RES(item)->when), sizeof(*when));
- *another = DATA_RES(item)->another;
- *task_id2 = DATA_RES(item)->task_id2;
- *nonce2 = DATA_RES(item)->nonce2;
- k_free_head(minioninfo->rfree_list, item);
- }
- K_WUNLOCK(minioninfo->rnonce_list);
- return found;
- }
- static const char *addr2txt(uint8_t addr)
- {
- switch (addr) {
- case READ_ADDR(MINION_SYS_CHIP_SIG):
- return "RChipSig";
- case READ_ADDR(MINION_SYS_CHIP_STA):
- return "RChipSta";
- case WRITE_ADDR(MINION_SYS_SPI_LED):
- return "WLed";
- case WRITE_ADDR(MINION_SYS_MISC_CTL):
- return "WMiscCtrl";
- case WRITE_ADDR(MINION_SYS_RSTN_CTL):
- return "WResetCtrl";
- case READ_ADDR(MINION_SYS_FIFO_STA):
- return "RFifoSta";
- case READ_ADDR(MINION_CORE_ENA0_31):
- return "RCoreEna0-31";
- case WRITE_ADDR(MINION_CORE_ENA0_31):
- return "WCoreEna0-31";
- case READ_ADDR(MINION_CORE_ENA32_63):
- return "RCoreEna32-63";
- case WRITE_ADDR(MINION_CORE_ENA32_63):
- return "WCoreEna32-63";
- case READ_ADDR(MINION_CORE_ENA64_95):
- return "RCoreEna64-95";
- case WRITE_ADDR(MINION_CORE_ENA64_95):
- return "WCoreEna64-95";
- case READ_ADDR(MINION_CORE_ENA96_98):
- return "RCoreEna96-98";
- case WRITE_ADDR(MINION_CORE_ENA96_98):
- return "WCoreEna96-98";
- case READ_ADDR(MINION_CORE_ACT0_31):
- return "RCoreAct0-31";
- case READ_ADDR(MINION_CORE_ACT32_63):
- return "RCoreAct32-63";
- case READ_ADDR(MINION_CORE_ACT64_95):
- return "RCoreAct64-95";
- case READ_ADDR(MINION_CORE_ACT96_98):
- return "RCoreAct96-98";
- case READ_ADDR(MINION_RES_DATA):
- return "RResData";
- case READ_ADDR(MINION_RES_PEEK):
- return "RResPeek";
- case WRITE_ADDR(MINION_QUE_0):
- return "WQueWork";
- case READ_ADDR(MINION_NONCE_START):
- return "RNonceStart";
- case WRITE_ADDR(MINION_NONCE_START):
- return "WNonceStart";
- case READ_ADDR(MINION_NONCE_RANGE):
- return "RNonceRange";
- case WRITE_ADDR(MINION_NONCE_RANGE):
- return "WNonceRange";
- case READ_ADDR(MINION_SYS_INT_STA):
- return "RIntSta";
- case WRITE_ADDR(MINION_SYS_INT_ENA):
- return "WIntEna";
- case WRITE_ADDR(MINION_SYS_INT_CLR):
- return "WIntClear";
- case WRITE_ADDR(MINION_SYS_BUF_TRIG):
- return "WResTrigger";
- case WRITE_ADDR(MINION_SYS_QUE_TRIG):
- return "WCmdTrigger";
- case READ_ADDR(MINION_SYS_TEMP_CTL):
- return "RTempCtrl";
- case WRITE_ADDR(MINION_SYS_TEMP_CTL):
- return "WTempCtrl";
- case READ_ADDR(MINION_SYS_FREQ_CTL):
- return "RFreqCtrl";
- case WRITE_ADDR(MINION_SYS_FREQ_CTL):
- return "WFreqCtrl";
- case READ_ADDR(MINION_SYS_IDLE_CNT):
- return "RIdleCnt";
- }
- // gcc warning if this is in default:
- if (IS_ADDR_READ(addr))
- return "RUnhandled";
- else
- return "WUnhandled";
- }
- // For display_ioctl()
- #define IOCTRL_LOG LOG_WARNING
- // For all other debug so it can easily be switched always on
- #define MINION_LOG LOG_DEBUG
- // For task corruption logging
- #define MINTASK_LOG LOG_DEBUG
- // Set to 1 for debug
- #define MINION_SHOW_IO 0
- #define DATA_ALL 2048
- #define DATA_OFF 512
- #if MINION_SHOW_IO
- static void display_ioctl(int reply, uint32_t osiz, uint8_t *obuf, uint32_t rsiz, uint8_t *rbuf)
- {
- struct minion_result *res;
- const char *name, *dir, *ex;
- char buf[4096];
- int i, rescount;
- name = addr2txt(obuf[1]);
- if (IS_ADDR_READ(obuf[1]))
- dir = "from";
- else
- dir = "to";
- buf[0] = '\0';
- ex = "";
- switch (obuf[1]) {
- case READ_ADDR(MINION_SYS_CHIP_SIG):
- case READ_ADDR(MINION_SYS_CHIP_STA):
- break;
- case WRITE_ADDR(MINION_SYS_SPI_LED):
- case WRITE_ADDR(MINION_SYS_MISC_CTL):
- case WRITE_ADDR(MINION_SYS_RSTN_CTL):
- if (osiz > HSIZE()) {
- ex = " wrote ";
- __bin2hex(buf, obuf + HSIZE(), osiz - HSIZE());
- } else
- ex = " wrote nothing";
- break;
- default:
- if (IS_ADDR_WRITE(obuf[1])) {
- if (osiz > HSIZE()) {
- ex = " wrote ";
- __bin2hex(buf, obuf + HSIZE(), osiz - HSIZE());
- } else
- ex = " wrote nothing";
- }
- break;
- }
- if (reply < 0) {
- applog(IOCTRL_LOG, "%s %s chipid %d osiz %d%s%s",
- name, dir, (int)obuf[0], (int)osiz, ex, buf);
- applog(IOCTRL_LOG, " reply was error %d", reply);
- } else {
- if (IS_ADDR_WRITE(obuf[1])) {
- applog(IOCTRL_LOG, "%s %s chipid %d osiz %d%s%s",
- name, dir, (int)obuf[0], (int)osiz, ex, buf);
- applog(IOCTRL_LOG, " write ret was %d", reply);
- } else {
- switch (obuf[1]) {
- case READ_ADDR(MINION_RES_DATA):
- rescount = (int)((float)rsiz / (float)MINION_RES_DATA_SIZ);
- applog(IOCTRL_LOG, "%s %s chipid %d osiz %d%s%s",
- name, dir, (int)obuf[0], (int)osiz, ex, buf);
- for (i = 0; i < rescount; i++) {
- res = (struct minion_result *)(rbuf + osiz - rsiz + (i * MINION_RES_DATA_SIZ));
- if (!IS_RESULT(res)) {
- applog(IOCTRL_LOG, " %s reply %d of %d - none", name, i+1, rescount);
- } else {
- __bin2hex(buf, res->nonce, DATA_SIZ);
- applog(IOCTRL_LOG, " %s reply %d of %d %d(%d) was task 0x%04x"
- " chipid %d core %d gold %s nonce 0x%s",
- name, i+1, rescount, reply, rsiz,
- RES_TASK(res),
- (int)RES_CHIPID(res),
- (int)RES_CORE(res),
- (int)RES_GOLD(res) ? "Y" : "N",
- buf);
- }
- }
- break;
- case READ_ADDR(MINION_SYS_CHIP_SIG):
- case READ_ADDR(MINION_SYS_CHIP_STA):
- default:
- applog(IOCTRL_LOG, "%s %s chipid %d osiz %d%s%s",
- name, dir, (int)obuf[0], (int)osiz, ex, buf);
- __bin2hex(buf, rbuf + osiz - rsiz, rsiz);
- applog(IOCTRL_LOG, " %s reply %d(%d) was %s", name, reply, rsiz, buf);
- break;
- }
- }
- }
- }
- #endif
- #define MINION_UNEXPECTED_TASK -999
- #define MINION_OVERSIZE_TASK -998
- static void set_pin(struct minion_info *minioninfo, int pin, bool on)
- {
- volatile uint32_t *paddr;
- uint32_t value;
- int bcm;
- bcm = minionPins[pin].bcm;
- paddr = minioninfo->gpio + ((on ? BCM2835_GPIO_SET0 : BCM2835_GPIO_CLR0) / 4) + (bcm / 10);
- value = 1 << (bcm % 32);
- *paddr = value;
- *paddr = value;
- }
- static void init_pins(struct minion_info *minioninfo)
- {
- int pin;
- // Initialise all pins high as required
- MINION_PIN_BEFORE;
- for (pin = 0; pin < (int)MINION_PIN_COUNT; pin++) {
- set_pin(minioninfo, pin, true);
- MINION_PIN_SLEEP;
- }
- }
- #define EXTRA_LOG_IO 0
- static bool minion_init_spi(struct cgpu_info *minioncgpu, struct minion_info *minioninfo, int bus, int chip, bool reset);
- static int __do_ioctl(struct cgpu_info *minioncgpu, struct minion_info *minioninfo,
- int pin, uint8_t *obuf, uint32_t osiz, uint8_t *rbuf,
- uint32_t rsiz, uint64_t *ioseq, MINION_FFL_ARGS)
- {
- struct spi_ioc_transfer tran;
- bool fail = false, powercycle = false, show = false;
- double lastshow, total;
- K_ITEM *xitem;
- time_t now;
- int ret;
- #if MINION_SHOW_IO
- char dataw[DATA_ALL], datar[DATA_ALL];
- #endif
- #if DO_IO_STATS
- struct timeval sta, fin, lsta, lfin, tsd;
- #endif
- if ((int)osiz > MINION_BUFSIZ)
- quitfrom(1, file, func, line, "%s() invalid osiz %u > %d (chip=%d reg=0x%02x)",
- __func__, osiz, MINION_BUFSIZ, (int)(obuf[0]), obuf[1]);
- if (rsiz >= osiz)
- quitfrom(1, file, func, line, "%s() invalid rsiz %u >= osiz %u (chip=%u reg=0x%02x)",
- __func__, rsiz, osiz, (int)(obuf[0]), obuf[1]);
- memset(&obuf[0] + osiz - rsiz, 0xff, rsiz);
- #if MINION_SHOW_IO
- // if the a5/5a outside the data change, it means data overrun or corruption
- memset(dataw, 0xa5, sizeof(dataw));
- memset(datar, 0x5a, sizeof(datar));
- memcpy(&dataw[DATA_OFF], &obuf[0], osiz);
- char *buf = bin2hex((unsigned char *)&(dataw[DATA_OFF]), osiz);
- applog(IOCTRL_LOG, "*** %s() pin %d cid %d sending %02x %02x %s %02x %02x",
- __func__, pin, (int)(dataw[DATA_OFF]),
- dataw[0], dataw[DATA_OFF-1], buf,
- dataw[DATA_OFF+osiz], dataw[DATA_ALL-1]);
- free(buf);
- #endif
- memset((char *)rbuf, 0x00, osiz);
- // cgsleep_ms(5); // TODO: a delay ... based on the last command? But subtract elapsed
- // i.e. do any commands need a delay after the I/O has completed before the next I/O?
- memset(&tran, 0, sizeof(tran));
- if (osiz < MINION_SPI_BUFSIZ)
- tran.len = osiz;
- else
- return MINION_OVERSIZE_TASK;
- tran.delay_usecs = opt_minion_spiusec;
- tran.speed_hz = MINION_SPI_SPEED;
- #if MINION_SHOW_IO
- tran.tx_buf = (uintptr_t)&(dataw[DATA_OFF]);
- tran.rx_buf = (uintptr_t)&(datar[DATA_OFF]);
- #else
- tran.tx_buf = (uintptr_t)obuf;
- tran.rx_buf = (uintptr_t)rbuf;
- #endif
- IO_STAT_NOW(&lsta);
- mutex_lock(&(minioninfo->spi_lock));
- if (usepins) {
- // Pin low for I/O
- MINION_PIN_BEFORE;
- set_pin(minioninfo, pin, false);
- MINION_PIN_SLEEP;
- }
- IO_STAT_NOW(&sta);
- ret = ioctl(minioninfo->spifd, SPI_IOC_MESSAGE(1), (void *)&tran);
- *ioseq = minioninfo->ioseq++;
- IO_STAT_NOW(&fin);
- if (usepins) {
- MINION_PIN_AFTER;
- // Pin back high after I/O
- set_pin(minioninfo, pin, true);
- }
- now = time(NULL);
- if (ret >= 0 && rbuf[0] == 0xff && rbuf[ret-1] == 0xff &&
- (obuf[1] == READ_ADDR(MINION_RES_DATA) || obuf[1] == READ_ADDR(MINION_SYS_FIFO_STA))) {
- int i;
- fail = true;
- for (i = 1; i < ret-2; i++) {
- if (rbuf[i] != 0xff) {
- fail = false;
- break;
- }
- }
- if (fail) {
- powercycle = show = false;
- minioninfo->xffs++;
- minioninfo->last_xff = now;
- if (minioninfo->xfree_list->count > 0)
- xitem = k_unlink_head(minioninfo->xfree_list);
- else
- xitem = k_unlink_tail(minioninfo->xff_list);
- DATA_XFF(xitem)->when = now;
- if (!minioninfo->xff_list->head)
- show = true;
- else {
- // if !changing and xff_list is full
- if (!minioninfo->changing[obuf[0]] &&
- minioninfo->xfree_list->count == 0) {
- total = DATA_XFF(xitem)->when -
- DATA_XFF(minioninfo->xff_list->tail)->when;
- if (total <= MINION_POWER_TIME) {
- powercycle = true;
- // Discard the history
- k_list_transfer_to_head(minioninfo->xff_list,
- minioninfo->xfree_list);
- k_add_head(minioninfo->xfree_list, xitem);
- xitem = NULL;
- }
- }
- if (!powercycle) {
- lastshow = DATA_XFF(xitem)->when -
- DATA_XFF(minioninfo->xff_list->head)->when;
- show = (lastshow >= 5);
- }
- }
- if (xitem)
- k_add_head(minioninfo->xff_list, xitem);
- #if MINION_ROCKCHIP == 1
- if (powercycle)
- minion_toggle_gpio(minioncgpu, MINION_POWERCYCLE_GPIO);
- #endif
- minion_init_spi(minioncgpu, minioninfo, 0, 0, true);
- }
- } else if (minioninfo->spi_reset_count) {
- if (minioninfo->spi_reset_io) {
- if (*ioseq > 0 && (*ioseq % minioninfo->spi_reset_count) == 0)
- minion_init_spi(minioncgpu, minioninfo, 0, 0, true);
- } else {
- if (minioninfo->last_spi_reset == 0)
- minioninfo->last_spi_reset = now;
- else {
- if ((now - minioninfo->last_spi_reset) >= minioninfo->spi_reset_count)
- minion_init_spi(minioncgpu, minioninfo, 0, 0, true);
- minioninfo->last_spi_reset = now;
- }
- }
- }
- if (opt_minion_spidelay)
- cgsleep_ms(opt_minion_spidelay);
- mutex_unlock(&(minioninfo->spi_lock));
- IO_STAT_NOW(&lfin);
- IO_STAT_NOW(&tsd);
- IO_STAT_STORE(&sta, &fin, &lsta, &lfin, &tsd, obuf, osiz, ret, 1);
- if (fail) {
- if (powercycle) {
- applog(LOG_ERR, "%s%d: power cycle ioctl %"PRIu64" (%"PRIu64")",
- minioncgpu->drv->name, minioncgpu->device_id, *ioseq,
- minioninfo->xffs - minioninfo->last_displayed_xff);
- minioninfo->last_displayed_xff = minioninfo->xffs;
- } else if (show) {
- char *what = "unk";
- switch (obuf[1]) {
- case READ_ADDR(MINION_RES_DATA):
- what = "nonce";
- break;
- case READ_ADDR(MINION_SYS_FIFO_STA):
- what = "fifo";
- break;
- }
- applog(LOG_ERR, "%s%d: reset ioctl %"PRIu64" %s all 0xff (%"PRIu64")",
- minioncgpu->drv->name, minioncgpu->device_id,
- *ioseq, what, minioninfo->xffs - minioninfo->last_displayed_xff);
- minioninfo->last_displayed_xff = minioninfo->xffs;
- }
- }
- #if MINION_SHOW_IO
- if (ret > 0) {
- buf = bin2hex((unsigned char *)&(datar[DATA_OFF]), ret);
- applog(IOCTRL_LOG, "*** %s() reply %d = pin %d cid %d %02x %02x %s %02x %02x",
- __func__, ret, pin, (int)(dataw[DATA_OFF]),
- datar[0], datar[DATA_OFF-1], buf,
- datar[DATA_OFF+osiz], datar[DATA_ALL-1]);
- free(buf);
- } else
- applog(LOG_ERR, "*** %s() reply = %d", __func__, ret);
- memcpy(&rbuf[0], &datar[DATA_OFF], osiz);
- display_ioctl(ret, osiz, (uint8_t *)(&dataw[DATA_OFF]), rsiz, (uint8_t *)(&datar[DATA_OFF]));
- #endif
- #if EXTRA_LOG_IO
- if (obuf[1] == READ_ADDR(MINION_RES_PEEK) ||
- obuf[1] == READ_ADDR(MINION_RES_DATA) ||
- obuf[1] == READ_ADDR(MINION_SYS_FIFO_STA)) {
- char *uf1, *uf2, c;
- uf1 = bin2hex(obuf, DATA_SIZ);
- uf2 = bin2hex(rbuf, (size_t)ret);
- switch (obuf[1]) {
- case READ_ADDR(MINION_RES_PEEK):
- c = 'P';
- break;
- case READ_ADDR(MINION_RES_DATA):
- c = 'D';
- break;
- case READ_ADDR(MINION_SYS_FIFO_STA):
- c = 'F';
- break;
- }
- applog(LOG_WARNING, "*** ioseq %"PRIu64" cmd %c %s rep %.8s %s",
- *ioseq, c, uf1, uf2, uf2+8);
- free(uf2);
- free(uf1);
- }
- if (obuf[1] == WRITE_ADDR(MINION_QUE_0)) {
- char *uf;
- uf = bin2hex(obuf, osiz);
- applog(LOG_WARNING, "*** ioseq %"PRIu64" work %s",
- *ioseq, uf);
- free(uf);
- }
- #endif
- return ret;
- }
- #if 1
- #define do_ioctl(_pin, _obuf, _osiz, _rbuf, _rsiz, _ioseq) \
- __do_ioctl(minioncgpu, minioninfo, _pin, _obuf, _osiz, _rbuf, \
- _rsiz, _ioseq, MINION_FFL_HERE)
- #else
- #define do_ioctl(_pin, _obuf, _osiz, _rbuf, _rsiz, _ioseq) \
- _do_ioctl(minioninfo, _pin, _obuf, _osiz, _rbuf, \
- _rsiz, _ioseq, MINION_FFL_HERE)
- // This sends an expected to work, SPI command before each SPI command
- static int _do_ioctl(struct minion_info *minioninfo, int pin, uint8_t *obuf, uint32_t osiz, uint8_t *rbuf, uint32_t rsiz, uint64_t *ioseq, MINION_FFL_ARGS)
- {
- struct minion_header *head;
- uint8_t buf1[MINION_BUFSIZ];
- uint8_t buf2[MINION_BUFSIZ];
- uint32_t siz;
- head = (struct minion_header *)buf1;
- head->chipid = 1; // Needs to be set to a valid chip
- head->reg = READ_ADDR(MINION_SYS_FIFO_STA);
- SET_HEAD_SIZ(head, DATA_SIZ);
- siz = HSIZE() + DATA_SIZ;
- __do_ioctl(minioncgpu, minioninfo, pin, buf1, siz, buf2, MINION_CORE_SIZ, ioseq, MINION_FFL_PASS);
- return __do_ioctl(minioncgpu, minioninfo, pin, obuf, osiz, rbuf, rsiz, ioseq, MINION_FFL_PASS);
- }
- #endif
- static bool _minion_txrx(struct cgpu_info *minioncgpu, struct minion_info *minioninfo, TASK_ITEM *task, MINION_FFL_ARGS)
- {
- struct minion_header *head;
- head = (struct minion_header *)(task->obuf);
- head->chipid = minioninfo->chipid[task->chip];
- if (task->write)
- SET_HEAD_WRITE(head, task->address);
- else
- SET_HEAD_READ(head, task->address);
- SET_HEAD_SIZ(head, task->wsiz + task->rsiz);
- if (task->wsiz)
- memcpy(&(head->data[0]), task->wbuf, task->wsiz);
- task->osiz = HSIZE() + task->wsiz + task->rsiz;
- task->reply = do_ioctl(CHIP_PIN(task->chip), task->obuf, task->osiz, task->rbuf, task->rsiz,
- &(task->ioseq));
- if (task->reply < 0) {
- applog(LOG_ERR, "%s%d: chip=%d ioctl failed reply=%d err=%d" MINION_FFL,
- minioncgpu->drv->name, minioncgpu->device_id,
- task->chip, task->reply, errno, MINION_FFL_PASS);
- } else if (task->reply < (int)(task->osiz)) {
- applog(LOG_ERR, "%s%d: chip=%d ioctl failed to write %d only wrote %d (err=%d)" MINION_FFL,
- minioncgpu->drv->name, minioncgpu->device_id,
- task->chip, (int)(task->osiz), task->reply, errno, MINION_FFL_PASS);
- }
- return (task->reply >= (int)(task->osiz));
- }
- // Only for DATA_SIZ commands
- static int build_cmd(struct cgpu_info *minioncgpu, struct minion_info *minioninfo, int chip, uint8_t reg, uint8_t *rbuf, uint32_t rsiz, uint8_t *data)
- {
- struct minion_header *head;
- uint8_t wbuf[MINION_BUFSIZ];
- uint32_t wsiz;
- uint64_t ioseq;
- int reply;
- head = (struct minion_header *)wbuf;
- head->chipid = minioninfo->chipid[chip];
- head->reg = reg;
- SET_HEAD_SIZ(head, DATA_SIZ);
- head->data[0] = data[0];
- head->data[1] = data[1];
- head->data[2] = data[2];
- head->data[3] = data[3];
- wsiz = HSIZE() + DATA_SIZ;
- reply = do_ioctl(CHIP_PIN(chip), wbuf, wsiz, rbuf, rsiz, &ioseq);
- if (reply != (int)wsiz) {
- applog(LOG_ERR, "%s: chip %d %s returned %d (should be %d)",
- minioncgpu->drv->dname, chip,
- addr2txt(head->reg),
- reply, (int)wsiz);
- }
- return reply;
- }
- static void set_freq(struct cgpu_info *minioncgpu, struct minion_info *minioninfo, int chip, int freq)
- {
- uint8_t rbuf[MINION_BUFSIZ];
- uint8_t data[4];
- uint32_t value;
- __maybe_unused int reply;
- freq /= MINION_FREQ_FACTOR;
- if (freq < MINION_FREQ_FACTOR_MIN)
- freq = MINION_FREQ_FACTOR_MIN;
- if (freq > MINION_FREQ_FACTOR_MAX)
- freq = MINION_FREQ_FACTOR_MAX;
- value = minion_freq[freq];
- data[0] = (uint8_t)(value & 0xff);
- data[1] = (uint8_t)(((value & 0xff00) >> 8) & 0xff);
- data[2] = (uint8_t)(((value & 0xff0000) >> 16) & 0xff);
- data[3] = (uint8_t)(((value & 0xff000000) >> 24) & 0xff);
- minioninfo->freqsent[chip] = value;
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_SYS_FREQ_CTL),
- rbuf, 0, data);
- cgtime(&(minioninfo->lastfreq[chip]));
- applog(LOG_DEBUG, "%s%i: chip %d freq %d sec %d usec %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, freq,
- (int)(minioninfo->lastfreq[chip].tv_sec) % 10,
- (int)(minioninfo->lastfreq[chip].tv_usec));
- // Reset all this info on chip reset or freq change
- minioninfo->reset_time[chip] = (int)FREQ_DELAY(minioninfo->init_freq[chip]);
- if (second_check)
- minioninfo->reset2_time[chip] = (int)FREQ2_DELAY(minioninfo->init_freq[chip]);
- minioninfo->chip_status[chip].first_nonce.tv_sec = 0L;
- // Discard chip history (if there is any)
- if (minioninfo->hfree_list) {
- K_WLOCK(minioninfo->hfree_list);
- k_list_transfer_to_head(minioninfo->hchip_list[chip], minioninfo->hfree_list);
- minioninfo->reset_mark[chip] = NULL;
- minioninfo->reset_count[chip] = 0;
- K_WUNLOCK(minioninfo->hfree_list);
- }
- }
- static void init_chip(struct cgpu_info *minioncgpu, struct minion_info *minioninfo, int chip)
- {
- uint8_t rbuf[MINION_BUFSIZ];
- uint8_t data[4];
- __maybe_unused int reply;
- int choice;
- // Complete chip reset
- data[0] = 0x00;
- data[1] = 0x00;
- data[2] = 0xa5;
- data[3] = 0xf5;
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_SYS_RSTN_CTL),
- rbuf, 0, data);
- // Default reset
- data[0] = SYS_RSTN_CTL_INIT;
- data[1] = 0x00;
- data[2] = 0x00;
- data[3] = 0x00;
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_SYS_RSTN_CTL),
- rbuf, 0, data);
- // Default initialisation
- data[0] = SYS_MISC_CTL_DEFAULT;
- data[1] = 0x00;
- data[2] = 0x00;
- data[3] = 0x00;
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_SYS_MISC_CTL),
- rbuf, 0, data);
- // Set chip frequency
- choice = minioninfo->init_freq[chip];
- if (choice < MINION_FREQ_MIN)
- choice = MINION_FREQ_MIN;
- if (choice > MINION_FREQ_MAX)
- choice = MINION_FREQ_MAX;
- minioninfo->init_freq[chip] = choice;
- set_freq(minioncgpu, minioninfo, chip, choice);
- // Set temp threshold
- choice = minioninfo->init_temp[chip];
- if (choice == MINION_TEMP_CTL_DISABLE)
- choice = MINION_TEMP_CTL_DISABLE_VALUE;
- else {
- if (choice < MINION_TEMP_CTL_MIN_VALUE || choice > MINION_TEMP_CTL_MAX_VALUE)
- choice = MINION_TEMP_CTL_DEF;
- choice -= MINION_TEMP_CTL_MIN_VALUE;
- choice /= MINION_TEMP_CTL_STEP;
- choice += MINION_TEMP_CTL_MIN;
- if (choice < MINION_TEMP_CTL_MIN)
- choice = MINION_TEMP_CTL_MIN;
- if (choice > MINION_TEMP_CTL_MAX)
- choice = MINION_TEMP_CTL_MAX;
- }
- data[0] = (uint8_t)choice;
- data[1] = 0;
- data[2] = 0;
- data[3] = 0;
- minioninfo->chip_status[chip].tempsent = choice;
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_SYS_TEMP_CTL),
- rbuf, 0, data);
- }
- static void enable_chip_cores(struct cgpu_info *minioncgpu, struct minion_info *minioninfo, int chip)
- {
- uint8_t rbuf[MINION_BUFSIZ];
- uint8_t data[4];
- __maybe_unused int reply;
- int rep, i;
- for (i = 0; i < 4; i++)
- data[i] = minioninfo->init_cores[chip][i];
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_CORE_ENA0_31),
- rbuf, 0, data);
- for (i = 0; i < 4; i++)
- data[i] = minioninfo->init_cores[chip][i+4];
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_CORE_ENA32_63),
- rbuf, 0, data);
- for (i = 0; i < 4; i++)
- data[i] = minioninfo->init_cores[chip][i+8];
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_CORE_ENA64_95),
- rbuf, 0, data);
- for (i = 0; i < 4; i++)
- data[i] = minioninfo->init_cores[chip][i+12];
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_CORE_ENA96_98),
- rbuf, 0, data);
- /* Below is for testing - disabled/use default
- // 1/3 range for each of the 3 cores
- // data[0] = 0x55;
- // data[1] = 0x55;
- // data[2] = 0x55;
- // data[3] = 0x55;
- // quicker replies
- // data[0] = 0x05;
- // data[1] = 0x05;
- // data[2] = 0x05;
- // data[3] = 0x05;
- // 0x00000100 at 20MH/s per core = 336TH/s if 1 nonce per work item
- // 0x00001000 = 21.0TH/s - so well above 2TH/s
- // 0x00002000 = 10.5TH/s - above 2TH/s
- // speed test
- data[0] = 0x00;
- data[1] = 0x01;
- data[2] = 0x00;
- data[3] = 0x00;
- // data[3] = 0x20; // slow it down for other testing
- // 2 cores
- // data[0] = 0xff;
- // data[1] = 0xff;
- // data[2] = 0xff;
- // data[3] = 0x7f;
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_NONCE_RANGE),
- rbuf, 0, data);
- // find lots more nonces in a short time on my test data
- // i.e. emulate a MUCH higher hash rate on SPI and work
- // generation/testing
- // Current test data (same repeated 10 times) has nonce 0x05e0ed6d
- data[0] = 0x00;
- data[1] = 0xed;
- data[2] = 0xe0;
- data[3] = 0x05;
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_NONCE_START),
- rbuf, 0, data);
- */
- // store the core ena state
- for (rep = 0; rep < MINION_CORE_REPS; rep++) {
- data[0] = 0x0;
- data[1] = 0x0;
- data[2] = 0x0;
- data[3] = 0x0;
- reply = build_cmd(minioncgpu, minioninfo,
- chip, READ_ADDR(MINION_CORE_ENA0_31 + rep),
- rbuf, MINION_CORE_SIZ, data);
- minioninfo->chip_core_ena[rep][chip] = *((uint32_t *)&(rbuf[HSIZE()]));
- }
- // store the core active state
- for (rep = 0; rep < MINION_CORE_REPS; rep++) {
- data[0] = 0x0;
- data[1] = 0x0;
- data[2] = 0x0;
- data[3] = 0x0;
- reply = build_cmd(minioncgpu, minioninfo,
- chip, READ_ADDR(MINION_CORE_ACT0_31 + rep),
- rbuf, MINION_CORE_SIZ, data);
- minioninfo->chip_core_act[rep][chip] = *((uint32_t *)&(rbuf[HSIZE()]));
- }
- }
- #if ENABLE_INT_NONO
- static void enable_interrupt(struct cgpu_info *minioncgpu, struct minion_info *minioninfo, int chip)
- {
- uint8_t rbuf[MINION_BUFSIZ];
- uint8_t data[4];
- __maybe_unused int reply;
- data[0] = MINION_RESULT_INT_SIZE;
- data[1] = 0x00;
- data[2] = 0x00;
- data[3] = 0x00;
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_SYS_BUF_TRIG),
- rbuf, 0, data);
- // data[0] = MINION_QUE_MAX; // spaces available ... i.e. empty
- // data[0] = MINION_QUE_LOW; // spaces in use
- data[0] = MINION_QUE_MAX - MINION_QUE_LOW; // spaces available
- data[1] = 0x00;
- data[2] = 0x00;
- data[3] = 0x00;
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_SYS_QUE_TRIG),
- rbuf, 0, data);
- // data[0] = MINION_RESULT_INT;
- data[0] = MINION_RESULT_INT | MINION_CMD_INT;
- data[1] = 0x00;
- data[2] = 0x00;
- data[3] = 0x00;
- reply = build_cmd(minioncgpu, minioninfo,
- chip, WRITE_ADDR(MINION_SYS_INT_ENA),
- rbuf, 0, data);
- }
- #endif
- static void minion_detect_one(struct cgpu_info *minioncgpu, struct minion_info *minioninfo, int pin, int chipid)
- {
- struct minion_header *head;
- uint8_t wbuf[MINION_BUFSIZ];
- uint8_t rbuf[MINION_BUFSIZ];
- uint32_t wsiz, rsiz;
- int reply, tries, newchip;
- uint64_t ioseq;
- bool ok;
- head = (struct minion_header *)wbuf;
- head->chipid = chipid;
- rsiz = MINION_SYS_SIZ;
- SET_HEAD_READ(head, MINION_SYS_CHIP_SIG);
- SET_HEAD_SIZ(head, rsiz);
- wsiz = HSIZE() + rsiz;
- tries = 0;
- ok = false;
- do {
- reply = do_ioctl(pin, wbuf, wsiz, rbuf, rsiz, &ioseq);
- if (reply == (int)(wsiz)) {
- uint32_t sig = u8tou32(rbuf, wsiz - rsiz);
- if (sig == MINION_CHIP_SIG) {
- newchip = (minioninfo->chips)++;
- minioninfo->has_chip[newchip] = true;
- minioninfo->chipid[newchip] = chipid;
- minioninfo->chip_pin[newchip] = pin;
- ok = true;
- } else {
- if (sig == MINION_CHIP_SIG_SHIFT1 ||
- sig == MINION_CHIP_SIG_SHIFT2 ||
- sig == MINION_CHIP_SIG_SHIFT3 ||
- sig == MINION_CHIP_SIG_SHIFT4) {
- applog(LOG_WARNING, "%s: pin %d chipid %d detect offset got"
- " 0x%08x wanted 0x%08x",
- minioncgpu->drv->dname, pin, chipid,
- sig, MINION_CHIP_SIG);
- } else {
- if (sig == MINION_NOCHIP_SIG ||
- sig == MINION_NOCHIP_SIG2) // Assume no chip
- ok = true;
- else {
- applog(LOG_ERR, "%s: pin %d chipid %d detect failed"
- " got 0x%08x wanted 0x%08x",
- minioncgpu->drv->dname, pin,
- chipid, sig, MINION_CHIP_SIG);
- }
- }
- }
- } else {
- applog(LOG_ERR, "%s: pin %d chipid %d reply %d ignored should be %d",
- minioncgpu->drv->dname, pin, chipid, reply, (int)(wsiz));
- }
- } while (!ok && ++tries <= MINION_SIG_TRIES);
- if (!ok) {
- applog(LOG_ERR, "%s: pin %d chipid %d - detect failure status",
- minioncgpu->drv->dname, pin, chipid);
- }
- }
- // Simple detect - just check each chip for the signature
- static void minion_detect_chips(struct cgpu_info *minioncgpu, struct minion_info *minioninfo)
- {
- int pin, chipid, chip;
- int pinend, start_freq, want_freq, freqms;
- #if MINION_ROCKCHIP == 1
- minion_toggle_gpio(minioncgpu, MINION_POWERCYCLE_GPIO);
- cgsleep_ms(100);
- #endif
- if (usepins) {
- init_pins(minioninfo);
- pinend = (int)MINION_PIN_COUNT;
- } else
- pinend = 1;
- for (pin = 0; pin < pinend; pin++) {
- for (chipid = MINION_MIN_CHIP; chipid <= MINION_MAX_CHIP; chipid++) {
- minion_detect_one(minioncgpu, minioninfo, pin, chipid);
- }
- }
- if (minioninfo->chips) {
- for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
- if (minioninfo->has_chip[chip]) {
- want_freq = minioninfo->init_freq[chip];
- start_freq = want_freq * opt_minion_freqpercent / 100;
- start_freq -= (start_freq % MINION_FREQ_FACTOR);
- if (start_freq < MINION_FREQ_MIN)
- start_freq = MINION_FREQ_MIN;
- minioninfo->want_freq[chip] = want_freq;
- minioninfo->init_freq[chip] = start_freq;
- if (start_freq != want_freq) {
- freqms = opt_minion_freqchange;
- freqms /= ((want_freq - start_freq) / MINION_FREQ_FACTOR);
- if (freqms < 0)
- freqms = -freqms;
- minioninfo->freqms[chip] = freqms;
- minioninfo->changing[chip] = true;
- }
- init_chip(minioncgpu, minioninfo, chip);
- enable_chip_cores(minioncgpu, minioninfo, chip);
- }
- }
- #if ENABLE_INT_NONO
- // After everything is ready
- for (chip = 0; chip < MINION_CHIPS; chip++)
- if (minioninfo->has_chip[chip])
- enable_interrupt(minioncgpu, minioninfo, chip);
- #endif
- }
- }
- static const char *minion_modules[] = {
- #if MINION_ROCKCHIP == 0
- "i2c-dev",
- "i2c-bcm2708",
- "spidev",
- "spi-bcm2708",
- #endif
- NULL
- };
- static struct {
- int request;
- int value;
- } minion_ioc[] = {
- { SPI_IOC_RD_MODE, 0 },
- { SPI_IOC_WR_MODE, 0 },
- { SPI_IOC_RD_BITS_PER_WORD, 8 },
- { SPI_IOC_WR_BITS_PER_WORD, 8 },
- { SPI_IOC_RD_MAX_SPEED_HZ, MINION_SPI_SPEED },
- { SPI_IOC_WR_MAX_SPEED_HZ, MINION_SPI_SPEED },
- { -1, -1 }
- };
- static bool minion_init_spi(struct cgpu_info *minioncgpu, struct minion_info *minioninfo, int bus, int chip, bool reset)
- {
- int i, err, data;
- char buf[64];
- if (reset) {
- // TODO: maybe slow it down?
- close(minioninfo->spifd);
- if (opt_minion_spisleep)
- cgsleep_ms(opt_minion_spisleep);
- minioninfo->spifd = open(minioncgpu->device_path, O_RDWR);
- if (minioninfo->spifd < 0)
- goto bad_out;
- minioninfo->spi_resets++;
- // minioninfo->chip_status[chip].first_nonce.tv_sec = 0L;
- } else {
- for (i = 0; minion_modules[i]; i++) {
- snprintf(buf, sizeof(buf), "modprobe %s", minion_modules[i]);
- err = system(buf);
- if (err) {
- applog(LOG_ERR, "%s: failed to modprobe %s (%d) - you need to be root?",
- minioncgpu->drv->dname,
- minion_modules[i], err);
- goto bad_out;
- }
- }
- snprintf(buf, sizeof(buf), "/dev/spidev%d.%d", bus, chip);
- minioninfo->spifd = open(buf, O_RDWR);
- if (minioninfo->spifd < 0) {
- applog(LOG_ERR, "%s: failed to open spidev (%d)",
- minioncgpu->drv->dname,
- errno);
- goto bad_out;
- }
- minioncgpu->device_path = strdup(buf);
- }
- for (i = 0; minion_ioc[i].value != -1; i++) {
- data = minion_ioc[i].value;
- err = ioctl(minioninfo->spifd, minion_ioc[i].request, (void *)&data);
- if (err < 0) {
- applog(LOG_ERR, "%s: failed ioctl configuration (%d) (%d)",
- minioncgpu->drv->dname,
- i, errno);
- goto close_out;
- }
- }
- return true;
- close_out:
- close(minioninfo->spifd);
- minioninfo->spifd = 0;
- free(minioncgpu->device_path);
- minioncgpu->device_path = NULL;
- bad_out:
- return false;
- }
- static bool minion_setup_chip_select(struct cgpu_info *minioncgpu, struct minion_info *minioninfo)
- {
- volatile uint32_t *paddr;
- uint32_t mask, value, mem;
- int count, memfd, pin, bcm;
- memfd = open(minion_memory, O_RDWR | O_SYNC);
- if (memfd < 0) {
- applog(LOG_ERR, "%s: failed open %s (%d)",
- minioncgpu->drv->dname,
- minion_memory, errno);
- return false;
- }
- minioninfo->gpio = (volatile unsigned *)mmap(NULL, MINION_PAGE_SIZE,
- PROT_READ | PROT_WRITE,
- MAP_SHARED, memfd,
- minion_memory_addr);
- if (minioninfo->gpio == MAP_FAILED) {
- close(memfd);
- applog(LOG_ERR, "%s: failed mmap gpio (%d)",
- minioncgpu->drv->dname,
- errno);
- return false;
- }
- close(memfd);
- for (pin = 0; pin < (int)MINION_PIN_COUNT; pin++) {
- bcm = minionPins[pin].bcm;
- paddr = minioninfo->gpio + (BCM2835_GPIO_FSEL0 / 4) + (bcm / 10);
- // Set each pin to be an output pin
- mask = BCM2835_GPIO_FSEL_MASK << ((bcm % 10) * 3);
- value = BCM2835_GPIO_FSEL_OUTPUT << ((bcm % 10) * 3);
- // Read settings
- mem = *paddr;
- *paddr;
- mem = (mem & ~mask) | (value & mask);
- // Write appended setting
- *paddr = mem;
- *paddr = mem;
- count++;
- }
- if (count == 0)
- return false;
- else
- return true;
- }
- #if ENABLE_INT_NONO
- static bool minion_init_gpio_interrupt(struct cgpu_info *minioncgpu, struct minion_info *minioninfo)
- {
- char pindir[64], ena[64], pin[8], dir[64], edge[64], act[64];
- struct stat st;
- int file, err;
- ssize_t ret;
- snprintf(pindir, sizeof(pindir), MINION_GPIO_SYS MINION_GPIO_PIN,
- MINION_GPIO_RESULT_INT_PIN);
- memset(&st, 0, sizeof(st));
- if (stat(pindir, &st) == 0) { // already exists
- if (!S_ISDIR(st.st_mode)) {
- applog(LOG_ERR, "%s: failed1 to enable GPIO pin %d interrupt"
- " - not a directory",
- minioncgpu->drv->dname,
- MINION_GPIO_RESULT_INT_PIN);
- return false;
- }
- } else {
- snprintf(ena, sizeof(ena), MINION_GPIO_SYS MINION_GPIO_ENA);
- file = open(ena, O_WRONLY | O_SYNC);
- if (file == -1) {
- applog(LOG_ERR, "%s: failed2 to enable GPIO pin %d interrupt (%d)"
- " - you need to be root?",
- minioncgpu->drv->dname,
- MINION_GPIO_RESULT_INT_PIN,
- errno);
- return false;
- }
- snprintf(pin, sizeof(pin), MINION_GPIO_ENA_VAL, MINION_GPIO_RESULT_INT_PIN);
- ret = write(file, pin, (size_t)strlen(pin));
- if (ret != (ssize_t)strlen(pin)) {
- if (ret < 0)
- err = errno;
- else
- err = (int)ret;
- close(file);
- applog(LOG_ERR, "%s: failed3 to enable GPIO pin %d interrupt (%d:%d)",
- minioncgpu->drv->dname,
- MINION_GPIO_RESULT_INT_PIN,
- err, (int)strlen(pin));
- return false;
- }
- close(file);
- // Check again if it exists
- memset(&st, 0, sizeof(st));
- if (stat(pindir, &st) != 0) {
- applog(LOG_ERR, "%s: failed4 to enable GPIO pin %d interrupt (%d)",
- minioncgpu->drv->dname,
- MINION_GPIO_RESULT_INT_PIN,
- errno);
- return false;
- }
- }
- // Set the pin attributes
- // Direction
- snprintf(dir, sizeof(dir), MINION_GPIO_SYS MINION_GPIO_PIN MINION_GPIO_DIR,
- MINION_GPIO_RESULT_INT_PIN);
- file = open(dir, O_WRONLY | O_SYNC);
- if (file == -1) {
- applog(LOG_ERR, "%s: failed5 to enable GPIO pin %d interrupt (%d)"
- " - you need to be root?",
- minioncgpu->drv->dname,
- MINION_GPIO_RESULT_INT_PIN,
- errno);
- return false;
- }
- ret = write(file, MINION_GPIO_DIR_READ, (size_t)strlen(MINION_GPIO_DIR_READ));
- if (ret != (ssize_t)strlen(MINION_GPIO_DIR_READ)) {
- if (ret < 0)
- err = errno;
- else
- err = (int)ret;
- close(file);
- applog(LOG_ERR, "%s: failed6 to enable GPIO pin %d interrupt (%d:%d)",
- minioncgpu->drv->dname,
- MINION_GPIO_RESULT_INT_PIN,
- err, (int)strlen(MINION_GPIO_DIR_READ));
- return false;
- }
- close(file);
- // Edge
- snprintf(edge, sizeof(edge), MINION_GPIO_SYS MINION_GPIO_PIN MINION_GPIO_EDGE,
- MINION_GPIO_RESULT_INT_PIN);
- file = open(edge, O_WRONLY | O_SYNC);
- if (file == -1) {
- applog(LOG_ERR, "%s: failed7 to enable GPIO pin %d interrupt (%d)",
- minioncgpu->drv->dname,
- MINION_GPIO_RESULT_INT_PIN,
- errno);
- return false;
- }
- ret = write(file, MINION_GPIO_EDGE_RISING, (size_t)strlen(MINION_GPIO_EDGE_RISING));
- if (ret != (ssize_t)strlen(MINION_GPIO_EDGE_RISING)) {
- if (ret < 0)
- err = errno;
- else
- err = (int)ret;
- close(file);
- applog(LOG_ERR, "%s: failed8 to enable GPIO pin %d interrupt (%d:%d)",
- minioncgpu->drv->dname,
- MINION_GPIO_RESULT_INT_PIN,
- err, (int)strlen(MINION_GPIO_EDGE_RISING));
- return false;
- }
- close(file);
- // Active
- snprintf(act, sizeof(act), MINION_GPIO_SYS MINION_GPIO_PIN MINION_GPIO_ACT,
- MINION_GPIO_RESULT_INT_PIN);
- file = open(act, O_WRONLY | O_SYNC);
- if (file == -1) {
- applog(LOG_ERR, "%s: failed9 to enable GPIO pin %d interrupt (%d)",
- minioncgpu->drv->dname,
- MINION_GPIO_RESULT_INT_PIN,
- errno);
- return false;
- }
- ret = write(file, MINION_GPIO_ACT_HI, (size_t)strlen(MINION_GPIO_ACT_HI));
- if (ret != (ssize_t)strlen(MINION_GPIO_ACT_HI)) {
- if (ret < 0)
- err = errno;
- else
- err = (int)ret;
- close(file);
- applog(LOG_ERR, "%s: failed10 to enable GPIO pin %d interrupt (%d:%d)",
- minioncgpu->drv->dname,
- MINION_GPIO_RESULT_INT_PIN,
- err, (int)strlen(MINION_GPIO_ACT_HI));
- return false;
- }
- close(file);
- // Setup fd access to Value
- snprintf(minioninfo->gpiointvalue, sizeof(minioninfo->gpiointvalue),
- MINION_GPIO_SYS MINION_GPIO_PIN MINION_GPIO_VALUE,
- MINION_GPIO_RESULT_INT_PIN);
- minioninfo->gpiointfd = open(minioninfo->gpiointvalue, O_RDONLY);
- if (minioninfo->gpiointfd == -1) {
- applog(LOG_ERR, "%s: failed11 to enable GPIO pin %d interrupt (%d)",
- minioncgpu->drv->dname,
- MINION_GPIO_RESULT_INT_PIN,
- errno);
- return false;
- }
- return true;
- }
- #endif
- // Default meaning all cores
- static void default_all_cores(uint8_t *cores)
- {
- int i;
- // clear all bits
- for (i = 0; i < (int)(DATA_SIZ * MINION_CORE_REPS); i++)
- cores[i] = 0x00;
- // enable (only) all cores
- for (i = 0; i < MINION_CORES; i++)
- ENABLE_CORE(cores, i);
- }
- static void minion_process_options(struct minion_info *minioninfo)
- {
- int last_freq, last_temp;
- char *freq, *temp, *core, *comma, *buf, *plus, *minus;
- uint8_t last_cores[DATA_SIZ*MINION_CORE_REPS];
- int i, core1, core2;
- bool cleared;
- if (opt_minion_spireset && *opt_minion_spireset) {
- bool is_io = true;
- int val;
- switch (tolower(*opt_minion_spireset)) {
- case 'i':
- is_io = true;
- break;
- case 's':
- is_io = false;
- break;
- default:
- applog(LOG_WARNING, "ERR: Invalid SPI reset '%s'",
- opt_minion_spireset);
- goto skip;
- }
- val = atoi(opt_minion_spireset+1);
- if (val < 0 || val > 9999) {
- applog(LOG_WARNING, "ERR: Invalid SPI reset '%s'",
- opt_minion_spireset);
- } else {
- minioninfo->spi_reset_io = is_io;
- minioninfo->spi_reset_count = val;
- minioninfo->last_spi_reset = time(NULL);
- }
- }
- skip:
- last_freq = MINION_FREQ_DEF;
- if (opt_minion_freq && *opt_minion_freq) {
- buf = freq = strdup(opt_minion_freq);
- comma = strchr(freq, ',');
- if (comma)
- *(comma++) = '\0';
- for (i = 0; i < (int)MINION_CHIPS; i++) {
- if (freq && isdigit(*freq)) {
- last_freq = (int)(round((double)atoi(freq) / (double)MINION_FREQ_FACTOR)) * MINION_FREQ_FACTOR;
- if (last_freq < MINION_FREQ_MIN)
- last_freq = MINION_FREQ_MIN;
- if (last_freq > MINION_FREQ_MAX)
- last_freq = MINION_FREQ_MAX;
- freq = comma;
- if (comma) {
- comma = strchr(freq, ',');
- if (comma)
- *(comma++) = '\0';
- }
- }
- minioninfo->init_freq[i] = last_freq;
- }
- free(buf);
- }
- last_temp = MINION_TEMP_CTL_DEF;
- if (opt_minion_temp && *opt_minion_temp) {
- buf = temp = strdup(opt_minion_temp);
- comma = strchr(temp, ',');
- if (comma)
- *(comma++) = '\0';
- for (i = 0; i < (int)MINION_CHIPS; i++) {
- if (temp) {
- if (isdigit(*temp)) {
- last_temp = atoi(temp);
- last_temp -= (last_temp % MINION_TEMP_CTL_STEP);
- if (last_temp < MINION_TEMP_CTL_MIN_VALUE)
- last_temp = MINION_TEMP_CTL_MIN_VALUE;
- if (last_temp > MINION_TEMP_CTL_MAX_VALUE)
- last_temp = MINION_TEMP_CTL_MAX_VALUE;
- } else {
- if (strcasecmp(temp, MINION_TEMP_DISABLE) == 0)
- last_temp = MINION_TEMP_CTL_DISABLE;
- }
- temp = comma;
- if (comma) {
- comma = strchr(temp, ',');
- if (comma)
- *(comma++) = '\0';
- }
- }
- minioninfo->init_temp[i] = last_temp;
- }
- free(buf);
- }
- default_all_cores(&(last_cores[0]));
- // default to all cores until we find valid data
- cleared = false;
- if (opt_minion_cores && *opt_minion_cores) {
- buf = core = strdup(opt_minion_cores);
- comma = strchr(core, ',');
- if (comma)
- *(comma++) = '\0';
- for (i = 0; i < (int)MINION_CHIPS; i++) {
- // default to previous until we find valid data
- cleared = false;
- if (core) {
- plus = strchr(core, '+');
- if (plus)
- *(plus++) = '\0';
- while (core) {
- minus = strchr(core, '-');
- if (minus)
- *(minus++) = '\0';
- if (isdigit(*core)) {
- core1 = atoi(core);
- if (core1 >= 0 && core1 < MINION_CORES) {
- if (!minus) {
- if (!cleared) {
- memset(last_cores, 0, sizeof(last_cores));
- cleared = true;
- }
- ENABLE_CORE(last_cores, core1);
- } else {
- core2 = atoi(minus);
- if (core2 >= core1) {
- if (core2 >= MINION_CORES)
- core2 = MINION_CORES - 1;
- while (core1 <= core2) {
- if (!cleared) {
- memset(last_cores, 0,
- sizeof(last_cores));
- cleared = true;
- }
- ENABLE_CORE(last_cores, core1);
- core1++;
- }
- }
- }
- }
- } else {
- if (strcasecmp(core, MINION_CORE_ALL) == 0)
- default_all_cores(&(last_cores[0]));
- }
- core = plus;
- if (plus) {
- plus = strchr(core, '+');
- if (plus)
- *(plus++) = '\0';
- }
- }
- core = comma;
- if (comma) {
- comma = strchr(core, ',');
- if (comma)
- *(comma++) = '\0';
- }
- }
- memcpy(&(minioninfo->init_cores[i][0]), &(last_cores[0]), sizeof(last_cores));
- }
- free(buf);
- }
- }
- static void minion_detect(bool hotplug)
- {
- struct cgpu_info *minioncgpu = NULL;
- struct minion_info *minioninfo = NULL;
- char buf[512];
- size_t off;
- int i;
- if (hotplug)
- return;
- define_test();
- minioncgpu = calloc(1, sizeof(*minioncgpu));
- if (unlikely(!minioncgpu))
- quithere(1, "Failed to calloc minioncgpu");
- minioncgpu->drv = &minion_drv;
- minioncgpu->deven = DEV_ENABLED;
- minioncgpu->threads = 1;
- minioninfo = calloc(1, sizeof(*minioninfo)); // everything '0'
- if (unlikely(!minioninfo))
- quithere(1, "Failed to calloc minioninfo");
- minioncgpu->device_data = (void *)minioninfo;
- if (!minion_init_spi(minioncgpu, minioninfo, MINION_SPI_BUS, MINION_SPI_CHIP, false))
- goto unalloc;
- #if ENABLE_INT_NONO
- if (!minion_init_gpio_interrupt(minioncgpu, minioninfo))
- goto unalloc;
- #endif
- if (usepins) {
- if (!minion_setup_chip_select(minioncgpu, minioninfo))
- goto unalloc;
- }
- mutex_init(&(minioninfo->spi_lock));
- mutex_init(&(minioninfo->sta_lock));
- for (i = 0; i < (int)MINION_CHIPS; i++) {
- minioninfo->init_freq[i] = MINION_FREQ_DEF;
- minioninfo->init_temp[i] = MINION_TEMP_CTL_DEF;
- default_all_cores(&(minioninfo->init_cores[i][0]));
- }
- minion_process_options(minioninfo);
- applog(LOG_WARNING, "%s: checking for chips ...", minioncgpu->drv->dname);
- minion_detect_chips(minioncgpu, minioninfo);
- buf[0] = '\0';
- for (i = 0; i < (int)MINION_CHIPS; i++) {
- if (minioninfo->has_chip[i]) {
- off = strlen(buf);
- snprintf(buf + off, sizeof(buf) - off, " %d:%d/%d",
- i, minioninfo->chip_pin[i], (int)(minioninfo->chipid[i]));
- }
- }
- applog(LOG_WARNING, "%s: found %d chip%s:%s",
- minioncgpu->drv->dname, minioninfo->chips,
- (minioninfo->chips == 1) ? "" : "s", buf);
- if (minioninfo->chips == 0)
- goto cleanup;
- if (!add_cgpu(minioncgpu))
- goto cleanup;
- mutex_init(&(minioninfo->nonce_lock));
- minioninfo->wfree_list = k_new_list("Work", sizeof(WORK_ITEM),
- ALLOC_WORK_ITEMS, LIMIT_WORK_ITEMS, true);
- minioninfo->wwork_list = k_new_store(minioninfo->wfree_list);
- minioninfo->wstale_list = k_new_store(minioninfo->wfree_list);
- // Initialise them all in case we later decide to enable chips
- for (i = 0; i < (int)MINION_CHIPS; i++) {
- minioninfo->wque_list[i] = k_new_store(minioninfo->wfree_list);
- minioninfo->wchip_list[i] = k_new_store(minioninfo->wfree_list);
- }
- minioninfo->tfree_list = k_new_list("Task", sizeof(TASK_ITEM),
- ALLOC_TASK_ITEMS, LIMIT_TASK_ITEMS, true);
- minioninfo->task_list = k_new_store(minioninfo->tfree_list);
- minioninfo->treply_list = k_new_store(minioninfo->tfree_list);
- minioninfo->rfree_list = k_new_list("Reply", sizeof(RES_ITEM),
- ALLOC_RES_ITEMS, LIMIT_RES_ITEMS, true);
- minioninfo->rnonce_list = k_new_store(minioninfo->rfree_list);
- minioninfo->history_gen = MINION_MAX_RESET_CHECK;
- minioninfo->hfree_list = k_new_list("History", sizeof(HIST_ITEM),
- ALLOC_HIST_ITEMS, LIMIT_HIST_ITEMS, true);
- for (i = 0; i < (int)MINION_CHIPS; i++)
- minioninfo->hchip_list[i] = k_new_store(minioninfo->hfree_list);
- minioninfo->pfree_list = k_new_list("Performance", sizeof(PERF_ITEM),
- ALLOC_PERF_ITEMS, LIMIT_PERF_ITEMS, true);
- for (i = 0; i < (int)MINION_CHIPS; i++)
- minioninfo->p_list[i] = k_new_store(minioninfo->pfree_list);
- minioninfo->xfree_list = k_new_list("0xff", sizeof(XFF_ITEM),
- ALLOC_XFF_ITEMS, LIMIT_XFF_ITEMS, true);
- minioninfo->xff_list = k_new_store(minioninfo->xfree_list);
- cgsem_init(&(minioninfo->task_ready));
- cgsem_init(&(minioninfo->nonce_ready));
- cgsem_init(&(minioninfo->scan_work));
- minioninfo->initialised = true;
- dupalloc(minioncgpu, 10);
- return;
- cleanup:
- close(minioninfo->gpiointfd);
- close(minioninfo->spifd);
- mutex_destroy(&(minioninfo->sta_lock));
- mutex_destroy(&(minioninfo->spi_lock));
- unalloc:
- free(minioninfo);
- free(minioncgpu);
- }
- static char *minion_api_set(struct cgpu_info *minioncgpu, char *option, char *setting, char *replybuf, size_t siz)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- int chip, val;
- char *colon;
- if (strcasecmp(option, "help") == 0) {
- snprintf(replybuf, siz, "reset: chip 0-%d freq: 0-%d:%d-%d "
- "ledcount: 0-100 ledlimit: 0-200 "
- "spidelay: 0-9999 spireset i|s0-9999 "
- "spisleep: 0-9999",
- minioninfo->chips - 1,
- minioninfo->chips - 1,
- MINION_FREQ_MIN, MINION_FREQ_MAX);
- return replybuf;
- }
- if (strcasecmp(option, "reset") == 0) {
- if (!setting || !*setting) {
- snprintf(replybuf, siz, "missing chip to reset");
- return replybuf;
- }
- chip = atoi(setting);
- if (chip < 0 || chip >= minioninfo->chips) {
- snprintf(replybuf, siz, "invalid reset: chip '%s' valid range 0-%d",
- setting,
- minioninfo->chips);
- return replybuf;
- }
- if (!minioninfo->has_chip[chip]) {
- snprintf(replybuf, siz, "unable to reset chip %d - chip disabled",
- chip);
- return replybuf;
- }
- minioninfo->flag_reset[chip] = true;
- return NULL;
- }
- // This sets up a freq step up/down to the given freq without a reset
- if (strcasecmp(option, "freq") == 0) {
- if (!setting || !*setting) {
- snprintf(replybuf, siz, "missing chip:freq");
- return replybuf;
- }
- colon = strchr(setting, ':');
- if (!colon) {
- snprintf(replybuf, siz, "missing ':' for chip:freq");
- return replybuf;
- }
- *(colon++) = '\0';
- if (!*colon) {
- snprintf(replybuf, siz, "missing freq in chip:freq");
- return replybuf;
- }
- chip = atoi(setting);
- if (chip < 0 || chip >= minioninfo->chips) {
- snprintf(replybuf, siz, "invalid freq: chip '%s' valid range 0-%d",
- setting,
- minioninfo->chips);
- return replybuf;
- }
- if (!minioninfo->has_chip[chip]) {
- snprintf(replybuf, siz, "unable to modify chip %d - chip not enabled",
- chip);
- return replybuf;
- }
- val = atoi(colon);
- if (val < MINION_FREQ_MIN || val > MINION_FREQ_MAX) {
- snprintf(replybuf, siz, "invalid freq: '%s' valid range %d-%d",
- setting,
- MINION_FREQ_MIN, MINION_FREQ_MAX);
- return replybuf;
- }
- int want_freq = val - (val % MINION_FREQ_FACTOR);
- int start_freq = minioninfo->init_freq[chip];
- int freqms;
- if (want_freq != start_freq) {
- minioninfo->changing[chip] = false;
- freqms = opt_minion_freqchange;
- freqms /= ((want_freq - start_freq) / MINION_FREQ_FACTOR);
- if (freqms < 0)
- freqms = -freqms;
- minioninfo->freqms[chip] = freqms;
- minioninfo->want_freq[chip] = want_freq;
- cgtime(&(minioninfo->lastfreq[chip]));
- minioninfo->changing[chip] = true;
- }
- return NULL;
- }
- if (strcasecmp(option, "ledcount") == 0) {
- if (!setting || !*setting) {
- snprintf(replybuf, siz, "missing ledcount value");
- return replybuf;
- }
- val = atoi(setting);
- if (val < 0 || val > 100) {
- snprintf(replybuf, siz, "invalid ledcount: '%s' valid range 0-100",
- setting);
- return replybuf;
- }
- opt_minion_ledcount = val;
- return NULL;
- }
- if (strcasecmp(option, "ledlimit") == 0) {
- if (!setting || !*setting) {
- snprintf(replybuf, siz, "missing ledlimit value");
- return replybuf;
- }
- val = atoi(setting);
- if (val < 0 || val > 200) {
- snprintf(replybuf, siz, "invalid ledlimit: GHs '%s' valid range 0-200",
- setting);
- return replybuf;
- }
- opt_minion_ledlimit = val;
- return NULL;
- }
- if (strcasecmp(option, "spidelay") == 0) {
- if (!setting || !*setting) {
- snprintf(replybuf, siz, "missing spidelay value");
- return replybuf;
- }
- val = atoi(setting);
- if (val < 0 || val > 9999) {
- snprintf(replybuf, siz, "invalid spidelay: ms '%s' valid range 0-9999",
- setting);
- return replybuf;
- }
- opt_minion_spidelay = val;
- return NULL;
- }
- if (strcasecmp(option, "spireset") == 0) {
- bool is_io = true;
- if (!setting || !*setting) {
- snprintf(replybuf, siz, "missing spireset value");
- return replybuf;
- }
- switch (tolower(*setting)) {
- case 'i':
- is_io = true;
- break;
- case 's':
- is_io = false;
- break;
- default:
- snprintf(replybuf, siz, "invalid spireset: '%s' must start with i or s",
- setting);
- return replybuf;
- }
- val = atoi(setting+1);
- if (val < 0 || val > 9999) {
- snprintf(replybuf, siz, "invalid spireset: %c '%s' valid range 0-9999",
- *setting, setting+1);
- return replybuf;
- }
- minioninfo->spi_reset_io = is_io;
- minioninfo->spi_reset_count = val;
- minioninfo->last_spi_reset = time(NULL);
- return NULL;
- }
- if (strcasecmp(option, "spisleep") == 0) {
- if (!setting || !*setting) {
- snprintf(replybuf, siz, "missing spisleep value");
- return replybuf;
- }
- val = atoi(setting);
- if (val < 0 || val > 9999) {
- snprintf(replybuf, siz, "invalid spisleep: ms '%s' valid range 0-9999",
- setting);
- return replybuf;
- }
- opt_minion_spisleep = val;
- return NULL;
- }
- if (strcasecmp(option, "spiusec") == 0) {
- if (!setting || !*setting) {
- snprintf(replybuf, siz, "missing spiusec value");
- return replybuf;
- }
- val = atoi(setting);
- if (val < 0 || val > 9999) {
- snprintf(replybuf, siz, "invalid spiusec: '%s' valid range 0-9999",
- setting);
- return replybuf;
- }
- opt_minion_spiusec = val;
- return NULL;
- }
- snprintf(replybuf, siz, "Unknown option: %s", option);
- return replybuf;
- }
- static void minion_identify(__maybe_unused struct cgpu_info *minioncgpu)
- {
- // flash a led
- }
- /*
- * SPI/ioctl write thread
- * Non urgent work is to keep the queue full
- * Urgent work is when an LP occurs (or the queue is empty/low)
- */
- static void *minion_spi_write(void *userdata)
- {
- struct cgpu_info *minioncgpu = (struct cgpu_info *)userdata;
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- K_ITEM *item, *tail, *task, *work;
- TASK_ITEM *titem;
- applog(MINION_LOG, "%s%i: SPI writing...",
- minioncgpu->drv->name, minioncgpu->device_id);
- // Wait until we're ready
- while (minioncgpu->shutdown == false) {
- if (minioninfo->initialised) {
- break;
- }
- cgsleep_ms(1); // asap to start mining
- }
- // TODO: combine all urgent into a single I/O?
- // Then combine all state 1 for the same chip into a single I/O ?
- // (then again for state 2?)
- while (minioncgpu->shutdown == false) {
- item = NULL;
- K_WLOCK(minioninfo->task_list);
- tail = minioninfo->task_list->tail;
- if (tail) {
- // Find first urgent item
- item = tail;
- while (item && !(DATA_TASK(item)->urgent))
- item = item->prev;
- // No urgent items, just do the tail
- if (!item)
- item = tail;
- k_unlink_item(minioninfo->task_list, item);
- }
- K_WUNLOCK(minioninfo->task_list);
- if (item) {
- bool do_txrx = true;
- bool store_reply = true;
- struct timeval now;
- double howlong;
- int i;
- titem = DATA_TASK(item);
- switch (titem->address) {
- // TODO: case MINION_SYS_TEMP_CTL:
- // TODO: case MINION_SYS_FREQ_CTL:
- case READ_ADDR(MINION_SYS_CHIP_STA):
- case WRITE_ADDR(MINION_SYS_SPI_LED):
- case WRITE_ADDR(MINION_SYS_RSTN_CTL):
- case WRITE_ADDR(MINION_SYS_INT_CLR):
- case READ_ADDR(MINION_SYS_IDLE_CNT):
- case READ_ADDR(MINION_CORE_ENA0_31):
- case READ_ADDR(MINION_CORE_ENA32_63):
- case READ_ADDR(MINION_CORE_ENA64_95):
- case READ_ADDR(MINION_CORE_ENA96_98):
- case READ_ADDR(MINION_CORE_ACT0_31):
- case READ_ADDR(MINION_CORE_ACT32_63):
- case READ_ADDR(MINION_CORE_ACT64_95):
- case READ_ADDR(MINION_CORE_ACT96_98):
- store_reply = false;
- break;
- case WRITE_ADDR(MINION_QUE_0):
- //applog(LOG_ERR, "%s%i: ZZZ send task_id 0x%04x - chip %d", minioncgpu->drv->name, minioncgpu->device_id, titem->task_id, titem->chip);
- store_reply = false;
- break;
- default:
- do_txrx = false;
- titem->reply = MINION_UNEXPECTED_TASK;
- applog(LOG_ERR, "%s%i: Unexpected task address 0x%02x (%s)",
- minioncgpu->drv->name, minioncgpu->device_id,
- (unsigned int)(titem->address),
- addr2txt(titem->address));
- break;
- }
- if (do_txrx) {
- if (titem->witem) {
- cgtime(&now);
- howlong = tdiff(&now, &(DATA_WORK(titem->witem)->created));
- minioninfo->wt_work++;
- minioninfo->wt_time += howlong;
- if (minioninfo->wt_min == 0 || minioninfo->wt_min > howlong)
- minioninfo->wt_min = howlong;
- else if (minioninfo->wt_max < howlong)
- minioninfo->wt_max = howlong;
- for (i = 0; i < TIME_BANDS; i++) {
- if (howlong < time_bands[i]) {
- minioninfo->wt_bands[i]++;
- break;
- }
- }
- if (i >= TIME_BANDS)
- minioninfo->wt_bands[TIME_BANDS]++;
- }
- minion_txrx(titem);
- int chip = titem->chip;
- switch (titem->address) {
- case READ_ADDR(MINION_SYS_CHIP_STA):
- if (titem->reply >= (int)(titem->osiz)) {
- uint8_t *rep = &(titem->rbuf[titem->osiz - titem->rsiz]);
- mutex_lock(&(minioninfo->sta_lock));
- minioninfo->chip_status[chip].temp = STA_TEMP(rep);
- minioninfo->chip_status[chip].cores = STA_CORES(rep);
- minioninfo->chip_status[chip].freq = STA_FREQ(rep);
- mutex_unlock(&(minioninfo->sta_lock));
- if (minioninfo->chip_status[chip].overheat) {
- switch (STA_TEMP(rep)) {
- case MINION_TEMP_40:
- case MINION_TEMP_60:
- case MINION_TEMP_80:
- cgtime(&(minioninfo->chip_status[chip].lastrecover));
- minioninfo->chip_status[chip].overheat = false;
- applog(LOG_WARNING, "%s%d: chip %d cooled, restarting",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- chip);
- cgtime(&(minioninfo->chip_status[chip].lastrecover));
- minioninfo->chip_status[chip].overheattime +=
- tdiff(&(minioninfo->chip_status[chip].lastrecover),
- &(minioninfo->chip_status[chip].lastoverheat));
- break;
- default:
- break;
- }
- } else {
- if (opt_minion_overheat && STA_TEMP(rep) == MINION_TEMP_OVER) {
- cgtime(&(minioninfo->chip_status[chip].lastoverheat));
- minioninfo->chip_status[chip].overheat = true;
- applog(LOG_WARNING, "%s%d: chip %d overheated! idling",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- chip);
- K_WLOCK(minioninfo->tfree_list);
- task = k_unlink_head(minioninfo->tfree_list);
- DATA_TASK(task)->tid = ++(minioninfo->next_tid);
- DATA_TASK(task)->chip = chip;
- DATA_TASK(task)->write = true;
- DATA_TASK(task)->address = MINION_SYS_RSTN_CTL;
- DATA_TASK(task)->task_id = 0; // ignored
- DATA_TASK(task)->wsiz = MINION_SYS_SIZ;
- DATA_TASK(task)->rsiz = 0;
- DATA_TASK(task)->wbuf[0] = SYS_RSTN_CTL_FLUSH;
- DATA_TASK(task)->wbuf[1] = 0;
- DATA_TASK(task)->wbuf[2] = 0;
- DATA_TASK(task)->wbuf[3] = 0;
- DATA_TASK(task)->urgent = true;
- k_add_head(minioninfo->task_list, task);
- K_WUNLOCK(minioninfo->tfree_list);
- minioninfo->chip_status[chip].overheats++;
- }
- }
- }
- break;
- case READ_ADDR(MINION_SYS_IDLE_CNT):
- {
- uint32_t *cnt = (uint32_t *)&(titem->rbuf[titem->osiz - titem->rsiz]);
- minioninfo->chip_status[chip].idle = *cnt;
- }
- break;
- case WRITE_ADDR(MINION_SYS_RSTN_CTL):
- // Do this here after it has actually been flushed
- if ((titem->wbuf[0] & SYS_RSTN_CTL_FLUSH) == SYS_RSTN_CTL_FLUSH) {
- int cnt = 0;
- K_WLOCK(minioninfo->wwork_list);
- work = minioninfo->wchip_list[chip]->head;
- while (work) {
- cnt++;
- DATA_WORK(work)->stale = true;
- work = work->next;
- }
- minioninfo->chip_status[chip].chipwork = 0;
- minioninfo->chip_status[chip].realwork = 0;
- minioninfo->wchip_staled += cnt;
- #if MINION_SHOW_IO
- applog(IOCTRL_LOG, "RSTN chip %d (cnt=%d) cw0=%u rw0=%u qw=%u",
- chip, cnt,
- minioninfo->chip_status[chip].chipwork,
- minioninfo->chip_status[chip].realwork,
- minioninfo->chip_status[chip].quework);
- #endif
- K_WUNLOCK(minioninfo->wwork_list);
- }
- break;
- case WRITE_ADDR(MINION_QUE_0):
- K_WLOCK(minioninfo->wchip_list[chip]);
- k_unlink_item(minioninfo->wque_list[chip], titem->witem);
- k_add_head(minioninfo->wchip_list[chip], titem->witem);
- DATA_WORK(titem->witem)->ioseq = titem->ioseq;
- minioninfo->chip_status[chip].quework--;
- minioninfo->chip_status[chip].chipwork++;
- #if MINION_SHOW_IO
- applog(IOCTRL_LOG, "QUE_0 chip %d cw+1=%u rw=%u qw-1=%u",
- chip,
- minioninfo->chip_status[chip].chipwork,
- minioninfo->chip_status[chip].realwork,
- minioninfo->chip_status[chip].quework);
- #endif
- K_WUNLOCK(minioninfo->wchip_list[chip]);
- applog(LOG_DEBUG, "%s%d: task 0x%04x sent to chip %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- titem->task_id, chip);
- break;
- case READ_ADDR(MINION_CORE_ENA0_31):
- case READ_ADDR(MINION_CORE_ENA32_63):
- case READ_ADDR(MINION_CORE_ENA64_95):
- case READ_ADDR(MINION_CORE_ENA96_98):
- {
- uint32_t *rep = (uint32_t *)&(titem->rbuf[titem->osiz - titem->rsiz]);
- int off = titem->address - READ_ADDR(MINION_CORE_ENA0_31);
- minioninfo->chip_core_ena[off][chip] = *rep;
- }
- break;
- case READ_ADDR(MINION_CORE_ACT0_31):
- case READ_ADDR(MINION_CORE_ACT32_63):
- case READ_ADDR(MINION_CORE_ACT64_95):
- case READ_ADDR(MINION_CORE_ACT96_98):
- {
- uint32_t *rep = (uint32_t *)&(titem->rbuf[titem->osiz - titem->rsiz]);
- int off = titem->address - READ_ADDR(MINION_CORE_ACT0_31);
- minioninfo->chip_core_act[off][chip] = *rep;
- }
- break;
- case WRITE_ADDR(MINION_SYS_INT_CLR):
- case WRITE_ADDR(MINION_SYS_SPI_LED):
- break;
- default:
- break;
- }
- }
- K_WLOCK(minioninfo->treply_list);
- if (store_reply)
- k_add_head(minioninfo->treply_list, item);
- else
- k_free_head(minioninfo->tfree_list, item);
- K_WUNLOCK(minioninfo->treply_list);
- /*
- * Always check for the next task immediately if we just did one
- * i.e. empty the task queue
- */
- continue;
- }
- cgsem_mswait(&(minioninfo->task_ready), MINION_TASK_mS);
- }
- return NULL;
- }
- /*
- * SPI/ioctl reply thread
- * ioctl done every interrupt or MINION_REPLY_mS checking for results
- */
- static void *minion_spi_reply(void *userdata)
- {
- struct cgpu_info *minioncgpu = (struct cgpu_info *)userdata;
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- struct minion_result *result1, *result2, *use1, *use2;
- K_ITEM *item;
- TASK_ITEM fifo_task, res1_task, res2_task;
- int chip, resoff;
- bool somelow;
- struct timeval now;
- #if ENABLE_INT_NONO
- uint64_t ioseq;
- TASK_ITEM clr_task;
- struct pollfd pfd;
- struct minion_header *head;
- uint8_t rbuf[MINION_BUFSIZ];
- uint8_t wbuf[MINION_BUFSIZ];
- uint32_t wsiz, rsiz;
- int ret, reply;
- bool gotreplies = false;
- #endif
- applog(MINION_LOG, "%s%i: SPI replying...",
- minioncgpu->drv->name, minioncgpu->device_id);
- // Wait until we're ready
- while (minioncgpu->shutdown == false) {
- if (minioninfo->initialised) {
- break;
- }
- cgsleep_ms(2);
- }
- fifo_task.chip = 0;
- fifo_task.write = false;
- fifo_task.address = MINION_SYS_FIFO_STA;
- fifo_task.wsiz = 0;
- fifo_task.rsiz = MINION_SYS_SIZ;
- res1_task.chip = 0;
- res1_task.write = false;
- if (minreread)
- res1_task.address = MINION_RES_PEEK;
- else
- res1_task.address = MINION_RES_DATA;
- res1_task.wsiz = 0;
- res1_task.rsiz = MINION_RES_DATA_SIZ;
- res2_task.chip = 0;
- res2_task.write = false;
- res2_task.address = MINION_RES_DATA;
- res2_task.wsiz = 0;
- res2_task.rsiz = MINION_RES_DATA_SIZ;
- #if ENABLE_INT_NONO
- // Clear RESULT_INT after reading all results
- clr_task.chip = 0;
- clr_task.write = true;
- clr_task.address = MINION_SYS_INT_CLR;
- clr_task.wsiz = MINION_SYS_SIZ;
- clr_task.rsiz = 0;
- clr_task.wbuf[0] = MINION_RESULT_INT;
- clr_task.wbuf[1] = 0;
- clr_task.wbuf[2] = 0;
- clr_task.wbuf[3] = 0;
- memset(&pfd, 0, sizeof(pfd));
- pfd.fd = minioninfo->gpiointfd;
- pfd.events = POLLPRI;
- head = (struct minion_header *)wbuf;
- SET_HEAD_SIZ(head, MINION_SYS_SIZ);
- wsiz = HSIZE() + MINION_SYS_SIZ;
- rsiz = MINION_SYS_SIZ; // for READ, use 0 for WRITE
- #endif
- somelow = false;
- while (minioncgpu->shutdown == false) {
- for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
- if (minioninfo->has_chip[chip]) {
- int tries = 0;
- uint8_t res, cmd;
- if (minioninfo->changing[chip] &&
- ms_tdiff(&now, &minioninfo->lastfreq[chip]) >
- minioninfo->freqms[chip]) {
- int want_freq = minioninfo->want_freq[chip];
- int init_freq = minioninfo->init_freq[chip];
- if (want_freq > init_freq) {
- minioninfo->init_freq[chip] += MINION_FREQ_FACTOR;
- init_freq += MINION_FREQ_FACTOR;
- set_freq(minioncgpu, minioninfo, chip, init_freq);
- } else if (want_freq < init_freq) {
- minioninfo->init_freq[chip] -= MINION_FREQ_FACTOR;
- init_freq -= MINION_FREQ_FACTOR;
- set_freq(minioncgpu, minioninfo, chip, init_freq);
- }
- if (init_freq == want_freq)
- minioninfo->changing[chip] = false;
- }
- while (++tries < 4) {
- res = cmd = 0;
- fifo_task.chip = chip;
- fifo_task.reply = 0;
- minion_txrx(&fifo_task);
- if (fifo_task.reply <= 0) {
- minioninfo->spi_errors++;
- minioninfo->fifo_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- break;
- } else {
- if (fifo_task.reply < (int)(fifo_task.osiz)) {
- char *buf = bin2hex((unsigned char *)(&(fifo_task.rbuf[fifo_task.osiz - fifo_task.rsiz])),
- (int)(fifo_task.rsiz));
- applog(LOG_DEBUG, "%s%i: Chip %d Bad fifo reply (%s) size %d, should be %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, buf,
- fifo_task.reply, (int)(fifo_task.osiz));
- free(buf);
- minioninfo->spi_errors++;
- minioninfo->fifo_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- } else {
- if (fifo_task.reply > (int)(fifo_task.osiz)) {
- applog(LOG_DEBUG, "%s%i: Chip %d Unexpected fifo reply size %d, "
- "expected only %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, fifo_task.reply, (int)(fifo_task.osiz));
- }
- res = FIFO_RES(fifo_task.rbuf, fifo_task.osiz - fifo_task.rsiz);
- cmd = FIFO_CMD(fifo_task.rbuf, fifo_task.osiz - fifo_task.rsiz);
- // valid reply?
- if (res <= MINION_QUE_MAX && cmd <= MINION_QUE_MAX)
- break;
- applog(LOG_DEBUG, "%s%i: Chip %d Bad fifo reply res %d (max is %d) "
- "cmd %d (max is %d)",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, (int)res, MINION_QUE_MAX,
- (int)cmd, MINION_QUE_MAX);
- minioninfo->spi_errors++;
- minioninfo->fifo_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- }
- }
- }
- // Give up on this chip this round
- if (tries >= 4)
- continue;
- K_WLOCK(minioninfo->wwork_list);
- // have to just assume it's always correct since we can't verify it
- minioninfo->chip_status[chip].realwork = (uint32_t)cmd;
- #if MINION_SHOW_IO
- applog(IOCTRL_LOG, "SetReal chip %d cw=%u rw==%u qw=%u",
- chip,
- minioninfo->chip_status[chip].chipwork,
- minioninfo->chip_status[chip].realwork,
- minioninfo->chip_status[chip].quework);
- #endif
- K_WUNLOCK(minioninfo->wwork_list);
- if (cmd < MINION_QUE_LOW) {
- somelow = true;
- // Flag it in case the count is wrong
- K_WLOCK(minioninfo->wwork_list);
- minioninfo->chip_status[chip].islow = true;
- minioninfo->chip_status[chip].lowcount = (int)cmd;
- K_WUNLOCK(minioninfo->wwork_list);
- }
- /*
- * Chip has results?
- * You can't request results unless it says it has some.
- * We don't ever directly flush the output queue while processing
- * (except at startup) so the answer is always valid
- * i.e. there could be more, but never less ... unless the reply was corrupt
- */
- if (res > MINION_MAX_RES) {
- applog(LOG_ERR, "%s%i: Large work reply chip %d res %d",
- minioncgpu->drv->name, minioncgpu->device_id, chip, res);
- minioninfo->spi_errors++;
- minioninfo->fifo_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- res = 1; // Just read one result
- }
- //else
- //applog(LOG_ERR, "%s%i: work reply res %d", minioncgpu->drv->name, minioncgpu->device_id, res);
- uint8_t left = res;
- int peeks = 0;
- while (left > 0) {
- res = left;
- if (res > MINION_MAX_RES)
- res = MINION_MAX_RES;
- left -= res;
- repeek:
- res1_task.chip = chip;
- res1_task.reply = 0;
- res1_task.rsiz = res * MINION_RES_DATA_SIZ;
- minion_txrx(&res1_task);
- if (res1_task.reply <= 0)
- break;
- else {
- cgtime(&now);
- if (res1_task.reply < (int)MINION_RES_DATA_SIZ) {
- char *buf = bin2hex((unsigned char *)(&(res1_task.rbuf[res1_task.osiz - res1_task.rsiz])), (int)(res1_task.rsiz));
- applog(LOG_ERR, "%s%i: Chip %d Bad work reply (%s) size %d, should be at least %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, buf,
- res1_task.reply, (int)MINION_RES_DATA_SIZ);
- free(buf);
- minioninfo->spi_errors++;
- minioninfo->res_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- } else {
- if (res1_task.reply != (int)(res1_task.osiz)) {
- applog(LOG_ERR, "%s%i: Chip %d Unexpected work reply size %d, expected %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, res1_task.reply, (int)(res1_task.osiz));
- minioninfo->spi_errors++;
- minioninfo->res_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- // Can retry a PEEK without losing data
- if (minreread) {
- if (++peeks < 4)
- goto repeek;
- break;
- }
- }
- if (minreread) {
- res2_task.chip = chip;
- res2_task.reply = 0;
- res2_task.rsiz = res * MINION_RES_DATA_SIZ;
- minion_txrx(&res2_task);
- if (res2_task.reply <= 0) {
- minioninfo->spi_errors++;
- minioninfo->res_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- }
- }
- for (resoff = res1_task.osiz - res1_task.rsiz; resoff < (int)res1_task.osiz; resoff += MINION_RES_DATA_SIZ) {
- result1 = (struct minion_result *)&(res1_task.rbuf[resoff]);
- if (minreread && resoff < (int)res2_task.osiz)
- result2 = (struct minion_result *)&(res2_task.rbuf[resoff]);
- else
- result2 = NULL;
- if (IS_RESULT(result1) || (minreread && result2 && IS_RESULT(result2))) {
- K_WLOCK(minioninfo->rfree_list);
- item = k_unlink_head(minioninfo->rfree_list);
- K_WUNLOCK(minioninfo->rfree_list);
- if (IS_RESULT(result1)) {
- use1 = result1;
- if (minreread && result2 && IS_RESULT(result2))
- use2 = result2;
- else
- use2 = NULL;
- } else {
- use1 = result2;
- use2 = NULL;
- minioninfo->use_res2[chip]++;
- }
- //DATA_RES(item)->chip = RES_CHIPID(use1);
- // We can avoid any SPI transmission error of the chip number
- DATA_RES(item)->chip = (uint8_t)chip;
- if (minioninfo->chipid[chip] != RES_CHIPID(use1)) {
- minioninfo->spi_errors++;
- minioninfo->res_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- }
- if (use2 && minioninfo->chipid[chip] != RES_CHIPID(use2)) {
- minioninfo->spi_errors++;
- minioninfo->res_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- }
- DATA_RES(item)->core = RES_CORE(use1);
- DATA_RES(item)->task_id = RES_TASK(use1);
- DATA_RES(item)->nonce = RES_NONCE(use1);
- DATA_RES(item)->no_nonce = !RES_GOLD(use1);
- memcpy(&(DATA_RES(item)->when), &now, sizeof(now));
- applog(LOG_DEBUG, "%s%i: reply task_id 0x%04x"
- " - chip %d - gold %d",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- RES_TASK(use1),
- (int)RES_CHIPID(use1),
- (int)RES_GOLD(use1));
- if (!use2)
- DATA_RES(item)->another = false;
- else {
- DATA_RES(item)->another = true;
- DATA_RES(item)->task_id2 = RES_TASK(use2);
- DATA_RES(item)->nonce2 = RES_NONCE(use2);
- }
- //if (RES_GOLD(use1))
- //applog(MINTASK_LOG, "%s%i: found a result chip %d core %d task 0x%04x nonce 0x%08x gold=%d", minioncgpu->drv->name, minioncgpu->device_id, DATA_RES(item)->chip, DATA_RES(item)->core, DATA_RES(item)->task_id, DATA_RES(item)->nonce, (int)RES_GOLD(use1));
- K_WLOCK(minioninfo->rnonce_list);
- k_add_head(minioninfo->rnonce_list, item);
- K_WUNLOCK(minioninfo->rnonce_list);
- if (!(minioninfo->chip_status[chip].first_nonce.tv_sec)) {
- cgtime(&(minioninfo->chip_status[chip].first_nonce));
- minioninfo->chip_status[chip].from_first_good = 0;
- }
- cgsem_post(&(minioninfo->nonce_ready));
- } else {
- minioninfo->res_err_count[chip]++;
- applog(MINTASK_LOG, "%s%i: Invalid res0 task_id 0x%04x - chip %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- RES_TASK(result1), chip);
- if (minreread && result2) {
- applog(MINTASK_LOG, "%s%i: Invalid res1 task_id 0x%04x - chip %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- RES_TASK(result2), chip);
- }
- }
- }
- }
- }
- }
- }
- }
- if (somelow)
- cgsem_post(&(minioninfo->scan_work));
- #if ENABLE_INT_NONO
- if (gotreplies)
- minion_txrx(&clr_task);
- #endif
- #if !ENABLE_INT_NONO
- cgsleep_ms(MINION_REPLY_mS);
- #else
- // TODO: this is going to require a bit of tuning with 2TH/s mining:
- // The interrupt size MINION_RESULT_INT_SIZE should be high enough to expect
- // most chips to have some results but low enough to cause negligible latency
- // If all chips don't have some results when an interrupt occurs, then it is a waste
- // since we have to check all chips for results anyway since we don't know which one
- // caused the interrupt
- // MINION_REPLY_mS needs to be low enough in the case of bad luck where no chip
- // finds MINION_RESULT_INT_SIZE results in a short amount of time, so we go check
- // them all anyway - to avoid high latency when there are only a few results due to low luck
- ret = poll(&pfd, 1, MINION_REPLY_mS);
- if (ret > 0) {
- bool gotres;
- int c;
- minioninfo->interrupts++;
- read(minioninfo->gpiointfd, &c, 1);
- // applog(LOG_ERR, "%s%i: Interrupt2",
- // minioncgpu->drv->name,
- // minioncgpu->device_id);
- gotres = false;
- for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
- if (minioninfo->has_chip[chip]) {
- SET_HEAD_READ(head, MINION_SYS_INT_STA);
- head->chipid = minioninfo->chipid[chip];
- reply = do_ioctl(CHIP_PIN(chip), wbuf, wsiz, rbuf, rsiz, &ioseq);
- if (reply != (int)wsiz) {
- applog(LOG_ERR, "%s: chip %d int status returned %d"
- " (should be %d)",
- minioncgpu->drv->dname,
- chip, reply, (int)wsiz);
- }
- snprintf(minioninfo->last_interrupt,
- sizeof(minioninfo->last_interrupt),
- "%d %d 0x%02x%02x%02x%02x%02x%02x%02x%02x %d %d 0x%02x %d %d",
- (int)(minioninfo->interrupts), chip,
- rbuf[0], rbuf[1], rbuf[2], rbuf[3],
- rbuf[4], rbuf[5], rbuf[6], rbuf[7],
- (int)wsiz, (int)rsiz, rbuf[wsiz - rsiz],
- rbuf[wsiz - rsiz] & MINION_RESULT_INT,
- rbuf[wsiz - rsiz] & MINION_CMD_INT);
- if ((rbuf[wsiz - rsiz] & MINION_RESULT_INT) != 0) {
- gotres = true;
- (minioninfo->result_interrupts)++;
- // applog(LOG_ERR, "%s%i: chip %d got RES interrupt",
- // minioncgpu->drv->name,
- // minioncgpu->device_id,
- // chip);
- }
- if ((rbuf[wsiz - rsiz] & MINION_CMD_INT) != 0) {
- // Work queue is empty
- (minioninfo->command_interrupts)++;
- // applog(LOG_ERR, "%s%i: chip %d got CMD interrupt",
- // minioncgpu->drv->name,
- // minioncgpu->device_id,
- // chip);
- }
- // char *tmp;
- // tmp = bin2hex(rbuf, wsiz);
- // applog(LOG_ERR, "%s%i: chip %d interrupt: %s",
- // minioncgpu->drv->name,
- // minioncgpu->device_id,
- // chip, tmp);
- // free(tmp);
- // Don't clear either interrupt until after send/recv
- }
- }
- // Doing this last means we can't miss an interrupt
- if (gotres)
- cgsem_post(&(minioninfo->scan_work));
- }
- #endif
- }
- return NULL;
- }
- /*
- * Find the matching work item for this chip
- * Discard any older work items for this chip
- */
- enum nonce_state {
- NONCE_GOOD_NONCE,
- NONCE_NO_NONCE,
- NONCE_DUP_NONCE,
- NONCE_BAD_NONCE,
- NONCE_BAD_WORK,
- NONCE_NO_WORK,
- NONCE_SPI_ERR
- };
- static void cleanup_older(struct cgpu_info *minioncgpu, int chip, K_ITEM *item, bool no_nonce)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- K_ITEM *tail;
- // bool errs;
- /* remove older ioseq work items
- no_nonce means this 'item' has finished also */
- tail = minioninfo->wchip_list[chip]->tail;
- while (tail && (DATA_WORK(tail)->ioseq < DATA_WORK(item)->ioseq)) {
- k_unlink_item(minioninfo->wchip_list[chip], tail);
- if (!(DATA_WORK(tail)->stale)) {
- minioninfo->chip_status[chip].chipwork--;
- #if MINION_SHOW_IO
- applog(IOCTRL_LOG, "COld chip %d cw-1=%u rw=%u qw=%u",
- chip,
- minioninfo->chip_status[chip].chipwork,
- minioninfo->chip_status[chip].realwork,
- minioninfo->chip_status[chip].quework);
- #endif
- /*
- // If it had no valid work (only errors) then it won't have been cleaned up
- errs = (DATA_WORK(tail)->errors > 0);
- applog(errs ? LOG_DEBUG : LOG_ERR,
- applog(LOG_ERR,
- "%s%i: discarded old task 0x%04x chip %d no reply errs=%d",
- minioncgpu->drv->name, minioncgpu->device_id,
- DATA_WORK(tail)->task_id, chip, DATA_WORK(tail)->errors);
- */
- }
- applog(MINION_LOG, "%s%i: marking complete - old task 0x%04x chip %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- DATA_WORK(tail)->task_id, chip);
- if (DATA_WORK(tail)->rolled)
- free_work(DATA_WORK(tail)->work);
- else
- work_completed(minioncgpu, DATA_WORK(tail)->work);
- k_free_head(minioninfo->wfree_list, tail);
- tail = minioninfo->wchip_list[chip]->tail;
- }
- if (no_nonce) {
- if (!(DATA_WORK(item)->stale)) {
- minioninfo->chip_status[chip].chipwork--;
- #if MINION_SHOW_IO
- applog(IOCTRL_LOG, "CONoN chip %d cw-1=%u rw=%u qw=%u",
- chip,
- minioninfo->chip_status[chip].chipwork,
- minioninfo->chip_status[chip].realwork,
- minioninfo->chip_status[chip].quework);
- #endif
- }
- applog(MINION_LOG, "%s%i: marking complete - no_nonce task 0x%04x chip %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- DATA_WORK(item)->task_id, chip);
- if (DATA_WORK(item)->rolled)
- free_work(DATA_WORK(item)->work);
- else
- work_completed(minioncgpu, DATA_WORK(item)->work);
- }
- }
- // Need to put it back in the list where it was - according to ioseq
- static void restorework(struct minion_info *minioninfo, int chip, K_ITEM *item)
- {
- K_ITEM *look;
- look = minioninfo->wchip_list[chip]->tail;
- while (look && DATA_WORK(look)->ioseq < DATA_WORK(item)->ioseq)
- look = look->prev;
- if (!look)
- k_add_head(minioninfo->wchip_list[chip], item);
- else
- k_insert_after(minioninfo->wchip_list[chip], item, look);
- }
- static enum nonce_state oknonce(struct thr_info *thr, struct cgpu_info *minioncgpu, int chip, int core,
- uint32_t task_id, uint32_t nonce, bool no_nonce, struct timeval *when,
- bool another, uint32_t task_id2, uint32_t nonce2)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- struct timeval now;
- K_ITEM *item, *tail;
- uint32_t min_task_id, max_task_id;
- // uint64_t chip_good;
- bool redo;
- // if the chip has been disabled - but we don't do that - so not possible (yet)
- if (!(minioninfo->has_chip[chip])) {
- minioninfo->spi_errors++;
- applog(MINTASK_LOG, "%s%i: nonce error chip %d not present",
- minioncgpu->drv->name, minioncgpu->device_id, chip);
- return NONCE_NO_WORK;
- }
- if (core < 0 || core >= MINION_CORES) {
- minioninfo->spi_errors++;
- minioninfo->res_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- applog(MINTASK_LOG, "%s%i: SPI nonce error invalid core %d (chip %d)",
- minioncgpu->drv->name, minioncgpu->device_id, core, chip);
- // use the fake core number so we don't discard the result
- core = FAKE_CORE;
- }
- if (no_nonce)
- minioninfo->chip_nononces[chip]++;
- else
- minioninfo->chip_nonces[chip]++;
- redo = false;
- retry:
- K_WLOCK(minioninfo->wchip_list[chip]);
- item = minioninfo->wchip_list[chip]->tail;
- if (!item) {
- K_WUNLOCK(minioninfo->wchip_list[chip]);
- minioninfo->spi_errors++;
- minioninfo->res_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- applog(MINTASK_LOG, "%s%i: chip %d has no tasks (core %d task 0x%04x)",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, core, (int)task_id);
- if (!no_nonce) {
- minioninfo->untested_nonces++;
- minioninfo->chip_err[chip]++;
- }
- return NONCE_NO_WORK;
- }
- min_task_id = DATA_WORK(item)->task_id;
- while (item) {
- if (DATA_WORK(item)->task_id == task_id)
- break;
- item = item->prev;
- }
- max_task_id = DATA_WORK(minioninfo->wchip_list[chip]->head)->task_id;
- if (!item) {
- K_WUNLOCK(minioninfo->wchip_list[chip]);
- if (another && task_id != task_id2) {
- minioninfo->tasks_failed[chip]++;
- task_id = task_id2;
- redo = true;
- goto retry;
- }
- minioninfo->spi_errors++;
- minioninfo->res_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- applog(MINTASK_LOG, "%s%i: chip %d core %d unknown task 0x%04x "
- "(min=0x%04x max=0x%04x no_nonce=%d)",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, core, (int)task_id, (int)min_task_id,
- (int)max_task_id, no_nonce);
- if (!no_nonce) {
- minioninfo->untested_nonces++;
- minioninfo->chip_err[chip]++;
- }
- return NONCE_BAD_WORK;
- }
- if (redo)
- minioninfo->tasks_recovered[chip]++;
- k_unlink_item(minioninfo->wchip_list[chip], item);
- if (no_nonce) {
- cleanup_older(minioncgpu, chip, item, no_nonce);
- k_free_head(minioninfo->wfree_list, item);
- K_WUNLOCK(minioninfo->wchip_list[chip]);
- return NONCE_NO_NONCE;
- }
- K_WUNLOCK(minioninfo->wchip_list[chip]);
- minioninfo->tested_nonces++;
- redo = false;
- retest:
- if (test_nonce(DATA_WORK(item)->work, nonce)) {
- /*
- if (isdupnonce(minioncgpu, DATA_WORK(item)->work, nonce)) {
- minioninfo->chip_dup[chip]++;
- applog(LOG_WARNING, " ... nonce %02x%02x%02x%02x chip %d core %d task 0x%04x",
- (nonce & 0xff), ((nonce >> 8) & 0xff),
- ((nonce >> 16) & 0xff), ((nonce >> 24) & 0xff),
- chip, core, task_id);
- K_WLOCK(minioninfo->wchip_list[chip]);
- restorework(minioninfo, chip, item);
- K_WUNLOCK(minioninfo->wchip_list[chip]);
- return NONCE_DUP_NONCE;
- }
- */
- //applog(MINTASK_LOG, "%s%i: Valid Nonce chip %d core %d task 0x%04x nonce 0x%08x", minioncgpu->drv->name, minioncgpu->device_id, chip, core, task_id, nonce);
- //
- submit_tested_work(thr, DATA_WORK(item)->work);
- if (redo)
- minioninfo->nonces_recovered[chip]++;
- /* chip_good = */ ++(minioninfo->chip_good[chip]);
- minioninfo->chip_status[chip].from_first_good++;
- minioninfo->core_good[chip][core]++;
- DATA_WORK(item)->nonces++;
- mutex_lock(&(minioninfo->nonce_lock));
- minioninfo->new_nonces++;
- mutex_unlock(&(minioninfo->nonce_lock));
- minioninfo->ok_nonces++;
- K_WLOCK(minioninfo->wchip_list[chip]);
- cleanup_older(minioncgpu, chip, item, no_nonce);
- restorework(minioninfo, chip, item);
- K_WUNLOCK(minioninfo->wchip_list[chip]);
- // add to history and remove old history and keep track of the 2 reset marks
- int chip_tmp;
- cgtime(&now);
- K_WLOCK(minioninfo->hfree_list);
- item = k_unlink_head(minioninfo->hfree_list);
- memcpy(&(DATA_HIST(item)->when), when, sizeof(*when));
- k_add_head(minioninfo->hchip_list[chip], item);
- if (minioninfo->reset_mark[chip])
- minioninfo->reset_count[chip]++;
- if (second_check && minioninfo->reset2_mark[chip])
- minioninfo->reset2_count[chip]++;
- // N.B. this also corrects each reset_mark/reset_count within each hchip_list
- for (chip_tmp = 0; chip_tmp < (int)MINION_CHIPS; chip_tmp++) {
- tail = minioninfo->hchip_list[chip_tmp]->tail;
- while (tail && tdiff(&(DATA_HIST(tail)->when), &now) > MINION_HISTORY_s) {
- if (minioninfo->reset_mark[chip] == tail) {
- minioninfo->reset_mark[chip] = tail->prev;
- minioninfo->reset_count[chip]--;
- }
- if (second_check && minioninfo->reset2_mark[chip] == tail) {
- minioninfo->reset2_mark[chip] = tail->prev;
- minioninfo->reset2_count[chip]--;
- }
- tail = k_unlink_tail(minioninfo->hchip_list[chip_tmp]);
- k_add_head(minioninfo->hfree_list, item);
- tail = minioninfo->hchip_list[chip_tmp]->tail;
- }
- if (!(minioninfo->reset_mark[chip])) {
- minioninfo->reset_mark[chip] = minioninfo->hchip_list[chip]->tail;
- minioninfo->reset_count[chip] = minioninfo->hchip_list[chip]->count;
- }
- if (second_check && !(minioninfo->reset2_mark[chip])) {
- minioninfo->reset2_mark[chip] = minioninfo->hchip_list[chip]->tail;
- minioninfo->reset2_count[chip] = minioninfo->hchip_list[chip]->count;
- }
- tail = minioninfo->reset_mark[chip];
- while (tail && tdiff(&(DATA_HIST(tail)->when), &now) > minioninfo->reset_time[chip]) {
- tail = minioninfo->reset_mark[chip] = tail->prev;
- minioninfo->reset_count[chip]--;
- }
- if (second_check) {
- tail = minioninfo->reset2_mark[chip];
- while (tail && tdiff(&(DATA_HIST(tail)->when), &now) > minioninfo->reset2_time[chip]) {
- tail = minioninfo->reset2_mark[chip] = tail->prev;
- minioninfo->reset2_count[chip]--;
- }
- }
- }
- K_WUNLOCK(minioninfo->hfree_list);
- /*
- // Reset the chip after 8 nonces found
- if (chip_good == 8) {
- memcpy(&(minioninfo->last_reset[chip]), &now, sizeof(now));
- init_chip(minioncgpu, minioninfo, chip);
- }
- */
- return NONCE_GOOD_NONCE;
- }
- if (another && nonce != nonce2) {
- minioninfo->nonces_failed[chip]++;
- nonce = nonce2;
- redo = true;
- goto retest;
- }
- DATA_WORK(item)->errors++;
- K_WLOCK(minioninfo->wchip_list[chip]);
- restorework(minioninfo, chip, item);
- K_WUNLOCK(minioninfo->wchip_list[chip]);
- minioninfo->chip_bad[chip]++;
- minioninfo->core_bad[chip][core]++;
- inc_hw_errors(thr);
- //applog(MINTASK_LOG, "%s%i: HW ERROR chip %d core %d task 0x%04x nonce 0x%08x", minioncgpu->drv->name, minioncgpu->device_id, chip, core, task_id, nonce);
- return NONCE_BAD_NONCE;
- }
- /* Check each chip how long since the last nonce
- * Should normally be a fraction of a second
- * so (MINION_RESET_s * 1.5) will certainly be long enough,
- * but also will avoid lots of resets if there is trouble getting work
- * Should be longer than MINION_RESET_s to avoid interfering with normal resets */
- static void check_last_nonce(struct cgpu_info *minioncgpu)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- struct timeval now;
- K_ITEM *head;
- double howlong;
- int chip;
- cgtime(&now);
- K_RLOCK(minioninfo->hfree_list);
- for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
- if (minioninfo->has_chip[chip] && !(minioninfo->changing[chip])) {
- head = minioninfo->hchip_list[chip]->head;
- if (head) {
- howlong = tdiff(&now, &(DATA_HIST(head)->when));
- if (howlong > ((double)MINION_RESET_s * 1.5)) {
- // Setup a reset
- minioninfo->flag_reset[chip] = true;
- minioninfo->do_reset[chip] = 0.0;
- }
- }
- }
- }
- K_RUNLOCK(minioninfo->hfree_list);
- }
- // Results checking thread
- static void *minion_results(void *userdata)
- {
- struct cgpu_info *minioncgpu = (struct cgpu_info *)userdata;
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- struct thr_info *thr;
- int chip = 0, core = 0;
- uint32_t task_id = 0;
- uint32_t nonce = 0;
- bool no_nonce = false;
- struct timeval when;
- bool another;
- uint32_t task_id2 = 0;
- uint32_t nonce2 = 0;
- int last_check;
- applog(MINION_LOG, "%s%i: Results...",
- minioncgpu->drv->name, minioncgpu->device_id);
- // Wait until we're ready
- while (minioncgpu->shutdown == false) {
- if (minioninfo->initialised) {
- break;
- }
- cgsleep_ms(3);
- }
- thr = minioninfo->thr;
- last_check = 0;
- while (minioncgpu->shutdown == false) {
- if (!oldest_nonce(minioncgpu, &chip, &core, &task_id, &nonce,
- &no_nonce, &when, &another, &task_id2, &nonce2)) {
- check_last_nonce(minioncgpu);
- last_check = 0;
- cgsem_mswait(&(minioninfo->nonce_ready), MINION_NONCE_mS);
- continue;
- }
- oknonce(thr, minioncgpu, chip, core, task_id, nonce, no_nonce, &when,
- another, task_id2, nonce2);
- // Interrupt nonce checking if low CPU and oldest_nonce() is always true
- if (++last_check > 100) {
- check_last_nonce(minioncgpu);
- last_check = 0;
- }
- }
- return NULL;
- }
- static void minion_flush_work(struct cgpu_info *minioncgpu)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- K_ITEM *prev_unused, *task, *prev_task, *witem;
- int i;
- if (minioninfo->initialised == false)
- return;
- applog(MINION_LOG, "%s%i: flushing work",
- minioncgpu->drv->name, minioncgpu->device_id);
- // TODO: N.B. scanwork also gets work locks - which master thread calls flush?
- K_WLOCK(minioninfo->wwork_list);
- // Simply remove the whole unused wwork_list
- k_list_transfer_to_head(minioninfo->wwork_list, minioninfo->wstale_list);
- minioninfo->wwork_flushed += minioninfo->wstale_list->count;
- // TODO: flush/work tasks should have a block sequence number so this task removal code
- // might be better implemented in minion_spi_write where each work task would
- // update the block sequence number and any work tasks with an old block sequence
- // number would be discarded rather than sent - minion_spi_write will also need to
- // prioritise flush urgent tasks above work urgent tasks - have 3 urgent states?
- // They should however be 2 seperate variables in minioninfo to reduce locking
- // - flush will increment one and put it in the flush task, (and work will use that)
- // minion_spi_write will check/update the other and thus not need a lock
- // No deadlock since this is the only code to get 2 locks
- K_WLOCK(minioninfo->tfree_list);
- task = minioninfo->task_list->tail;
- while (task) {
- prev_task = task->prev;
- if (DATA_TASK(task)->address == WRITE_ADDR(MINION_QUE_0)) {
- minioninfo->chip_status[DATA_TASK(task)->chip].quework--;
- #if MINION_SHOW_IO
- applog(IOCTRL_LOG, "QueFlush chip %d cw=%u rw=%u qw-1=%u",
- (int)DATA_TASK(task)->chip,
- minioninfo->chip_status[DATA_TASK(task)->chip].chipwork,
- minioninfo->chip_status[DATA_TASK(task)->chip].realwork,
- minioninfo->chip_status[DATA_TASK(task)->chip].quework);
- #endif
- witem = DATA_TASK(task)->witem;
- k_unlink_item(minioninfo->wque_list[DATA_TASK(task)->chip], witem);
- minioninfo->wque_flushed++;
- if (DATA_WORK(witem)->rolled)
- free_work(DATA_WORK(witem)->work);
- else
- work_completed(minioncgpu, DATA_WORK(witem)->work);
- k_free_head(minioninfo->wfree_list, witem);
- k_unlink_item(minioninfo->task_list, task);
- k_free_head(minioninfo->tfree_list, task);
- }
- task = prev_task;
- }
- for (i = 0; i < (int)MINION_CHIPS; i++) {
- if (minioninfo->has_chip[i]) {
- // TODO: consider sending it now rather than adding to the task list?
- task = k_unlink_head(minioninfo->tfree_list);
- DATA_TASK(task)->tid = ++(minioninfo->next_tid);
- DATA_TASK(task)->chip = i;
- DATA_TASK(task)->write = true;
- DATA_TASK(task)->address = MINION_SYS_RSTN_CTL;
- DATA_TASK(task)->task_id = 0; // ignored
- DATA_TASK(task)->wsiz = MINION_SYS_SIZ;
- DATA_TASK(task)->rsiz = 0;
- DATA_TASK(task)->wbuf[0] = SYS_RSTN_CTL_FLUSH;
- DATA_TASK(task)->wbuf[1] = 0;
- DATA_TASK(task)->wbuf[2] = 0;
- DATA_TASK(task)->wbuf[3] = 0;
- DATA_TASK(task)->urgent = true;
- k_add_head(minioninfo->task_list, task);
- }
- }
- K_WUNLOCK(minioninfo->tfree_list);
- K_WUNLOCK(minioninfo->wwork_list);
- // TODO: send a signal to force getting and sending new work - needs cgsem_wait in the sending thread
- // TODO: should we use this thread to do the following work?
- if (minioninfo->wstale_list->count) {
- // mark complete all stale unused work (oldest first)
- prev_unused = minioninfo->wstale_list->tail;
- while (prev_unused) {
- if (DATA_WORK(prev_unused)->rolled)
- free_work(DATA_WORK(prev_unused)->work);
- else
- work_completed(minioncgpu, DATA_WORK(prev_unused)->work);
- prev_unused = prev_unused->prev;
- }
- // put them back in the wfree_list
- K_WLOCK(minioninfo->wfree_list);
- k_list_transfer_to_head(minioninfo->wstale_list, minioninfo->wfree_list);
- K_WUNLOCK(minioninfo->wfree_list);
- }
- }
- static void sys_chip_sta(struct cgpu_info *minioncgpu, int chip)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- struct timeval now;
- K_ITEM *item;
- int limit, rep;
- cgtime(&now);
- // No lock required since 'last' is only accessed here
- if (minioninfo->chip_status[chip].last.tv_sec == 0) {
- memcpy(&(minioninfo->chip_status[chip].last), &now, sizeof(now));
- } else {
- limit = MINION_STATS_UPDATE_TIME_mS +
- (int)(random() % MINION_STATS_UPDATE_RAND_mS);
- if (ms_tdiff(&now, &(minioninfo->chip_status[chip].last)) > limit) {
- memcpy(&(minioninfo->chip_status[chip].last), &now, sizeof(now));
- K_WLOCK(minioninfo->tfree_list);
- item = k_unlink_head(minioninfo->tfree_list);
- DATA_TASK(item)->tid = ++(minioninfo->next_tid);
- K_WUNLOCK(minioninfo->tfree_list);
- DATA_TASK(item)->chip = chip;
- DATA_TASK(item)->write = false;
- DATA_TASK(item)->address = READ_ADDR(MINION_SYS_CHIP_STA);
- DATA_TASK(item)->task_id = 0;
- DATA_TASK(item)->wsiz = 0;
- DATA_TASK(item)->rsiz = MINION_SYS_SIZ;
- DATA_TASK(item)->urgent = false;
- K_WLOCK(minioninfo->task_list);
- k_add_head(minioninfo->task_list, item);
- item = k_unlink_head(minioninfo->tfree_list);
- DATA_TASK(item)->tid = ++(minioninfo->next_tid);
- K_WUNLOCK(minioninfo->task_list);
- DATA_TASK(item)->chip = chip;
- DATA_TASK(item)->write = false;
- DATA_TASK(item)->address = READ_ADDR(MINION_SYS_IDLE_CNT);
- DATA_TASK(item)->task_id = 0;
- DATA_TASK(item)->wsiz = 0;
- DATA_TASK(item)->rsiz = MINION_SYS_SIZ;
- DATA_TASK(item)->urgent = false;
- K_WLOCK(minioninfo->task_list);
- k_add_head(minioninfo->task_list, item);
- K_WUNLOCK(minioninfo->task_list);
- // Get the core ena and act state
- for (rep = 0; rep < MINION_CORE_REPS; rep++) {
- // Ena
- K_WLOCK(minioninfo->tfree_list);
- item = k_unlink_head(minioninfo->tfree_list);
- DATA_TASK(item)->tid = ++(minioninfo->next_tid);
- K_WUNLOCK(minioninfo->tfree_list);
- DATA_TASK(item)->chip = chip;
- DATA_TASK(item)->write = false;
- DATA_TASK(item)->address = READ_ADDR(MINION_CORE_ENA0_31 + rep);
- DATA_TASK(item)->task_id = 0;
- DATA_TASK(item)->wsiz = 0;
- DATA_TASK(item)->rsiz = MINION_SYS_SIZ;
- DATA_TASK(item)->urgent = false;
- K_WLOCK(minioninfo->task_list);
- k_add_head(minioninfo->task_list, item);
- // Act
- item = k_unlink_head(minioninfo->tfree_list);
- DATA_TASK(item)->tid = ++(minioninfo->next_tid);
- K_WUNLOCK(minioninfo->task_list);
- DATA_TASK(item)->chip = chip;
- DATA_TASK(item)->write = false;
- DATA_TASK(item)->address = READ_ADDR(MINION_CORE_ACT0_31 + rep);
- DATA_TASK(item)->task_id = 0;
- DATA_TASK(item)->wsiz = 0;
- DATA_TASK(item)->rsiz = MINION_SYS_SIZ;
- DATA_TASK(item)->urgent = false;
- K_WLOCK(minioninfo->task_list);
- k_add_head(minioninfo->task_list, item);
- K_WUNLOCK(minioninfo->task_list);
- }
- if (minioninfo->lednow[chip] != minioninfo->setled[chip]) {
- uint32_t led;
- minioninfo->lednow[chip] = minioninfo->setled[chip];
- if (minioninfo->lednow[chip])
- led = MINION_SPI_LED_ON;
- else
- led = MINION_SPI_LED_OFF;
- K_WLOCK(minioninfo->tfree_list);
- item = k_unlink_head(minioninfo->tfree_list);
- DATA_TASK(item)->tid = ++(minioninfo->next_tid);
- K_WUNLOCK(minioninfo->tfree_list);
- DATA_TASK(item)->chip = chip;
- DATA_TASK(item)->write = true;
- DATA_TASK(item)->address = MINION_SYS_SPI_LED;
- DATA_TASK(item)->task_id = 0;
- DATA_TASK(item)->wsiz = MINION_SYS_SIZ;
- DATA_TASK(item)->rsiz = 0;
- DATA_TASK(item)->wbuf[0] = led & 0xff;
- DATA_TASK(item)->wbuf[1] = (led >> 8) & 0xff;
- DATA_TASK(item)->wbuf[2] = (led >> 16) & 0xff;
- DATA_TASK(item)->wbuf[3] = (led >> 24) & 0xff;
- DATA_TASK(item)->urgent = false;
- K_WLOCK(minioninfo->task_list);
- k_add_head(minioninfo->task_list, item);
- K_WUNLOCK(minioninfo->task_list);
- }
- }
- }
- }
- static void new_work_task(struct cgpu_info *minioncgpu, K_ITEM *witem, int chip, bool urgent, uint8_t state)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- struct minion_que *que;
- K_ITEM *item;
- K_WLOCK(minioninfo->tfree_list);
- item = k_unlink_head(minioninfo->tfree_list);
- DATA_TASK(item)->tid = ++(minioninfo->next_tid);
- K_WUNLOCK(minioninfo->tfree_list);
- DATA_TASK(item)->chip = chip;
- DATA_TASK(item)->write = true;
- DATA_TASK(item)->address = MINION_QUE_0;
- // if threaded access to new_work_task() is added, this will need locking
- // Don't use task_id 0 so that we can ignore all '0' work replies
- // ... and report them as errors
- if (minioninfo->next_task_id == 0)
- minioninfo->next_task_id = 1;
- DATA_TASK(item)->task_id = minioninfo->next_task_id;
- DATA_WORK(witem)->task_id = minioninfo->next_task_id;
- minioninfo->next_task_id = (minioninfo->next_task_id + 1) & MINION_MAX_TASK_ID;
- DATA_TASK(item)->urgent = urgent;
- DATA_TASK(item)->work_state = state;
- DATA_TASK(item)->work = DATA_WORK(witem)->work;
- DATA_TASK(item)->witem = witem;
- que = (struct minion_que *)&(DATA_TASK(item)->wbuf[0]);
- que->task_id[0] = DATA_TASK(item)->task_id & 0xff;
- que->task_id[1] = (DATA_TASK(item)->task_id & 0xff00) >> 8;
- memcpy(&(que->midstate[0]), &(DATA_WORK(witem)->work->midstate[0]), MIDSTATE_BYTES);
- memcpy(&(que->merkle7[0]), &(DATA_WORK(witem)->work->data[MERKLE7_OFFSET]), MERKLE_BYTES);
- DATA_TASK(item)->wsiz = (int)sizeof(*que);
- DATA_TASK(item)->rsiz = 0;
- K_WLOCK(minioninfo->wque_list[chip]);
- k_add_head(minioninfo->wque_list[chip], witem);
- minioninfo->chip_status[chip].quework++;
- #if MINION_SHOW_IO
- applog(IOCTRL_LOG, "Que chip %d cw=%u rw=%u qw+1=%u",
- chip,
- minioninfo->chip_status[chip].chipwork,
- minioninfo->chip_status[chip].realwork,
- minioninfo->chip_status[chip].quework);
- #endif
- K_WUNLOCK(minioninfo->wque_list[chip]);
- K_WLOCK(minioninfo->task_list);
- k_add_head(minioninfo->task_list, item);
- K_WUNLOCK(minioninfo->task_list);
- if (urgent)
- cgsem_post(&(minioninfo->task_ready));
- // N.B. this will only update often enough if a chip is > ~2GH/s
- if (!urgent)
- sys_chip_sta(minioncgpu, chip);
- }
- // TODO: stale work ...
- static K_ITEM *next_work(struct minion_info *minioninfo)
- {
- K_ITEM *item;
- struct timeval now;
- double howlong;
- int i;
- K_WLOCK(minioninfo->wwork_list);
- item = k_unlink_tail(minioninfo->wwork_list);
- K_WUNLOCK(minioninfo->wwork_list);
- if (item) {
- cgtime(&now);
- howlong = tdiff(&now, &(DATA_WORK(item)->created));
- minioninfo->que_work++;
- minioninfo->que_time += howlong;
- if (minioninfo->que_min == 0 || minioninfo->que_min > howlong)
- minioninfo->que_min = howlong;
- else if (minioninfo->que_max < howlong)
- minioninfo->que_max = howlong;
- for (i = 0; i < TIME_BANDS; i++) {
- if (howlong < time_bands[i]) {
- minioninfo->que_bands[i]++;
- break;
- }
- }
- if (i >= TIME_BANDS)
- minioninfo->que_bands[TIME_BANDS]++;
- }
- return item;
- }
- static void minion_do_work(struct cgpu_info *minioncgpu)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- int count, chip, j, lowcount;
- TASK_ITEM fifo_task;
- uint8_t state, cmd;
- K_ITEM *item;
- #if ENABLE_INT_NONO
- K_ITEM *task;
- #endif
- bool islow, sentwork;
- fifo_task.chip = 0;
- fifo_task.write = false;
- fifo_task.address = MINION_SYS_FIFO_STA;
- fifo_task.wsiz = 0;
- fifo_task.rsiz = MINION_SYS_SIZ;
- // TODO: (remove this) Fake starved of work to test CMD Interrupt
- // if (total_secs > 120) {
- // cgsleep_ms(888);
- // return;
- // }
- /*
- * Fill the queues as follows:
- * 1) put at least 1 in each queue or if islow then add 1
- * 2) push each queue up to LOW or if count is high but islow, then add LOW-1
- * 3) push each LOW queue up to HIGH
- */
- sentwork = false;
- for (state = 0; state < 3; state++) {
- #define CHP 0
- //applog(LOG_ERR, "%s%i: chip %d presta %d: quew %d chw %d", minioncgpu->drv->name, minioncgpu->device_id, CHP, state, minioninfo->chip_status[CHP].quework, minioninfo->chip_status[CHP].chipwork);
- for (chip = 0; chip < (int)MINION_CHIPS; chip++)
- minioninfo->chip_status[chip].tohigh = false;
- for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
- if (minioninfo->has_chip[chip] && !minioninfo->chip_status[chip].overheat) {
- struct timeval now;
- double howlong;
- cgtime(&now);
- howlong = tdiff(&now, &(minioninfo->last_reset[chip]));
- if (howlong < MINION_RESET_DELAY_s)
- continue;
- int tries = 0;
- while (tries++ < 4) {
- cmd = 0;
- fifo_task.chip = chip;
- fifo_task.reply = 0;
- minion_txrx(&fifo_task);
- if (fifo_task.reply <= 0) {
- if (fifo_task.reply < (int)(fifo_task.osiz)) {
- char *buf = bin2hex((unsigned char *)(&(fifo_task.rbuf[fifo_task.osiz - fifo_task.rsiz])),
- (int)(fifo_task.rsiz));
- applog(LOG_ERR, "%s%i: Chip %d Bad fifo reply (%s) size %d, should be %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, buf,
- fifo_task.reply, (int)(fifo_task.osiz));
- free(buf);
- minioninfo->spi_errors++;
- minioninfo->fifo_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- } else {
- if (fifo_task.reply > (int)(fifo_task.osiz)) {
- applog(LOG_ERR, "%s%i: Chip %d Unexpected fifo reply size %d, expected only %d",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, fifo_task.reply, (int)(fifo_task.osiz));
- }
- cmd = FIFO_CMD(fifo_task.rbuf, fifo_task.osiz - fifo_task.rsiz);
- // valid reply?
- if (cmd < MINION_QUE_MAX) {
- K_WLOCK(minioninfo->wchip_list[chip]);
- minioninfo->chip_status[chip].realwork = cmd;
- K_WUNLOCK(minioninfo->wchip_list[chip]);
- if (cmd <= MINION_QUE_LOW || cmd >= MINION_QUE_HIGH) {
- applog(LOG_DEBUG, "%s%i: Chip %d fifo cmd %d",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- chip, (int)cmd);
- }
- break;
- }
- applog(LOG_ERR, "%s%i: Chip %d Bad fifo reply cmd %d (max is %d)",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, (int)cmd, MINION_QUE_MAX);
- minioninfo->spi_errors++;
- minioninfo->fifo_spi_errors[chip]++;
- minioninfo->res_err_count[chip]++;
- }
- }
- }
- K_WLOCK(minioninfo->wchip_list[chip]);
- count = minioninfo->chip_status[chip].quework +
- minioninfo->chip_status[chip].realwork;
- islow = minioninfo->chip_status[chip].islow;
- minioninfo->chip_status[chip].islow = false;
- lowcount = minioninfo->chip_status[chip].lowcount;
- K_WUNLOCK(minioninfo->wchip_list[chip]);
- switch (state) {
- case 0:
- if (count == 0 || islow) {
- item = next_work(minioninfo);
- if (item) {
- new_work_task(minioncgpu, item, chip, true, state);
- sentwork = true;
- applog(MINION_LOG, "%s%i: 0 task 0x%04x in chip %d list",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- DATA_WORK(item)->task_id, chip);
- } else {
- applog(LOG_ERR, "%s%i: chip %d urgent empty work list",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- chip);
- }
- }
- break;
- case 1:
- if (count < MINION_QUE_LOW || islow) {
- // do case 2: after we've done other chips
- minioninfo->chip_status[chip].tohigh = true;
- j = count;
- if (count >= MINION_QUE_LOW) {
- // islow means run a full case 1
- j = 1;
- applog(LOG_ERR, "%s%i: chip %d low que (%d) with high count %d",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- chip, lowcount, count);
- }
- for (; j < MINION_QUE_LOW; j++) {
- item = next_work(minioninfo);
- if (item) {
- new_work_task(minioncgpu, item, chip, false, state);
- sentwork = true;
- applog(MINION_LOG, "%s%i: 1 task 0x%04x in chip %d list",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- DATA_WORK(item)->task_id, chip);
- } else {
- applog(LOG_ERR, "%s%i: chip %d non-urgent lo "
- "empty work list (count=%d)",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- chip, j);
- }
- }
- }
- break;
- case 2:
- if (count <= MINION_QUE_LOW || minioninfo->chip_status[chip].tohigh) {
- for (j = count; j < MINION_QUE_HIGH; j++) {
- item = next_work(minioninfo);
- if (item) {
- new_work_task(minioncgpu, item, chip, false, state);
- sentwork = true;
- applog(MINION_LOG, "%s%i: 2 task 0x%04x in chip %d list",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- DATA_WORK(item)->task_id, chip);
- } else {
- applog(LOG_DEBUG, "%s%i: chip %d non-urgent hi "
- "empty work list (count=%d)",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- chip, j);
- }
- }
- }
- break;
- }
- } else
- if (minioninfo->has_chip[chip] && minioninfo->chip_status[chip].overheat && state == 2)
- sys_chip_sta(minioncgpu, chip);
- }
- }
- sentwork = sentwork;
- #if ENABLE_INT_NONO
- if (sentwork) {
- // Clear CMD interrupt since we've now sent more
- K_WLOCK(minioninfo->tfree_list);
- task = k_unlink_head(minioninfo->tfree_list);
- DATA_TASK(task)->tid = ++(minioninfo->next_tid);
- DATA_TASK(task)->chip = 0; // ignored
- DATA_TASK(task)->write = true;
- DATA_TASK(task)->address = MINION_SYS_INT_CLR;
- DATA_TASK(task)->task_id = 0; // ignored
- DATA_TASK(task)->wsiz = MINION_SYS_SIZ;
- DATA_TASK(task)->rsiz = 0;
- DATA_TASK(task)->wbuf[0] = MINION_CMD_INT;
- DATA_TASK(task)->wbuf[1] = 0;
- DATA_TASK(task)->wbuf[2] = 0;
- DATA_TASK(task)->wbuf[3] = 0;
- DATA_TASK(task)->urgent = false;
- k_add_head(minioninfo->task_list, task);
- K_WUNLOCK(minioninfo->tfree_list);
- }
- #endif
- //applog(LOG_ERR, "%s%i: chip %d fin: quew %d chw %d", minioncgpu->drv->name, minioncgpu->device_id, CHP, minioninfo->chip_status[CHP].quework, minioninfo->chip_status[CHP].chipwork);
- }
- static bool minion_thread_prepare(struct thr_info *thr)
- {
- struct cgpu_info *minioncgpu = thr->cgpu;
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- minioninfo->thr = thr;
- /*
- * SPI/ioctl write thread
- */
- if (thr_info_create(&(minioninfo->spiw_thr), NULL, minion_spi_write, (void *)minioncgpu)) {
- applog(LOG_ERR, "%s%i: SPI write thread create failed",
- minioncgpu->drv->name, minioncgpu->device_id);
- return false;
- }
- pthread_detach(minioninfo->spiw_thr.pth);
- /*
- * SPI/ioctl results thread
- */
- if (thr_info_create(&(minioninfo->spir_thr), NULL, minion_spi_reply, (void *)minioncgpu)) {
- applog(LOG_ERR, "%s%i: SPI reply thread create failed",
- minioncgpu->drv->name, minioncgpu->device_id);
- return false;
- }
- pthread_detach(minioninfo->spir_thr.pth);
- /*
- * Seperate results checking thread so ioctl timing can ignore the results checking
- */
- if (thr_info_create(&(minioninfo->res_thr), NULL, minion_results, (void *)minioncgpu)) {
- applog(LOG_ERR, "%s%i: Results thread create failed",
- minioncgpu->drv->name, minioncgpu->device_id);
- return false;
- }
- pthread_detach(minioninfo->res_thr.pth);
- return true;
- }
- static void minion_shutdown(struct thr_info *thr)
- {
- struct cgpu_info *minioncgpu = thr->cgpu;
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- int i;
- applog(MINION_LOG, "%s%i: shutting down",
- minioncgpu->drv->name, minioncgpu->device_id);
- for (i = 0; i < (int)MINION_CHIPS; i++)
- if (minioninfo->has_chip[i])
- // TODO: minion_shutdown(minioncgpu, minioninfo, i);
- i = i;
- minioncgpu->shutdown = true;
- }
- static bool minion_queue_full(struct cgpu_info *minioncgpu)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- struct work *work, *usework;
- int count, totneed, need, roll, roll_limit, chip;
- bool ret, rolled;
- if (minioninfo->initialised == false) {
- cgsleep_us(42);
- return true;
- }
- K_RLOCK(minioninfo->wwork_list);
- count = minioninfo->wwork_list->count;
- totneed = 0;
- for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
- if (minioninfo->has_chip[chip] &&
- !minioninfo->chip_status[chip].overheat) {
- totneed += MINION_QUE_HIGH;
- totneed -= minioninfo->chip_status[chip].quework;
- totneed -= minioninfo->chip_status[chip].realwork;
- // One for the pot :)
- totneed++;
- }
- }
- K_RUNLOCK(minioninfo->wwork_list);
- if (count >= totneed)
- ret = true;
- else {
- need = totneed - count;
- /* Ensure we do enough rolling to reduce CPU
- but dont roll too much to have them end up stale */
- if (need < 16)
- need = 16;
- work = get_queued(minioncgpu);
- if (work) {
- roll_limit = work->drv_rolllimit;
- roll = 0;
- do {
- if (roll == 0) {
- usework = work;
- minioninfo->work_unrolled++;
- rolled = false;
- } else {
- usework = copy_work_noffset(work, roll);
- minioninfo->work_rolled++;
- rolled = true;
- }
- ready_work(minioncgpu, usework, rolled);
- } while (--need > 0 && ++roll <= roll_limit);
- } else {
- // Avoid a hard loop when we can't get work fast enough
- cgsleep_us(42);
- }
- if (need > 0)
- ret = false;
- else
- ret = true;
- }
- return ret;
- }
- static void idle_report(struct cgpu_info *minioncgpu)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- struct timeval now;
- uint32_t idle;
- int msdiff;
- int chip;
- for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
- if (minioninfo->has_chip[chip]) {
- idle = minioninfo->chip_status[chip].idle;
- if (idle != minioninfo->chip_status[chip].last_rpt_idle) {
- cgtime(&now);
- msdiff = ms_tdiff(&now, &(minioninfo->chip_status[chip].idle_rpt));
- if (msdiff >= MINION_IDLE_MESSAGE_ms) {
- memcpy(&(minioninfo->chip_status[chip].idle_rpt), &now, sizeof(now));
- applog(LOG_WARNING,
- "%s%d: chip %d internal idle changed %08x",
- minioncgpu->drv->name, minioncgpu->device_id,
- chip, idle);
- minioninfo->chip_status[chip].last_rpt_idle = idle;
- }
- }
- }
- }
- }
- static void chip_report(struct cgpu_info *minioncgpu)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- struct timeval now;
- char buf[512];
- char res_err_msg[2];
- size_t len;
- double elapsed, ghs, ghs2, expect, howlong;
- char ghs2_display[64];
- K_ITEM *pitem;
- int msdiff, chip;
- int res_err_count;
- cgtime(&now);
- if (!(minioninfo->chip_chk.tv_sec)) {
- memcpy(&(minioninfo->chip_chk), &now, sizeof(now));
- memcpy(&(minioninfo->chip_rpt), &now, sizeof(now));
- return;
- }
- // Always run the calculations to check chip GHs for the LED
- buf[0] = '\0';
- res_err_msg[0] = '\0';
- res_err_msg[1] = '\0';
- K_RLOCK(minioninfo->hfree_list);
- for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
- if (minioninfo->has_chip[chip]) {
- len = strlen(buf);
- if (minioninfo->hchip_list[chip]->count < 2)
- ghs = 0.0;
- else {
- ghs = 0xffffffffull * (minioninfo->hchip_list[chip]->count - 1);
- ghs /= 1000000000.0;
- ghs /= tdiff(&now, &(DATA_HIST(minioninfo->hchip_list[chip]->tail)->when));
- }
- if (minioninfo->chip_status[chip].first_nonce.tv_sec == 0L ||
- tdiff(&now, &minioninfo->chip_status[chip].first_nonce) < MINION_LED_TEST_TIME) {
- ghs2_display[0] = '\0';
- minioninfo->setled[chip] = false;
- } else {
- ghs2 = 0xffffffffull * (minioninfo->chip_status[chip].from_first_good - 1);
- ghs2 /= 1000000000.0;
- ghs2 /= tdiff(&now, &minioninfo->chip_status[chip].first_nonce);
- minioninfo->setled[chip] = (ghs2 >= opt_minion_ledlimit);
- snprintf(ghs2_display, sizeof(ghs2_display), "[%.2f]", ghs2);
- }
- res_err_count = minioninfo->res_err_count[chip];
- minioninfo->res_err_count[chip] = 0;
- if (res_err_count > 100)
- res_err_msg[0] = '!';
- else if (res_err_count > 50)
- res_err_msg[0] = '*';
- else if (res_err_count > 0)
- res_err_msg[0] = '\'';
- else
- res_err_msg[0] = '\0';
- snprintf(buf + len, sizeof(buf) - len,
- " %d=%s%.2f%s", chip, res_err_msg, ghs, ghs2_display);
- minioninfo->history_ghs[chip] = ghs;
- }
- }
- K_RUNLOCK(minioninfo->hfree_list);
- // But only display it if required
- if (opt_minion_chipreport > 0) {
- msdiff = ms_tdiff(&now, &(minioninfo->chip_rpt));
- if (msdiff >= (opt_minion_chipreport * 1000)) {
- memcpy(&(minioninfo->chip_chk), &now, sizeof(now));
- applogsiz(LOG_WARNING, 512,
- "%s%d: Chip GHs%s",
- minioncgpu->drv->name, minioncgpu->device_id, buf);
- memcpy(&(minioninfo->chip_rpt), &now, sizeof(now));
- }
- }
- msdiff = ms_tdiff(&now, &(minioninfo->chip_chk));
- if (total_secs >= MINION_RESET_s && msdiff >= (minioninfo->history_gen * 1000)) {
- K_RLOCK(minioninfo->hfree_list);
- for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
- if (minioninfo->has_chip[chip]) {
- // Don't reset the chip while 'changing'
- if (minioninfo->changing[chip])
- continue;
- if (!minioninfo->reset_mark[chip] ||
- minioninfo->reset_count[chip] < 2) {
- elapsed = 0.0;
- ghs = 0.0;
- } else {
- // 'now' includes that it may have stopped getting nonces
- elapsed = tdiff(&now, &(DATA_HIST(minioninfo->reset_mark[chip])->when));
- ghs = 0xffffffffull * (minioninfo->reset_count[chip] - 1);
- ghs /= 1000000000.0;
- ghs /= elapsed;
- }
- expect = (double)(minioninfo->init_freq[chip]) *
- MINION_RESET_PERCENT / 1000.0;
- howlong = tdiff(&now, &(minioninfo->last_reset[chip]));
- if (ghs <= expect && howlong >= minioninfo->reset_time[chip]) {
- minioninfo->do_reset[chip] = expect;
- // For now - no lock required since no other code accesses it
- pitem = k_unlink_head(minioninfo->pfree_list);
- DATA_PERF(pitem)->elapsed = elapsed;
- DATA_PERF(pitem)->nonces = minioninfo->reset_count[chip] - 1;
- DATA_PERF(pitem)->freq = minioninfo->init_freq[chip];
- DATA_PERF(pitem)->ghs = ghs;
- memcpy(&(DATA_PERF(pitem)->when), &now, sizeof(now));
- k_add_head(minioninfo->p_list[chip], pitem);
- } else if (second_check) {
- expect = (double)(minioninfo->init_freq[chip]) *
- MINION_RESET2_PERCENT / 1000.0;
- if (ghs < expect && howlong >= minioninfo->reset2_time[chip]) {
- /* Only do a reset, don't record it, since the ghs
- is still above MINION_RESET_PERCENT */
- minioninfo->do_reset[chip] = expect;
- }
- }
- minioninfo->history_ghs[chip] = ghs;
- // Expire old perf items to stop clockdown
- if (minioninfo->do_reset[chip] <= 1.0 && howlong > MINION_CLR_s) {
- // Always remember the last reset
- while (minioninfo->p_list[chip]->count > 1) {
- pitem = k_unlink_tail(minioninfo->p_list[chip]);
- k_add_head(minioninfo->pfree_list, pitem);
- }
- }
- }
- }
- K_RUNLOCK(minioninfo->hfree_list);
- memcpy(&(minioninfo->chip_chk), &now, sizeof(now));
- }
- for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
- if (minioninfo->has_chip[chip]) {
- // Don't reset the chip while 'changing'
- if (minioninfo->changing[chip])
- continue;
- if (minioninfo->do_reset[chip] > 1.0 ||
- minioninfo->flag_reset[chip]) {
- bool std_reset = true;
- int curr_freq = minioninfo->init_freq[chip];
- int new_freq = 0.0;
- int count;
- // Adjust frequency down?
- if (!opt_minion_noautofreq &&
- minioninfo->p_list[chip]->count >= MINION_RESET_COUNT) {
- pitem = minioninfo->p_list[chip]->head;
- count = 1;
- while (pitem && pitem->next && count++ < MINION_RESET_COUNT) {
- if (DATA_PERF(pitem)->freq != DATA_PERF(pitem->next)->freq)
- break;
- if (count >= MINION_RESET_COUNT) {
- new_freq = minioninfo->init_freq[chip] -
- MINION_FREQ_RESET_STEP;
- if (new_freq < MINION_FREQ_MIN)
- new_freq = MINION_FREQ_MIN;
- if (minioninfo->init_freq[chip] != new_freq) {
- minioninfo->init_freq[chip] = new_freq;
- std_reset = false;
- }
- break;
- } else
- pitem = pitem->next;
- }
- }
- if (std_reset) {
- if (minioninfo->do_reset[chip] > 1.0) {
- applog(LOG_WARNING, "%s%d: Chip %d %dMHz threshold "
- "%.2fGHs - resetting",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- chip, curr_freq,
- minioninfo->do_reset[chip]);
- } else {
- applog(LOG_WARNING, "%s%d: Chip %d %dMhz flagged - "
- "resetting",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- chip, curr_freq);
- }
- } else {
- if (minioninfo->do_reset[chip] > 1.0) {
- applog(LOG_WARNING, "%s%d: Chip %d %dMHz threshold "
- "%.2fGHs - resetting to %dMhz",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- chip, curr_freq,
- minioninfo->do_reset[chip],
- new_freq);
- } else {
- applog(LOG_WARNING, "%s%d: Chip %d %dMhz flagged - "
- "resetting to %dMHz",
- minioncgpu->drv->name,
- minioncgpu->device_id,
- chip, curr_freq, new_freq);
- }
- }
- minioninfo->do_reset[chip] = 0.0;
- memcpy(&(minioninfo->last_reset[chip]), &now, sizeof(now));
- init_chip(minioncgpu, minioninfo, chip);
- minioninfo->flag_reset[chip] = false;
- }
- }
- }
- }
- static int64_t minion_scanwork(__maybe_unused struct thr_info *thr)
- {
- struct cgpu_info *minioncgpu = thr->cgpu;
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- int64_t hashcount = 0;
- if (minioninfo->initialised == false)
- return hashcount;
- minion_do_work(minioncgpu);
- mutex_lock(&(minioninfo->nonce_lock));
- if (minioninfo->new_nonces) {
- hashcount += 0xffffffffull * minioninfo->new_nonces;
- minioninfo->new_nonces = 0;
- }
- mutex_unlock(&(minioninfo->nonce_lock));
- if (opt_minion_idlecount)
- idle_report(minioncgpu);
- // Must always generate data to check/allow for chip reset
- chip_report(minioncgpu);
- /*
- * To avoid wasting CPU, wait until we get an interrupt
- * before returning back to the main cgminer work loop
- * i.e. we then know we'll need more work
- */
- cgsem_mswait(&(minioninfo->scan_work), MINION_SCAN_mS);
- return hashcount;
- }
- static const char *temp_str(uint16_t temp)
- {
- switch (temp) {
- case MINION_TEMP_40:
- return min_temp_40;
- case MINION_TEMP_60:
- return min_temp_60;
- case MINION_TEMP_80:
- return min_temp_80;
- case MINION_TEMP_100:
- return min_temp_100;
- case MINION_TEMP_OVER:
- return min_temp_over;
- }
- return min_temp_invalid;
- }
- static void minion_get_statline_before(char *buf, size_t bufsiz, struct cgpu_info *minioncgpu)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- uint16_t max_temp, cores;
- int chip, core;
- max_temp = 0;
- cores = 0;
- mutex_lock(&(minioninfo->sta_lock));
- for (chip = 0; chip < (int)MINION_CHIPS; chip++) {
- if (minioninfo->has_chip[chip]) {
- if (max_temp < minioninfo->chip_status[chip].temp)
- max_temp = minioninfo->chip_status[chip].temp;
- for (core = 0; core < MINION_CORES; core++) {
- if (minioninfo->chip_core_ena[core >> 5][chip] & (0x1 << (core % 32)))
- cores++;
- }
- }
- }
- mutex_unlock(&(minioninfo->sta_lock));
- tailsprintf(buf, bufsiz, "max%sC Ch:%d Co:%d",
- temp_str(max_temp), minioninfo->chips, (int)cores);
- }
- #define CHIPS_PER_STAT 5
- static struct api_data *minion_api_stats(struct cgpu_info *minioncgpu)
- {
- struct minion_info *minioninfo = (struct minion_info *)(minioncgpu->device_data);
- struct api_data *root = NULL;
- char cores[MINION_CORES+1];
- char data[2048];
- char buf[32];
- int i, to, j;
- size_t datalen, nlen;
- int chip, max_chip, que_work, chip_work, temp;
- if (minioninfo->initialised == false)
- return NULL;
- root = api_add_uint64(root, "OK Nonces", &(minioninfo->ok_nonces), true);
- root = api_add_uint64(root, "New Nonces", &(minioninfo->new_nonces), true);
- root = api_add_uint64(root, "Tested Nonces", &(minioninfo->tested_nonces), true);
- root = api_add_uint64(root, "Untested Nonces", &(minioninfo->untested_nonces), true);
- root = api_add_int(root, "Chips", &(minioninfo->chips), true);
- i = MINION_PIN_COUNT;
- root = api_add_int(root, "GPIO Pins", &i, true);
- max_chip = 0;
- for (chip = 0; chip < (int)MINION_CHIPS; chip++)
- if (minioninfo->has_chip[chip]) {
- max_chip = chip;
- snprintf(buf, sizeof(buf), "Chip %d Pin", chip);
- root = api_add_int(root, buf, &(minioninfo->chip_pin[chip]), true);
- snprintf(buf, sizeof(buf), "Chip %d ChipID", chip);
- i = (int)(minioninfo->chipid[chip]);
- root = api_add_int(root, buf, &i, true);
- snprintf(buf, sizeof(buf), "Chip %d Temperature", chip);
- root = api_add_const(root, buf, temp_str(minioninfo->chip_status[chip].temp), false);
- snprintf(buf, sizeof(buf), "Chip %d Cores", chip);
- root = api_add_uint16(root, buf, &(minioninfo->chip_status[chip].cores), true);
- snprintf(buf, sizeof(buf), "Chip %d Frequency", chip);
- root = api_add_uint32(root, buf, &(minioninfo->chip_status[chip].freq), true);
- snprintf(buf, sizeof(buf), "Chip %d InitFreq", chip);
- root = api_add_int(root, buf, &(minioninfo->init_freq[chip]), true);
- snprintf(buf, sizeof(buf), "Chip %d FreqSent", chip);
- root = api_add_hex32(root, buf, &(minioninfo->freqsent[chip]), true);
- snprintf(buf, sizeof(buf), "Chip %d InitTemp", chip);
- temp = minioninfo->init_temp[chip];
- if (temp == MINION_TEMP_CTL_DISABLE)
- root = api_add_string(root, buf, MINION_TEMP_DISABLE, true);
- else {
- snprintf(data, sizeof(data), "%d", temp);
- root = api_add_string(root, buf, data, true);
- }
- snprintf(buf, sizeof(buf), "Chip %d TempSent", chip);
- root = api_add_hex32(root, buf, &(minioninfo->chip_status[chip].tempsent), true);
- __bin2hex(data, (unsigned char *)(&(minioninfo->init_cores[chip][0])),
- sizeof(minioninfo->init_cores[chip]));
- snprintf(buf, sizeof(buf), "Chip %d InitCores", chip);
- root = api_add_string(root, buf, data, true);
- snprintf(buf, sizeof(buf), "Chip %d IdleCount", chip);
- root = api_add_hex32(root, buf, &(minioninfo->chip_status[chip].idle), true);
- snprintf(buf, sizeof(buf), "Chip %d QueWork", chip);
- root = api_add_uint32(root, buf, &(minioninfo->chip_status[chip].quework), true);
- snprintf(buf, sizeof(buf), "Chip %d ChipWork", chip);
- root = api_add_uint32(root, buf, &(minioninfo->chip_status[chip].chipwork), true);
- snprintf(buf, sizeof(buf), "Chip %d RealWork", chip);
- root = api_add_uint32(root, buf, &(minioninfo->chip_status[chip].realwork), true);
- snprintf(buf, sizeof(buf), "Chip %d QueListCount", chip);
- root = api_add_int(root, buf, &(minioninfo->wque_list[chip]->count), true);
- snprintf(buf, sizeof(buf), "Chip %d WorkListCount", chip);
- root = api_add_int(root, buf, &(minioninfo->wchip_list[chip]->count), true);
- snprintf(buf, sizeof(buf), "Chip %d Overheat", chip);
- root = api_add_bool(root, buf, &(minioninfo->chip_status[chip].overheat), true);
- snprintf(buf, sizeof(buf), "Chip %d Overheats", chip);
- root = api_add_uint32(root, buf, &(minioninfo->chip_status[chip].overheats), true);
- snprintf(buf, sizeof(buf), "Chip %d LastOverheat", chip);
- root = api_add_timeval(root, buf, &(minioninfo->chip_status[chip].lastoverheat), true);
- snprintf(buf, sizeof(buf), "Chip %d LastRecover", chip);
- root = api_add_timeval(root, buf, &(minioninfo->chip_status[chip].lastrecover), true);
- snprintf(buf, sizeof(buf), "Chip %d OverheatIdle", chip);
- root = api_add_double(root, buf, &(minioninfo->chip_status[chip].overheattime), true);
- for (i = 0; i < MINION_CORES; i++) {
- if (minioninfo->chip_core_ena[i >> 5][chip] & (0x1 << (i % 32)))
- cores[i] = 'o';
- else
- cores[i] = 'x';
- }
- cores[MINION_CORES] = '\0';
- snprintf(buf, sizeof(buf), "Chip %d CoresEna", chip);
- root = api_add_string(root, buf, cores, true);
- for (i = 0; i < MINION_CORES; i++) {
- if (minioninfo->chip_core_act[i >> 5][chip] & (0x1 << (i % 32)))
- cores[i] = '-';
- else
- cores[i] = 'o';
- }
- cores[MINION_CORES] = '\0';
- snprintf(buf, sizeof(buf), "Chip %d CoresAct", chip);
- root = api_add_string(root, buf, cores, true);
- if (opt_minion_extra) {
- data[0] = '\0';
- datalen = 0;
- for (i = 0; i < MINION_CORES; i++) {
- if (datalen < sizeof(data)) {
- nlen = snprintf(data+datalen, sizeof(data)-datalen,
- "%s%"PRIu64"-%s%"PRIu64,
- i == 0 ? "" : "/",
- minioninfo->core_good[chip][i],
- minioninfo->core_bad[chip][i] ? "'" : "",
- minioninfo->core_bad[chip][i]);
- if (nlen < 1)
- break;
- datalen += nlen;
- }
- }
- snprintf(buf, sizeof(buf), "Chip %d Cores Good-Bad", chip);
- root = api_add_string(root, buf, data, true);
- }
- snprintf(buf, sizeof(buf), "Chip %d History GHs", chip);
- root = api_add_mhs(root, buf, &(minioninfo->history_ghs[chip]), true);
- }
- double his = MINION_HISTORY_s;
- root = api_add_double(root, "History length", &his, true);
- his = MINION_RESET_s;
- root = api_add_double(root, "Default reset length", &his, true);
- his = MINION_RESET2_s;
- root = api_add_double(root, "Default reset2 length", &his, true);
- root = api_add_bool(root, "Reset2 enabled", &second_check, true);
- for (i = 0; i <= max_chip; i += CHIPS_PER_STAT) {
- to = i + CHIPS_PER_STAT - 1;
- if (to > max_chip)
- to = max_chip;
- data[0] = '\0';
- for (j = i; j <= to; j++) {
- snprintf(buf, sizeof(buf),
- "%s%d",
- j == i ? "" : " ",
- minioninfo->has_chip[j] ? 1 : 0);
- strcat(data, buf);
- }
- snprintf(buf, sizeof(buf), "Detected %02d - %02d", i, to);
- root = api_add_string(root, buf, data, true);
- data[0] = '\0';
- for (j = i; j <= to; j++) {
- snprintf(buf, sizeof(buf),
- "%s%8"PRIu64,
- j == i ? "" : " ",
- minioninfo->chip_nonces[j]);
- strcat(data, buf);
- }
- snprintf(buf, sizeof(buf), "Nonces %02d - %02d", i, to);
- root = api_add_string(root, buf, data, true);
- data[0] = '\0';
- for (j = i; j <= to; j++) {
- snprintf(buf, sizeof(buf),
- "%s%8"PRIu64,
- j == i ? "" : " ",
- minioninfo->chip_nononces[j]);
- strcat(data, buf);
- }
- snprintf(buf, sizeof(buf), "NoNonces %02d - %02d", i, to);
- root = api_add_string(root, buf, data, true);
- data[0] = '\0';
- for (j = i; j <= to; j++) {
- snprintf(buf, sizeof(buf),
- "%s%8"PRIu64,
- j == i ? "" : " ",
- minioninfo->chip_good[j]);
- strcat(data, buf);
- }
- snprintf(buf, sizeof(buf), "Good %02d - %02d", i, to);
- root = api_add_string(root, buf, data, true);
- data[0] = '\0';
- for (j = i; j <= to; j++) {
- snprintf(buf, sizeof(buf),
- "%s%8"PRIu64,
- j == i ? "" : " ",
- minioninfo->chip_bad[j]);
- strcat(data, buf);
- }
- snprintf(buf, sizeof(buf), "Bad %02d - %02d", i, to);
- root = api_add_string(root, buf, data, true);
- data[0] = '\0';
- for (j = i; j <= to; j++) {
- snprintf(buf, sizeof(buf),
- "%s%8"PRIu64,
- j == i ? "" : " ",
- minioninfo->chip_err[j]);
- strcat(data, buf);
- }
- snprintf(buf, sizeof(buf), "Err %02d - %02d", i, to);
- root = api_add_string(root, buf, data, true);
- data[0] = '\0';
- for (j = i; j <= to; j++) {
- snprintf(buf, sizeof(buf),
- "%s%8"PRIu64,
- j == i ? "" : " ",
- minioninfo->fifo_spi_errors[j]);
- strcat(data, buf);
- }
- snprintf(buf, sizeof(buf), "FifoSpiErr %02d - %02d", i, to);
- root = api_add_string(root, buf, data, true);
- data[0] = '\0';
- for (j = i; j <= to; j++) {
- snprintf(buf, sizeof(buf),
- "%s%8"PRIu64,
- j == i ? "" : " ",
- minioninfo->res_spi_errors[j]);
- strcat(data, buf);
- }
- snprintf(buf, sizeof(buf), "ResSpiErr %02d - %02d", i, to);
- root = api_add_string(root, buf, data, true);
- data[0] = '\0';
- for (j = i; j <= to; j++) {
- snprintf(buf, sizeof(buf),
- "%s%"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64"/%"PRIu64,
- j == i ? "" : " ",
- minioninfo->use_res2[j],
- minioninfo->tasks_failed[j],
- minioninfo->tasks_recovered[j],
- minioninfo->nonces_failed[j],
- minioninfo->nonces_recovered[j]);
- strcat(data, buf);
- }
- snprintf(buf, sizeof(buf), "Redo %02d - %02d", i, to);
- root = api_add_string(root, buf, data, true);
- }
- que_work = chip_work = 0;
- for (chip = 0; chip <= max_chip; chip++) {
- if (minioninfo->has_chip[chip]) {
- que_work += minioninfo->wque_list[chip]->count;
- chip_work += minioninfo->wchip_list[chip]->count;
- }
- }
- root = api_add_int(root, "WFree Total", &(minioninfo->wfree_list->total), true);
- root = api_add_int(root, "WFree Count", &(minioninfo->wfree_list->count), true);
- root = api_add_int(root, "WWork Count", &(minioninfo->wwork_list->count), true);
- root = api_add_uint64(root, "WWork Flushed", &(minioninfo->wwork_flushed), true);
- root = api_add_int(root, "WQue Count", &que_work, true);
- root = api_add_uint64(root, "WQue Flushed", &(minioninfo->wque_flushed), true);
- root = api_add_int(root, "WChip Count", &chip_work, true);
- root = api_add_uint64(root, "WChip Stale", &(minioninfo->wchip_staled), true);
- root = api_add_int(root, "TFree Total", &(minioninfo->tfree_list->total), true);
- root = api_add_int(root, "TFree Count", &(minioninfo->tfree_list->count), true);
- root = api_add_int(root, "Task Count", &(minioninfo->task_list->count), true);
- root = api_add_int(root, "Reply Count", &(minioninfo->treply_list->count), true);
- root = api_add_int(root, "RFree Total", &(minioninfo->rfree_list->total), true);
- root = api_add_int(root, "RFree Count", &(minioninfo->rfree_list->count), true);
- root = api_add_int(root, "RNonce Count", &(minioninfo->rnonce_list->count), true);
- root = api_add_int(root, "XFree Count", &(minioninfo->xfree_list->count), true);
- root = api_add_int(root, "XFF Count", &(minioninfo->xff_list->count), true);
- root = api_add_uint64(root, "XFFs", &(minioninfo->xffs), true);
- root = api_add_uint64(root, "SPI Resets", &(minioninfo->spi_resets), true);
- root = api_add_uint64(root, "Power Cycles", &(minioninfo->power_cycles), true);
- root = api_add_int(root, "Chip Report", &opt_minion_chipreport, true);
- root = api_add_int(root, "LED Count", &opt_minion_ledcount, true);
- root = api_add_int(root, "LED Limit", &opt_minion_ledlimit, true);
- bool b = !opt_minion_noautofreq;
- root = api_add_bool(root, "Auto Freq", &b, true);
- root = api_add_int(root, "SPI Delay", &opt_minion_spidelay, true);
- root = api_add_bool(root, "SPI Reset I/O", &(minioninfo->spi_reset_io), true);
- root = api_add_int(root, "SPI Reset", &(minioninfo->spi_reset_count), true);
- root = api_add_int(root, "SPI Reset Sleep", &opt_minion_spisleep, true);
- #if DO_IO_STATS
- #define sta_api(_name, _iostat) \
- do { \
- if ((_iostat).count) { \
- float _davg = (float)((_iostat).total_delay) / (float)((_iostat).count); \
- float _dlavg = (float)((_iostat).total_dlock) / (float)((_iostat).count); \
- float _dlwavg = (float)((_iostat).total_dlwait) / (float)((_iostat).count); \
- float _bavg = (float)((_iostat).total_bytes) / (float)((_iostat).count); \
- float _tavg = (float)((_iostat).tsd) / (float)((_iostat).count); \
- snprintf(data, sizeof(data), "%s Count=%"PRIu64 \
- " Delay=%.0fus DAvg=%.3f" \
- " DMin=%.0f DMax=%.0f DZ=%"PRIu64 \
- " DLock=%.0fus DLAvg=%.3f" \
- " DLMin=%.0f DLMax=%.0f DZ=%"PRIu64 \
- " DLWait=%.0fus DLWAvg=%.3f" \
- " Bytes=%"PRIu64" BAvg=%.3f" \
- " BMin=%"PRIu64" BMax=%"PRIu64" BZ=%"PRIu64 \
- " TSD=%.0fus TAvg=%.03f", \
- _name, (_iostat).count, \
- (_iostat).total_delay, _davg, (_iostat).min_delay, \
- (_iostat).max_delay, (_iostat).zero_delay, \
- (_iostat).total_dlock, _dlavg, (_iostat).min_dlock, \
- (_iostat).max_dlock, (_iostat).zero_dlock, \
- (_iostat).total_dlwait, _dlwavg, \
- (_iostat).total_bytes, _bavg, (_iostat).min_bytes, \
- (_iostat).max_bytes, (_iostat).zero_bytes, \
- (_iostat).tsd, _tavg); \
- root = api_add_string(root, buf, data, true); \
- } \
- } while(0);
- for (i = 0; i < 0x200; i++) {
- snprintf(buf, sizeof(buf), "Stat-0x%02x", i);
- sta_api(addr2txt((uint8_t)(i & 0xff)), minioninfo->iostats[i]);
- }
- // Test to avoid showing applog
- if (minioninfo->summary.count) {
- snprintf(buf, sizeof(buf), "Stat-S");
- sta_api("Summary", minioninfo->summary);
- applog(LOG_WARNING, "%s %d: (%.0f) %s - %s",
- minioncgpu->drv->name, minioncgpu->device_id,
- total_secs, buf, data);
- }
- #endif
- root = api_add_uint64(root, "Total SPI Errors", &(minioninfo->spi_errors), true);
- root = api_add_uint64(root, "Work Unrolled", &(minioninfo->work_unrolled), true);
- root = api_add_uint64(root, "Work Rolled", &(minioninfo->work_rolled), true);
- root = api_add_uint64(root, "Ints", &(minioninfo->interrupts), true);
- root = api_add_uint64(root, "Res Ints", &(minioninfo->result_interrupts), true);
- root = api_add_uint64(root, "Cmd Ints", &(minioninfo->command_interrupts), true);
- root = api_add_string(root, "Last Int", minioninfo->last_interrupt, true);
- root = api_add_hex32(root, "Next TaskID", &(minioninfo->next_task_id), true);
- double avg;
- root = api_add_uint64(root, "ToQue", &(minioninfo->que_work), true);
- if (minioninfo->que_work)
- avg = minioninfo->que_time / (double)(minioninfo->que_work);
- else
- avg = 0;
- root = api_add_double(root, "Que Avg", &avg, true);
- root = api_add_double(root, "Que Min", &(minioninfo->que_min), true);
- root = api_add_double(root, "Que Max", &(minioninfo->que_max), true);
- data[0] = '\0';
- for (i = 0; i <= TIME_BANDS; i++) {
- snprintf(buf, sizeof(buf),
- "%s%"PRIu64,
- i == 0 ? "" : "/",
- minioninfo->que_bands[i]);
- strcat(data, buf);
- }
- root = api_add_string(root, "Que Bands", data, true);
- root = api_add_uint64(root, "ToTxRx", &(minioninfo->wt_work), true);
- if (minioninfo->wt_work)
- avg = minioninfo->wt_time / (double)(minioninfo->wt_work);
- else
- avg = 0;
- root = api_add_double(root, "TxRx Avg", &avg, true);
- root = api_add_double(root, "TxRx Min", &(minioninfo->wt_min), true);
- root = api_add_double(root, "TxRx Max", &(minioninfo->wt_max), true);
- data[0] = '\0';
- for (i = 0; i <= TIME_BANDS; i++) {
- snprintf(buf, sizeof(buf),
- "%s%"PRIu64,
- i == 0 ? "" : "/",
- minioninfo->wt_bands[i]);
- strcat(data, buf);
- }
- root = api_add_string(root, "TxRx Bands", data, true);
- uint64_t checked, dups;
- dupcounters(minioncgpu, &checked, &dups);
- root = api_add_uint64(root, "Dups", &dups, true);
- return root;
- }
- #endif
- struct device_drv minion_drv = {
- .drv_id = DRIVER_minion,
- .dname = "Minion BlackArrow",
- .name = "MBA",
- .drv_detect = minion_detect,
- #ifdef LINUX
- .get_api_stats = minion_api_stats,
- .get_statline_before = minion_get_statline_before,
- .set_device = minion_api_set,
- .identify_device = minion_identify,
- .thread_prepare = minion_thread_prepare,
- .hash_work = hash_queued_work,
- .scanwork = minion_scanwork,
- .queue_full = minion_queue_full,
- .flush_work = minion_flush_work,
- .thread_shutdown = minion_shutdown
- #endif
- };
|