1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513 |
- diff -Nur linux-4.1.6.orig/drivers/net/phy/ar8216.c linux-4.1.6/drivers/net/phy/ar8216.c
- --- linux-4.1.6.orig/drivers/net/phy/ar8216.c 1970-01-01 01:00:00.000000000 +0100
- +++ linux-4.1.6/drivers/net/phy/ar8216.c 2015-09-13 23:19:20.073314441 +0200
- @@ -0,0 +1,2182 @@
- +/*
- + * ar8216.c: AR8216 switch driver
- + *
- + * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
- + * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
- + *
- + * 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 2
- + * of the License, or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + */
- +
- +#include <linux/if.h>
- +#include <linux/module.h>
- +#include <linux/init.h>
- +#include <linux/list.h>
- +#include <linux/if_ether.h>
- +#include <linux/skbuff.h>
- +#include <linux/netdevice.h>
- +#include <linux/netlink.h>
- +#include <linux/bitops.h>
- +#include <net/genetlink.h>
- +#include <linux/switch.h>
- +#include <linux/delay.h>
- +#include <linux/phy.h>
- +#include <linux/netdevice.h>
- +#include <linux/etherdevice.h>
- +#include <linux/lockdep.h>
- +#include <linux/ar8216_platform.h>
- +#include <linux/workqueue.h>
- +#include <linux/version.h>
- +
- +#include "ar8216.h"
- +
- +extern const struct ar8xxx_chip ar8327_chip;
- +extern const struct ar8xxx_chip ar8337_chip;
- +
- +#define AR8XXX_MIB_WORK_DELAY 2000 /* msecs */
- +
- +#define MIB_DESC(_s , _o, _n) \
- + { \
- + .size = (_s), \
- + .offset = (_o), \
- + .name = (_n), \
- + }
- +
- +static const struct ar8xxx_mib_desc ar8216_mibs[] = {
- + MIB_DESC(1, AR8216_STATS_RXBROAD, "RxBroad"),
- + MIB_DESC(1, AR8216_STATS_RXPAUSE, "RxPause"),
- + MIB_DESC(1, AR8216_STATS_RXMULTI, "RxMulti"),
- + MIB_DESC(1, AR8216_STATS_RXFCSERR, "RxFcsErr"),
- + MIB_DESC(1, AR8216_STATS_RXALIGNERR, "RxAlignErr"),
- + MIB_DESC(1, AR8216_STATS_RXRUNT, "RxRunt"),
- + MIB_DESC(1, AR8216_STATS_RXFRAGMENT, "RxFragment"),
- + MIB_DESC(1, AR8216_STATS_RX64BYTE, "Rx64Byte"),
- + MIB_DESC(1, AR8216_STATS_RX128BYTE, "Rx128Byte"),
- + MIB_DESC(1, AR8216_STATS_RX256BYTE, "Rx256Byte"),
- + MIB_DESC(1, AR8216_STATS_RX512BYTE, "Rx512Byte"),
- + MIB_DESC(1, AR8216_STATS_RX1024BYTE, "Rx1024Byte"),
- + MIB_DESC(1, AR8216_STATS_RXMAXBYTE, "RxMaxByte"),
- + MIB_DESC(1, AR8216_STATS_RXTOOLONG, "RxTooLong"),
- + MIB_DESC(2, AR8216_STATS_RXGOODBYTE, "RxGoodByte"),
- + MIB_DESC(2, AR8216_STATS_RXBADBYTE, "RxBadByte"),
- + MIB_DESC(1, AR8216_STATS_RXOVERFLOW, "RxOverFlow"),
- + MIB_DESC(1, AR8216_STATS_FILTERED, "Filtered"),
- + MIB_DESC(1, AR8216_STATS_TXBROAD, "TxBroad"),
- + MIB_DESC(1, AR8216_STATS_TXPAUSE, "TxPause"),
- + MIB_DESC(1, AR8216_STATS_TXMULTI, "TxMulti"),
- + MIB_DESC(1, AR8216_STATS_TXUNDERRUN, "TxUnderRun"),
- + MIB_DESC(1, AR8216_STATS_TX64BYTE, "Tx64Byte"),
- + MIB_DESC(1, AR8216_STATS_TX128BYTE, "Tx128Byte"),
- + MIB_DESC(1, AR8216_STATS_TX256BYTE, "Tx256Byte"),
- + MIB_DESC(1, AR8216_STATS_TX512BYTE, "Tx512Byte"),
- + MIB_DESC(1, AR8216_STATS_TX1024BYTE, "Tx1024Byte"),
- + MIB_DESC(1, AR8216_STATS_TXMAXBYTE, "TxMaxByte"),
- + MIB_DESC(1, AR8216_STATS_TXOVERSIZE, "TxOverSize"),
- + MIB_DESC(2, AR8216_STATS_TXBYTE, "TxByte"),
- + MIB_DESC(1, AR8216_STATS_TXCOLLISION, "TxCollision"),
- + MIB_DESC(1, AR8216_STATS_TXABORTCOL, "TxAbortCol"),
- + MIB_DESC(1, AR8216_STATS_TXMULTICOL, "TxMultiCol"),
- + MIB_DESC(1, AR8216_STATS_TXSINGLECOL, "TxSingleCol"),
- + MIB_DESC(1, AR8216_STATS_TXEXCDEFER, "TxExcDefer"),
- + MIB_DESC(1, AR8216_STATS_TXDEFER, "TxDefer"),
- + MIB_DESC(1, AR8216_STATS_TXLATECOL, "TxLateCol"),
- +};
- +
- +const struct ar8xxx_mib_desc ar8236_mibs[39] = {
- + MIB_DESC(1, AR8236_STATS_RXBROAD, "RxBroad"),
- + MIB_DESC(1, AR8236_STATS_RXPAUSE, "RxPause"),
- + MIB_DESC(1, AR8236_STATS_RXMULTI, "RxMulti"),
- + MIB_DESC(1, AR8236_STATS_RXFCSERR, "RxFcsErr"),
- + MIB_DESC(1, AR8236_STATS_RXALIGNERR, "RxAlignErr"),
- + MIB_DESC(1, AR8236_STATS_RXRUNT, "RxRunt"),
- + MIB_DESC(1, AR8236_STATS_RXFRAGMENT, "RxFragment"),
- + MIB_DESC(1, AR8236_STATS_RX64BYTE, "Rx64Byte"),
- + MIB_DESC(1, AR8236_STATS_RX128BYTE, "Rx128Byte"),
- + MIB_DESC(1, AR8236_STATS_RX256BYTE, "Rx256Byte"),
- + MIB_DESC(1, AR8236_STATS_RX512BYTE, "Rx512Byte"),
- + MIB_DESC(1, AR8236_STATS_RX1024BYTE, "Rx1024Byte"),
- + MIB_DESC(1, AR8236_STATS_RX1518BYTE, "Rx1518Byte"),
- + MIB_DESC(1, AR8236_STATS_RXMAXBYTE, "RxMaxByte"),
- + MIB_DESC(1, AR8236_STATS_RXTOOLONG, "RxTooLong"),
- + MIB_DESC(2, AR8236_STATS_RXGOODBYTE, "RxGoodByte"),
- + MIB_DESC(2, AR8236_STATS_RXBADBYTE, "RxBadByte"),
- + MIB_DESC(1, AR8236_STATS_RXOVERFLOW, "RxOverFlow"),
- + MIB_DESC(1, AR8236_STATS_FILTERED, "Filtered"),
- + MIB_DESC(1, AR8236_STATS_TXBROAD, "TxBroad"),
- + MIB_DESC(1, AR8236_STATS_TXPAUSE, "TxPause"),
- + MIB_DESC(1, AR8236_STATS_TXMULTI, "TxMulti"),
- + MIB_DESC(1, AR8236_STATS_TXUNDERRUN, "TxUnderRun"),
- + MIB_DESC(1, AR8236_STATS_TX64BYTE, "Tx64Byte"),
- + MIB_DESC(1, AR8236_STATS_TX128BYTE, "Tx128Byte"),
- + MIB_DESC(1, AR8236_STATS_TX256BYTE, "Tx256Byte"),
- + MIB_DESC(1, AR8236_STATS_TX512BYTE, "Tx512Byte"),
- + MIB_DESC(1, AR8236_STATS_TX1024BYTE, "Tx1024Byte"),
- + MIB_DESC(1, AR8236_STATS_TX1518BYTE, "Tx1518Byte"),
- + MIB_DESC(1, AR8236_STATS_TXMAXBYTE, "TxMaxByte"),
- + MIB_DESC(1, AR8236_STATS_TXOVERSIZE, "TxOverSize"),
- + MIB_DESC(2, AR8236_STATS_TXBYTE, "TxByte"),
- + MIB_DESC(1, AR8236_STATS_TXCOLLISION, "TxCollision"),
- + MIB_DESC(1, AR8236_STATS_TXABORTCOL, "TxAbortCol"),
- + MIB_DESC(1, AR8236_STATS_TXMULTICOL, "TxMultiCol"),
- + MIB_DESC(1, AR8236_STATS_TXSINGLECOL, "TxSingleCol"),
- + MIB_DESC(1, AR8236_STATS_TXEXCDEFER, "TxExcDefer"),
- + MIB_DESC(1, AR8236_STATS_TXDEFER, "TxDefer"),
- + MIB_DESC(1, AR8236_STATS_TXLATECOL, "TxLateCol"),
- +};
- +
- +static DEFINE_MUTEX(ar8xxx_dev_list_lock);
- +static LIST_HEAD(ar8xxx_dev_list);
- +
- +/* inspired by phy_poll_reset in drivers/net/phy/phy_device.c */
- +static int
- +ar8xxx_phy_poll_reset(struct mii_bus *bus)
- +{
- + unsigned int sleep_msecs = 20;
- + int ret, elapsed, i;
- +
- + for (elapsed = sleep_msecs; elapsed <= 600;
- + elapsed += sleep_msecs) {
- + msleep(sleep_msecs);
- + for (i = 0; i < AR8XXX_NUM_PHYS; i++) {
- + ret = mdiobus_read(bus, i, MII_BMCR);
- + if (ret < 0)
- + return ret;
- + if (ret & BMCR_RESET)
- + break;
- + if (i == AR8XXX_NUM_PHYS - 1) {
- + usleep_range(1000, 2000);
- + return 0;
- + }
- + }
- + }
- + return -ETIMEDOUT;
- +}
- +
- +static int
- +ar8xxx_phy_check_aneg(struct phy_device *phydev)
- +{
- + int ret;
- +
- + if (phydev->autoneg != AUTONEG_ENABLE)
- + return 0;
- + /*
- + * BMCR_ANENABLE might have been cleared
- + * by phy_init_hw in certain kernel versions
- + * therefore check for it
- + */
- + ret = phy_read(phydev, MII_BMCR);
- + if (ret < 0)
- + return ret;
- + if (ret & BMCR_ANENABLE)
- + return 0;
- +
- + dev_info(&phydev->dev, "ANEG disabled, re-enabling ...\n");
- + ret |= BMCR_ANENABLE | BMCR_ANRESTART;
- + return phy_write(phydev, MII_BMCR, ret);
- +}
- +
- +void
- +ar8xxx_phy_init(struct ar8xxx_priv *priv)
- +{
- + int i;
- + struct mii_bus *bus;
- +
- + bus = priv->mii_bus;
- + for (i = 0; i < AR8XXX_NUM_PHYS; i++) {
- + if (priv->chip->phy_fixup)
- + priv->chip->phy_fixup(priv, i);
- +
- + /* initialize the port itself */
- + mdiobus_write(bus, i, MII_ADVERTISE,
- + ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
- + if (ar8xxx_has_gige(priv))
- + mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL);
- + mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
- + }
- +
- + ar8xxx_phy_poll_reset(bus);
- +}
- +
- +u32
- +ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum)
- +{
- + struct mii_bus *bus = priv->mii_bus;
- + u16 lo, hi;
- +
- + lo = bus->read(bus, phy_id, regnum);
- + hi = bus->read(bus, phy_id, regnum + 1);
- +
- + return (hi << 16) | lo;
- +}
- +
- +void
- +ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val)
- +{
- + struct mii_bus *bus = priv->mii_bus;
- + u16 lo, hi;
- +
- + lo = val & 0xffff;
- + hi = (u16) (val >> 16);
- +
- + if (priv->chip->mii_lo_first)
- + {
- + bus->write(bus, phy_id, regnum, lo);
- + bus->write(bus, phy_id, regnum + 1, hi);
- + } else {
- + bus->write(bus, phy_id, regnum + 1, hi);
- + bus->write(bus, phy_id, regnum, lo);
- + }
- +}
- +
- +u32
- +ar8xxx_read(struct ar8xxx_priv *priv, int reg)
- +{
- + struct mii_bus *bus = priv->mii_bus;
- + u16 r1, r2, page;
- + u32 val;
- +
- + split_addr((u32) reg, &r1, &r2, &page);
- +
- + mutex_lock(&bus->mdio_lock);
- +
- + bus->write(bus, 0x18, 0, page);
- + wait_for_page_switch();
- + val = ar8xxx_mii_read32(priv, 0x10 | r2, r1);
- +
- + mutex_unlock(&bus->mdio_lock);
- +
- + return val;
- +}
- +
- +void
- +ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val)
- +{
- + struct mii_bus *bus = priv->mii_bus;
- + u16 r1, r2, page;
- +
- + split_addr((u32) reg, &r1, &r2, &page);
- +
- + mutex_lock(&bus->mdio_lock);
- +
- + bus->write(bus, 0x18, 0, page);
- + wait_for_page_switch();
- + ar8xxx_mii_write32(priv, 0x10 | r2, r1, val);
- +
- + mutex_unlock(&bus->mdio_lock);
- +}
- +
- +u32
- +ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
- +{
- + struct mii_bus *bus = priv->mii_bus;
- + u16 r1, r2, page;
- + u32 ret;
- +
- + split_addr((u32) reg, &r1, &r2, &page);
- +
- + mutex_lock(&bus->mdio_lock);
- +
- + bus->write(bus, 0x18, 0, page);
- + wait_for_page_switch();
- +
- + ret = ar8xxx_mii_read32(priv, 0x10 | r2, r1);
- + ret &= ~mask;
- + ret |= val;
- + ar8xxx_mii_write32(priv, 0x10 | r2, r1, ret);
- +
- + mutex_unlock(&bus->mdio_lock);
- +
- + return ret;
- +}
- +
- +void
- +ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
- + u16 dbg_addr, u16 dbg_data)
- +{
- + struct mii_bus *bus = priv->mii_bus;
- +
- + mutex_lock(&bus->mdio_lock);
- + bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr);
- + bus->write(bus, phy_addr, MII_ATH_DBG_DATA, dbg_data);
- + mutex_unlock(&bus->mdio_lock);
- +}
- +
- +void
- +ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 data)
- +{
- + struct mii_bus *bus = priv->mii_bus;
- +
- + mutex_lock(&bus->mdio_lock);
- + bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr);
- + bus->write(bus, phy_addr, MII_ATH_MMD_DATA, data);
- + mutex_unlock(&bus->mdio_lock);
- +}
- +
- +u16
- +ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr)
- +{
- + struct mii_bus *bus = priv->mii_bus;
- + u16 data;
- +
- + mutex_lock(&bus->mdio_lock);
- + bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr);
- + data = bus->read(bus, phy_addr, MII_ATH_MMD_DATA);
- + mutex_unlock(&bus->mdio_lock);
- +
- + return data;
- +}
- +
- +static int
- +ar8xxx_reg_wait(struct ar8xxx_priv *priv, u32 reg, u32 mask, u32 val,
- + unsigned timeout)
- +{
- + int i;
- +
- + for (i = 0; i < timeout; i++) {
- + u32 t;
- +
- + t = ar8xxx_read(priv, reg);
- + if ((t & mask) == val)
- + return 0;
- +
- + usleep_range(1000, 2000);
- + }
- +
- + return -ETIMEDOUT;
- +}
- +
- +static int
- +ar8xxx_mib_op(struct ar8xxx_priv *priv, u32 op)
- +{
- + unsigned mib_func = priv->chip->mib_func;
- + int ret;
- +
- + lockdep_assert_held(&priv->mib_lock);
- +
- + /* Capture the hardware statistics for all ports */
- + ar8xxx_rmw(priv, mib_func, AR8216_MIB_FUNC, (op << AR8216_MIB_FUNC_S));
- +
- + /* Wait for the capturing to complete. */
- + ret = ar8xxx_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10);
- + if (ret)
- + goto out;
- +
- + ret = 0;
- +
- +out:
- + return ret;
- +}
- +
- +static int
- +ar8xxx_mib_capture(struct ar8xxx_priv *priv)
- +{
- + return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_CAPTURE);
- +}
- +
- +static int
- +ar8xxx_mib_flush(struct ar8xxx_priv *priv)
- +{
- + return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_FLUSH);
- +}
- +
- +static void
- +ar8xxx_mib_fetch_port_stat(struct ar8xxx_priv *priv, int port, bool flush)
- +{
- + unsigned int base;
- + u64 *mib_stats;
- + int i;
- +
- + WARN_ON(port >= priv->dev.ports);
- +
- + lockdep_assert_held(&priv->mib_lock);
- +
- + base = priv->chip->reg_port_stats_start +
- + priv->chip->reg_port_stats_length * port;
- +
- + mib_stats = &priv->mib_stats[port * priv->chip->num_mibs];
- + for (i = 0; i < priv->chip->num_mibs; i++) {
- + const struct ar8xxx_mib_desc *mib;
- + u64 t;
- +
- + mib = &priv->chip->mib_decs[i];
- + t = ar8xxx_read(priv, base + mib->offset);
- + if (mib->size == 2) {
- + u64 hi;
- +
- + hi = ar8xxx_read(priv, base + mib->offset + 4);
- + t |= hi << 32;
- + }
- +
- + if (flush)
- + mib_stats[i] = 0;
- + else
- + mib_stats[i] += t;
- + }
- +}
- +
- +static void
- +ar8216_read_port_link(struct ar8xxx_priv *priv, int port,
- + struct switch_port_link *link)
- +{
- + u32 status;
- + u32 speed;
- +
- + memset(link, '\0', sizeof(*link));
- +
- + status = priv->chip->read_port_status(priv, port);
- +
- + link->aneg = !!(status & AR8216_PORT_STATUS_LINK_AUTO);
- + if (link->aneg) {
- + link->link = !!(status & AR8216_PORT_STATUS_LINK_UP);
- + } else {
- + link->link = true;
- +
- + if (priv->get_port_link) {
- + int err;
- +
- + err = priv->get_port_link(port);
- + if (err >= 0)
- + link->link = !!err;
- + }
- + }
- +
- + if (!link->link)
- + return;
- +
- + link->duplex = !!(status & AR8216_PORT_STATUS_DUPLEX);
- + link->tx_flow = !!(status & AR8216_PORT_STATUS_TXFLOW);
- + link->rx_flow = !!(status & AR8216_PORT_STATUS_RXFLOW);
- +
- + if (link->aneg && link->duplex && priv->chip->read_port_eee_status)
- + link->eee = priv->chip->read_port_eee_status(priv, port);
- +
- + speed = (status & AR8216_PORT_STATUS_SPEED) >>
- + AR8216_PORT_STATUS_SPEED_S;
- +
- + switch (speed) {
- + case AR8216_PORT_SPEED_10M:
- + link->speed = SWITCH_PORT_SPEED_10;
- + break;
- + case AR8216_PORT_SPEED_100M:
- + link->speed = SWITCH_PORT_SPEED_100;
- + break;
- + case AR8216_PORT_SPEED_1000M:
- + link->speed = SWITCH_PORT_SPEED_1000;
- + break;
- + default:
- + link->speed = SWITCH_PORT_SPEED_UNKNOWN;
- + break;
- + }
- +}
- +
- +static struct sk_buff *
- +ar8216_mangle_tx(struct net_device *dev, struct sk_buff *skb)
- +{
- + struct ar8xxx_priv *priv = dev->phy_ptr;
- + unsigned char *buf;
- +
- + if (unlikely(!priv))
- + goto error;
- +
- + if (!priv->vlan)
- + goto send;
- +
- + if (unlikely(skb_headroom(skb) < 2)) {
- + if (pskb_expand_head(skb, 2, 0, GFP_ATOMIC) < 0)
- + goto error;
- + }
- +
- + buf = skb_push(skb, 2);
- + buf[0] = 0x10;
- + buf[1] = 0x80;
- +
- +send:
- + return skb;
- +
- +error:
- + dev_kfree_skb_any(skb);
- + return NULL;
- +}
- +
- +static void
- +ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb)
- +{
- + struct ar8xxx_priv *priv;
- + unsigned char *buf;
- + int port, vlan;
- +
- + priv = dev->phy_ptr;
- + if (!priv)
- + return;
- +
- + /* don't strip the header if vlan mode is disabled */
- + if (!priv->vlan)
- + return;
- +
- + /* strip header, get vlan id */
- + buf = skb->data;
- + skb_pull(skb, 2);
- +
- + /* check for vlan header presence */
- + if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00))
- + return;
- +
- + port = buf[0] & 0xf;
- +
- + /* no need to fix up packets coming from a tagged source */
- + if (priv->vlan_tagged & (1 << port))
- + return;
- +
- + /* lookup port vid from local table, the switch passes an invalid vlan id */
- + vlan = priv->vlan_id[priv->pvid[port]];
- +
- + buf[14 + 2] &= 0xf0;
- + buf[14 + 2] |= vlan >> 8;
- + buf[15 + 2] = vlan & 0xff;
- +}
- +
- +int
- +ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
- +{
- + int timeout = 20;
- + u32 t = 0;
- +
- + while (1) {
- + t = ar8xxx_read(priv, reg);
- + if ((t & mask) == val)
- + return 0;
- +
- + if (timeout-- <= 0)
- + break;
- +
- + udelay(10);
- + }
- +
- + pr_err("ar8216: timeout on reg %08x: %08x & %08x != %08x\n",
- + (unsigned int) reg, t, mask, val);
- + return -ETIMEDOUT;
- +}
- +
- +static void
- +ar8216_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val)
- +{
- + if (ar8216_wait_bit(priv, AR8216_REG_VTU, AR8216_VTU_ACTIVE, 0))
- + return;
- + if ((op & AR8216_VTU_OP) == AR8216_VTU_OP_LOAD) {
- + val &= AR8216_VTUDATA_MEMBER;
- + val |= AR8216_VTUDATA_VALID;
- + ar8xxx_write(priv, AR8216_REG_VTU_DATA, val);
- + }
- + op |= AR8216_VTU_ACTIVE;
- + ar8xxx_write(priv, AR8216_REG_VTU, op);
- +}
- +
- +static void
- +ar8216_vtu_flush(struct ar8xxx_priv *priv)
- +{
- + ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0);
- +}
- +
- +static void
- +ar8216_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask)
- +{
- + u32 op;
- +
- + op = AR8216_VTU_OP_LOAD | (vid << AR8216_VTU_VID_S);
- + ar8216_vtu_op(priv, op, port_mask);
- +}
- +
- +static int
- +ar8216_atu_flush(struct ar8xxx_priv *priv)
- +{
- + int ret;
- +
- + ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0);
- + if (!ret)
- + ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_OP_FLUSH |
- + AR8216_ATU_ACTIVE);
- +
- + return ret;
- +}
- +
- +static int
- +ar8216_atu_flush_port(struct ar8xxx_priv *priv, int port)
- +{
- + u32 t;
- + int ret;
- +
- + ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0);
- + if (!ret) {
- + t = (port << AR8216_ATU_PORT_NUM_S) | AR8216_ATU_OP_FLUSH_PORT;
- + t |= AR8216_ATU_ACTIVE;
- + ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, t);
- + }
- +
- + return ret;
- +}
- +
- +static u32
- +ar8216_read_port_status(struct ar8xxx_priv *priv, int port)
- +{
- + return ar8xxx_read(priv, AR8216_REG_PORT_STATUS(port));
- +}
- +
- +static void
- +ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 members)
- +{
- + u32 header;
- + u32 egress, ingress;
- + u32 pvid;
- +
- + if (priv->vlan) {
- + pvid = priv->vlan_id[priv->pvid[port]];
- + if (priv->vlan_tagged & (1 << port))
- + egress = AR8216_OUT_ADD_VLAN;
- + else
- + egress = AR8216_OUT_STRIP_VLAN;
- + ingress = AR8216_IN_SECURE;
- + } else {
- + pvid = port;
- + egress = AR8216_OUT_KEEP;
- + ingress = AR8216_IN_PORT_ONLY;
- + }
- +
- + if (chip_is_ar8216(priv) && priv->vlan && port == AR8216_PORT_CPU)
- + header = AR8216_PORT_CTRL_HEADER;
- + else
- + header = 0;
- +
- + ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
- + AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE |
- + AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE |
- + AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK,
- + AR8216_PORT_CTRL_LEARN | header |
- + (egress << AR8216_PORT_CTRL_VLAN_MODE_S) |
- + (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S));
- +
- + ar8xxx_rmw(priv, AR8216_REG_PORT_VLAN(port),
- + AR8216_PORT_VLAN_DEST_PORTS | AR8216_PORT_VLAN_MODE |
- + AR8216_PORT_VLAN_DEFAULT_ID,
- + (members << AR8216_PORT_VLAN_DEST_PORTS_S) |
- + (ingress << AR8216_PORT_VLAN_MODE_S) |
- + (pvid << AR8216_PORT_VLAN_DEFAULT_ID_S));
- +}
- +
- +static int
- +ar8216_hw_init(struct ar8xxx_priv *priv)
- +{
- + if (priv->initialized)
- + return 0;
- +
- + ar8xxx_phy_init(priv);
- +
- + priv->initialized = true;
- + return 0;
- +}
- +
- +static void
- +ar8216_init_globals(struct ar8xxx_priv *priv)
- +{
- + /* standard atheros magic */
- + ar8xxx_write(priv, 0x38, 0xc000050e);
- +
- + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
- + AR8216_GCTRL_MTU, 1518 + 8 + 2);
- +}
- +
- +static void
- +ar8216_init_port(struct ar8xxx_priv *priv, int port)
- +{
- + /* Enable port learning and tx */
- + ar8xxx_write(priv, AR8216_REG_PORT_CTRL(port),
- + AR8216_PORT_CTRL_LEARN |
- + (4 << AR8216_PORT_CTRL_STATE_S));
- +
- + ar8xxx_write(priv, AR8216_REG_PORT_VLAN(port), 0);
- +
- + if (port == AR8216_PORT_CPU) {
- + ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port),
- + AR8216_PORT_STATUS_LINK_UP |
- + (ar8xxx_has_gige(priv) ?
- + AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) |
- + AR8216_PORT_STATUS_TXMAC |
- + AR8216_PORT_STATUS_RXMAC |
- + (chip_is_ar8316(priv) ? AR8216_PORT_STATUS_RXFLOW : 0) |
- + (chip_is_ar8316(priv) ? AR8216_PORT_STATUS_TXFLOW : 0) |
- + AR8216_PORT_STATUS_DUPLEX);
- + } else {
- + ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port),
- + AR8216_PORT_STATUS_LINK_AUTO);
- + }
- +}
- +
- +static void
- +ar8216_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1)
- +{
- + int timeout = 20;
- +
- + while (ar8xxx_mii_read32(priv, r2, r1) & AR8216_ATU_ACTIVE && --timeout)
- + udelay(10);
- +
- + if (!timeout)
- + pr_err("ar8216: timeout waiting for atu to become ready\n");
- +}
- +
- +static void ar8216_get_arl_entry(struct ar8xxx_priv *priv,
- + struct arl_entry *a, u32 *status, enum arl_op op)
- +{
- + struct mii_bus *bus = priv->mii_bus;
- + u16 r2, page;
- + u16 r1_func0, r1_func1, r1_func2;
- + u32 t, val0, val1, val2;
- + int i;
- +
- + split_addr(AR8216_REG_ATU_FUNC0, &r1_func0, &r2, &page);
- + r2 |= 0x10;
- +
- + r1_func1 = (AR8216_REG_ATU_FUNC1 >> 1) & 0x1e;
- + r1_func2 = (AR8216_REG_ATU_FUNC2 >> 1) & 0x1e;
- +
- + switch (op) {
- + case AR8XXX_ARL_INITIALIZE:
- + /* all ATU registers are on the same page
- + * therefore set page only once
- + */
- + bus->write(bus, 0x18, 0, page);
- + wait_for_page_switch();
- +
- + ar8216_wait_atu_ready(priv, r2, r1_func0);
- +
- + ar8xxx_mii_write32(priv, r2, r1_func0, AR8216_ATU_OP_GET_NEXT);
- + ar8xxx_mii_write32(priv, r2, r1_func1, 0);
- + ar8xxx_mii_write32(priv, r2, r1_func2, 0);
- + break;
- + case AR8XXX_ARL_GET_NEXT:
- + t = ar8xxx_mii_read32(priv, r2, r1_func0);
- + t |= AR8216_ATU_ACTIVE;
- + ar8xxx_mii_write32(priv, r2, r1_func0, t);
- + ar8216_wait_atu_ready(priv, r2, r1_func0);
- +
- + val0 = ar8xxx_mii_read32(priv, r2, r1_func0);
- + val1 = ar8xxx_mii_read32(priv, r2, r1_func1);
- + val2 = ar8xxx_mii_read32(priv, r2, r1_func2);
- +
- + *status = (val2 & AR8216_ATU_STATUS) >> AR8216_ATU_STATUS_S;
- + if (!*status)
- + break;
- +
- + i = 0;
- + t = AR8216_ATU_PORT0;
- + while (!(val2 & t) && ++i < priv->dev.ports)
- + t <<= 1;
- +
- + a->port = i;
- + a->mac[0] = (val0 & AR8216_ATU_ADDR5) >> AR8216_ATU_ADDR5_S;
- + a->mac[1] = (val0 & AR8216_ATU_ADDR4) >> AR8216_ATU_ADDR4_S;
- + a->mac[2] = (val1 & AR8216_ATU_ADDR3) >> AR8216_ATU_ADDR3_S;
- + a->mac[3] = (val1 & AR8216_ATU_ADDR2) >> AR8216_ATU_ADDR2_S;
- + a->mac[4] = (val1 & AR8216_ATU_ADDR1) >> AR8216_ATU_ADDR1_S;
- + a->mac[5] = (val1 & AR8216_ATU_ADDR0) >> AR8216_ATU_ADDR0_S;
- + break;
- + }
- +}
- +
- +static void
- +ar8236_setup_port(struct ar8xxx_priv *priv, int port, u32 members)
- +{
- + u32 egress, ingress;
- + u32 pvid;
- +
- + if (priv->vlan) {
- + pvid = priv->vlan_id[priv->pvid[port]];
- + if (priv->vlan_tagged & (1 << port))
- + egress = AR8216_OUT_ADD_VLAN;
- + else
- + egress = AR8216_OUT_STRIP_VLAN;
- + ingress = AR8216_IN_SECURE;
- + } else {
- + pvid = port;
- + egress = AR8216_OUT_KEEP;
- + ingress = AR8216_IN_PORT_ONLY;
- + }
- +
- + ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
- + AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE |
- + AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE |
- + AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK,
- + AR8216_PORT_CTRL_LEARN |
- + (egress << AR8216_PORT_CTRL_VLAN_MODE_S) |
- + (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S));
- +
- + ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN(port),
- + AR8236_PORT_VLAN_DEFAULT_ID,
- + (pvid << AR8236_PORT_VLAN_DEFAULT_ID_S));
- +
- + ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN2(port),
- + AR8236_PORT_VLAN2_VLAN_MODE |
- + AR8236_PORT_VLAN2_MEMBER,
- + (ingress << AR8236_PORT_VLAN2_VLAN_MODE_S) |
- + (members << AR8236_PORT_VLAN2_MEMBER_S));
- +}
- +
- +static void
- +ar8236_init_globals(struct ar8xxx_priv *priv)
- +{
- + /* enable jumbo frames */
- + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
- + AR8316_GCTRL_MTU, 9018 + 8 + 2);
- +
- + /* enable cpu port to receive arp frames */
- + ar8xxx_reg_set(priv, AR8216_REG_ATU_CTRL,
- + AR8236_ATU_CTRL_RES);
- +
- + /* enable cpu port to receive multicast and broadcast frames */
- + ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK,
- + AR8236_FM_CPU_BROADCAST_EN | AR8236_FM_CPU_BCAST_FWD_EN);
- +
- + /* Enable MIB counters */
- + ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN,
- + (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) |
- + AR8236_MIB_EN);
- +}
- +
- +static int
- +ar8316_hw_init(struct ar8xxx_priv *priv)
- +{
- + u32 val, newval;
- +
- + val = ar8xxx_read(priv, AR8316_REG_POSTRIP);
- +
- + if (priv->phy->interface == PHY_INTERFACE_MODE_RGMII) {
- + if (priv->port4_phy) {
- + /* value taken from Ubiquiti RouterStation Pro */
- + newval = 0x81461bea;
- + pr_info("ar8316: Using port 4 as PHY\n");
- + } else {
- + newval = 0x01261be2;
- + pr_info("ar8316: Using port 4 as switch port\n");
- + }
- + } else if (priv->phy->interface == PHY_INTERFACE_MODE_GMII) {
- + /* value taken from AVM Fritz!Box 7390 sources */
- + newval = 0x010e5b71;
- + } else {
- + /* no known value for phy interface */
- + pr_err("ar8316: unsupported mii mode: %d.\n",
- + priv->phy->interface);
- + return -EINVAL;
- + }
- +
- + if (val == newval)
- + goto out;
- +
- + ar8xxx_write(priv, AR8316_REG_POSTRIP, newval);
- +
- + if (priv->port4_phy &&
- + priv->phy->interface == PHY_INTERFACE_MODE_RGMII) {
- + /* work around for phy4 rgmii mode */
- + ar8xxx_phy_dbg_write(priv, 4, 0x12, 0x480c);
- + /* rx delay */
- + ar8xxx_phy_dbg_write(priv, 4, 0x0, 0x824e);
- + /* tx delay */
- + ar8xxx_phy_dbg_write(priv, 4, 0x5, 0x3d47);
- + msleep(1000);
- + }
- +
- + ar8xxx_phy_init(priv);
- +
- +out:
- + priv->initialized = true;
- + return 0;
- +}
- +
- +static void
- +ar8316_init_globals(struct ar8xxx_priv *priv)
- +{
- + /* standard atheros magic */
- + ar8xxx_write(priv, 0x38, 0xc000050e);
- +
- + /* enable cpu port to receive multicast and broadcast frames */
- + ar8xxx_write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f);
- +
- + /* enable jumbo frames */
- + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
- + AR8316_GCTRL_MTU, 9018 + 8 + 2);
- +
- + /* Enable MIB counters */
- + ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN,
- + (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) |
- + AR8236_MIB_EN);
- +}
- +
- +int
- +ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + priv->vlan = !!val->value.i;
- + return 0;
- +}
- +
- +int
- +ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + val->value.i = priv->vlan;
- + return 0;
- +}
- +
- +
- +int
- +ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- +
- + /* make sure no invalid PVIDs get set */
- +
- + if (vlan >= dev->vlans)
- + return -EINVAL;
- +
- + priv->pvid[port] = vlan;
- + return 0;
- +}
- +
- +int
- +ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + *vlan = priv->pvid[port];
- + return 0;
- +}
- +
- +static int
- +ar8xxx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + priv->vlan_id[val->port_vlan] = val->value.i;
- + return 0;
- +}
- +
- +static int
- +ar8xxx_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + val->value.i = priv->vlan_id[val->port_vlan];
- + return 0;
- +}
- +
- +int
- +ar8xxx_sw_get_port_link(struct switch_dev *dev, int port,
- + struct switch_port_link *link)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- +
- + ar8216_read_port_link(priv, port, link);
- + return 0;
- +}
- +
- +static int
- +ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + u8 ports = priv->vlan_table[val->port_vlan];
- + int i;
- +
- + val->len = 0;
- + for (i = 0; i < dev->ports; i++) {
- + struct switch_port *p;
- +
- + if (!(ports & (1 << i)))
- + continue;
- +
- + p = &val->value.ports[val->len++];
- + p->id = i;
- + if (priv->vlan_tagged & (1 << i))
- + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
- + else
- + p->flags = 0;
- + }
- + return 0;
- +}
- +
- +static int
- +ar8xxx_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + u8 *vt = &priv->vlan_table[val->port_vlan];
- + int i, j;
- +
- + *vt = 0;
- + for (i = 0; i < val->len; i++) {
- + struct switch_port *p = &val->value.ports[i];
- +
- + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
- + priv->vlan_tagged |= (1 << p->id);
- + } else {
- + priv->vlan_tagged &= ~(1 << p->id);
- + priv->pvid[p->id] = val->port_vlan;
- +
- + /* make sure that an untagged port does not
- + * appear in other vlans */
- + for (j = 0; j < AR8X16_MAX_VLANS; j++) {
- + if (j == val->port_vlan)
- + continue;
- + priv->vlan_table[j] &= ~(1 << p->id);
- + }
- + }
- +
- + *vt |= 1 << p->id;
- + }
- + return 0;
- +}
- +
- +static void
- +ar8216_set_mirror_regs(struct ar8xxx_priv *priv)
- +{
- + int port;
- +
- + /* reset all mirror registers */
- + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT,
- + AR8216_GLOBAL_CPUPORT_MIRROR_PORT,
- + (0xF << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
- + for (port = 0; port < AR8216_NUM_PORTS; port++) {
- + ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port),
- + AR8216_PORT_CTRL_MIRROR_RX);
- +
- + ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port),
- + AR8216_PORT_CTRL_MIRROR_TX);
- + }
- +
- + /* now enable mirroring if necessary */
- + if (priv->source_port >= AR8216_NUM_PORTS ||
- + priv->monitor_port >= AR8216_NUM_PORTS ||
- + priv->source_port == priv->monitor_port) {
- + return;
- + }
- +
- + ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT,
- + AR8216_GLOBAL_CPUPORT_MIRROR_PORT,
- + (priv->monitor_port << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
- +
- + if (priv->mirror_rx)
- + ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port),
- + AR8216_PORT_CTRL_MIRROR_RX);
- +
- + if (priv->mirror_tx)
- + ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port),
- + AR8216_PORT_CTRL_MIRROR_TX);
- +}
- +
- +int
- +ar8xxx_sw_hw_apply(struct switch_dev *dev)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + u8 portmask[AR8X16_MAX_PORTS];
- + int i, j;
- +
- + mutex_lock(&priv->reg_mutex);
- + /* flush all vlan translation unit entries */
- + priv->chip->vtu_flush(priv);
- +
- + memset(portmask, 0, sizeof(portmask));
- + if (!priv->init) {
- + /* calculate the port destination masks and load vlans
- + * into the vlan translation unit */
- + for (j = 0; j < AR8X16_MAX_VLANS; j++) {
- + u8 vp = priv->vlan_table[j];
- +
- + if (!vp)
- + continue;
- +
- + for (i = 0; i < dev->ports; i++) {
- + u8 mask = (1 << i);
- + if (vp & mask)
- + portmask[i] |= vp & ~mask;
- + }
- +
- + priv->chip->vtu_load_vlan(priv, priv->vlan_id[j],
- + priv->vlan_table[j]);
- + }
- + } else {
- + /* vlan disabled:
- + * isolate all ports, but connect them to the cpu port */
- + for (i = 0; i < dev->ports; i++) {
- + if (i == AR8216_PORT_CPU)
- + continue;
- +
- + portmask[i] = 1 << AR8216_PORT_CPU;
- + portmask[AR8216_PORT_CPU] |= (1 << i);
- + }
- + }
- +
- + /* update the port destination mask registers and tag settings */
- + for (i = 0; i < dev->ports; i++) {
- + priv->chip->setup_port(priv, i, portmask[i]);
- + }
- +
- + priv->chip->set_mirror_regs(priv);
- +
- + mutex_unlock(&priv->reg_mutex);
- + return 0;
- +}
- +
- +int
- +ar8xxx_sw_reset_switch(struct switch_dev *dev)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + const struct ar8xxx_chip *chip = priv->chip;
- + int i;
- +
- + mutex_lock(&priv->reg_mutex);
- + memset(&priv->vlan, 0, sizeof(struct ar8xxx_priv) -
- + offsetof(struct ar8xxx_priv, vlan));
- +
- + for (i = 0; i < AR8X16_MAX_VLANS; i++)
- + priv->vlan_id[i] = i;
- +
- + /* Configure all ports */
- + for (i = 0; i < dev->ports; i++)
- + chip->init_port(priv, i);
- +
- + priv->mirror_rx = false;
- + priv->mirror_tx = false;
- + priv->source_port = 0;
- + priv->monitor_port = 0;
- +
- + chip->init_globals(priv);
- +
- + mutex_unlock(&priv->reg_mutex);
- +
- + return chip->sw_hw_apply(dev);
- +}
- +
- +int
- +ar8xxx_sw_set_reset_mibs(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + unsigned int len;
- + int ret;
- +
- + if (!ar8xxx_has_mib_counters(priv))
- + return -EOPNOTSUPP;
- +
- + mutex_lock(&priv->mib_lock);
- +
- + len = priv->dev.ports * priv->chip->num_mibs *
- + sizeof(*priv->mib_stats);
- + memset(priv->mib_stats, '\0', len);
- + ret = ar8xxx_mib_flush(priv);
- + if (ret)
- + goto unlock;
- +
- + ret = 0;
- +
- +unlock:
- + mutex_unlock(&priv->mib_lock);
- + return ret;
- +}
- +
- +int
- +ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- +
- + mutex_lock(&priv->reg_mutex);
- + priv->mirror_rx = !!val->value.i;
- + priv->chip->set_mirror_regs(priv);
- + mutex_unlock(&priv->reg_mutex);
- +
- + return 0;
- +}
- +
- +int
- +ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + val->value.i = priv->mirror_rx;
- + return 0;
- +}
- +
- +int
- +ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- +
- + mutex_lock(&priv->reg_mutex);
- + priv->mirror_tx = !!val->value.i;
- + priv->chip->set_mirror_regs(priv);
- + mutex_unlock(&priv->reg_mutex);
- +
- + return 0;
- +}
- +
- +int
- +ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + val->value.i = priv->mirror_tx;
- + return 0;
- +}
- +
- +int
- +ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- +
- + mutex_lock(&priv->reg_mutex);
- + priv->monitor_port = val->value.i;
- + priv->chip->set_mirror_regs(priv);
- + mutex_unlock(&priv->reg_mutex);
- +
- + return 0;
- +}
- +
- +int
- +ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + val->value.i = priv->monitor_port;
- + return 0;
- +}
- +
- +int
- +ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- +
- + mutex_lock(&priv->reg_mutex);
- + priv->source_port = val->value.i;
- + priv->chip->set_mirror_regs(priv);
- + mutex_unlock(&priv->reg_mutex);
- +
- + return 0;
- +}
- +
- +int
- +ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + val->value.i = priv->source_port;
- + return 0;
- +}
- +
- +int
- +ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + int port;
- + int ret;
- +
- + if (!ar8xxx_has_mib_counters(priv))
- + return -EOPNOTSUPP;
- +
- + port = val->port_vlan;
- + if (port >= dev->ports)
- + return -EINVAL;
- +
- + mutex_lock(&priv->mib_lock);
- + ret = ar8xxx_mib_capture(priv);
- + if (ret)
- + goto unlock;
- +
- + ar8xxx_mib_fetch_port_stat(priv, port, true);
- +
- + ret = 0;
- +
- +unlock:
- + mutex_unlock(&priv->mib_lock);
- + return ret;
- +}
- +
- +int
- +ar8xxx_sw_get_port_mib(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + const struct ar8xxx_chip *chip = priv->chip;
- + u64 *mib_stats;
- + int port;
- + int ret;
- + char *buf = priv->buf;
- + int i, len = 0;
- +
- + if (!ar8xxx_has_mib_counters(priv))
- + return -EOPNOTSUPP;
- +
- + port = val->port_vlan;
- + if (port >= dev->ports)
- + return -EINVAL;
- +
- + mutex_lock(&priv->mib_lock);
- + ret = ar8xxx_mib_capture(priv);
- + if (ret)
- + goto unlock;
- +
- + ar8xxx_mib_fetch_port_stat(priv, port, false);
- +
- + len += snprintf(buf + len, sizeof(priv->buf) - len,
- + "Port %d MIB counters\n",
- + port);
- +
- + mib_stats = &priv->mib_stats[port * chip->num_mibs];
- + for (i = 0; i < chip->num_mibs; i++)
- + len += snprintf(buf + len, sizeof(priv->buf) - len,
- + "%-12s: %llu\n",
- + chip->mib_decs[i].name,
- + mib_stats[i]);
- +
- + val->value.s = buf;
- + val->len = len;
- +
- + ret = 0;
- +
- +unlock:
- + mutex_unlock(&priv->mib_lock);
- + return ret;
- +}
- +
- +int
- +ar8xxx_sw_get_arl_table(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + struct mii_bus *bus = priv->mii_bus;
- + const struct ar8xxx_chip *chip = priv->chip;
- + char *buf = priv->arl_buf;
- + int i, j, k, len = 0;
- + struct arl_entry *a, *a1;
- + u32 status;
- +
- + if (!chip->get_arl_entry)
- + return -EOPNOTSUPP;
- +
- + mutex_lock(&priv->reg_mutex);
- + mutex_lock(&bus->mdio_lock);
- +
- + chip->get_arl_entry(priv, NULL, NULL, AR8XXX_ARL_INITIALIZE);
- +
- + for(i = 0; i < AR8XXX_NUM_ARL_RECORDS; ++i) {
- + a = &priv->arl_table[i];
- + duplicate:
- + chip->get_arl_entry(priv, a, &status, AR8XXX_ARL_GET_NEXT);
- +
- + if (!status)
- + break;
- +
- + /* avoid duplicates
- + * ARL table can include multiple valid entries
- + * per MAC, just with differing status codes
- + */
- + for (j = 0; j < i; ++j) {
- + a1 = &priv->arl_table[j];
- + if (a->port == a1->port && !memcmp(a->mac, a1->mac, sizeof(a->mac)))
- + goto duplicate;
- + }
- + }
- +
- + mutex_unlock(&bus->mdio_lock);
- +
- + len += snprintf(buf + len, sizeof(priv->arl_buf) - len,
- + "address resolution table\n");
- +
- + if (i == AR8XXX_NUM_ARL_RECORDS)
- + len += snprintf(buf + len, sizeof(priv->arl_buf) - len,
- + "Too many entries found, displaying the first %d only!\n",
- + AR8XXX_NUM_ARL_RECORDS);
- +
- + for (j = 0; j < priv->dev.ports; ++j) {
- + for (k = 0; k < i; ++k) {
- + a = &priv->arl_table[k];
- + if (a->port != j)
- + continue;
- + len += snprintf(buf + len, sizeof(priv->arl_buf) - len,
- + "Port %d: MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
- + j,
- + a->mac[5], a->mac[4], a->mac[3],
- + a->mac[2], a->mac[1], a->mac[0]);
- + }
- + }
- +
- + val->value.s = buf;
- + val->len = len;
- +
- + mutex_unlock(&priv->reg_mutex);
- +
- + return 0;
- +}
- +
- +int
- +ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + int ret;
- +
- + mutex_lock(&priv->reg_mutex);
- + ret = priv->chip->atu_flush(priv);
- + mutex_unlock(&priv->reg_mutex);
- +
- + return ret;
- +}
- +
- +int
- +ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + int port, ret;
- +
- + port = val->port_vlan;
- + if (port >= dev->ports)
- + return -EINVAL;
- +
- + mutex_lock(&priv->reg_mutex);
- + ret = priv->chip->atu_flush_port(priv, port);
- + mutex_unlock(&priv->reg_mutex);
- +
- + return ret;
- +}
- +
- +static const struct switch_attr ar8xxx_sw_attr_globals[] = {
- + {
- + .type = SWITCH_TYPE_INT,
- + .name = "enable_vlan",
- + .description = "Enable VLAN mode",
- + .set = ar8xxx_sw_set_vlan,
- + .get = ar8xxx_sw_get_vlan,
- + .max = 1
- + },
- + {
- + .type = SWITCH_TYPE_NOVAL,
- + .name = "reset_mibs",
- + .description = "Reset all MIB counters",
- + .set = ar8xxx_sw_set_reset_mibs,
- + },
- + {
- + .type = SWITCH_TYPE_INT,
- + .name = "enable_mirror_rx",
- + .description = "Enable mirroring of RX packets",
- + .set = ar8xxx_sw_set_mirror_rx_enable,
- + .get = ar8xxx_sw_get_mirror_rx_enable,
- + .max = 1
- + },
- + {
- + .type = SWITCH_TYPE_INT,
- + .name = "enable_mirror_tx",
- + .description = "Enable mirroring of TX packets",
- + .set = ar8xxx_sw_set_mirror_tx_enable,
- + .get = ar8xxx_sw_get_mirror_tx_enable,
- + .max = 1
- + },
- + {
- + .type = SWITCH_TYPE_INT,
- + .name = "mirror_monitor_port",
- + .description = "Mirror monitor port",
- + .set = ar8xxx_sw_set_mirror_monitor_port,
- + .get = ar8xxx_sw_get_mirror_monitor_port,
- + .max = AR8216_NUM_PORTS - 1
- + },
- + {
- + .type = SWITCH_TYPE_INT,
- + .name = "mirror_source_port",
- + .description = "Mirror source port",
- + .set = ar8xxx_sw_set_mirror_source_port,
- + .get = ar8xxx_sw_get_mirror_source_port,
- + .max = AR8216_NUM_PORTS - 1
- + },
- + {
- + .type = SWITCH_TYPE_STRING,
- + .name = "arl_table",
- + .description = "Get ARL table",
- + .set = NULL,
- + .get = ar8xxx_sw_get_arl_table,
- + },
- + {
- + .type = SWITCH_TYPE_NOVAL,
- + .name = "flush_arl_table",
- + .description = "Flush ARL table",
- + .set = ar8xxx_sw_set_flush_arl_table,
- + },
- +};
- +
- +const struct switch_attr ar8xxx_sw_attr_port[] = {
- + {
- + .type = SWITCH_TYPE_NOVAL,
- + .name = "reset_mib",
- + .description = "Reset single port MIB counters",
- + .set = ar8xxx_sw_set_port_reset_mib,
- + },
- + {
- + .type = SWITCH_TYPE_STRING,
- + .name = "mib",
- + .description = "Get port's MIB counters",
- + .set = NULL,
- + .get = ar8xxx_sw_get_port_mib,
- + },
- + {
- + .type = SWITCH_TYPE_NOVAL,
- + .name = "flush_arl_table",
- + .description = "Flush port's ARL table entries",
- + .set = ar8xxx_sw_set_flush_port_arl_table,
- + },
- +};
- +
- +const struct switch_attr ar8xxx_sw_attr_vlan[1] = {
- + {
- + .type = SWITCH_TYPE_INT,
- + .name = "vid",
- + .description = "VLAN ID (0-4094)",
- + .set = ar8xxx_sw_set_vid,
- + .get = ar8xxx_sw_get_vid,
- + .max = 4094,
- + },
- +};
- +
- +static const struct switch_dev_ops ar8xxx_sw_ops = {
- + .attr_global = {
- + .attr = ar8xxx_sw_attr_globals,
- + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_globals),
- + },
- + .attr_port = {
- + .attr = ar8xxx_sw_attr_port,
- + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port),
- + },
- + .attr_vlan = {
- + .attr = ar8xxx_sw_attr_vlan,
- + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan),
- + },
- + .get_port_pvid = ar8xxx_sw_get_pvid,
- + .set_port_pvid = ar8xxx_sw_set_pvid,
- + .get_vlan_ports = ar8xxx_sw_get_ports,
- + .set_vlan_ports = ar8xxx_sw_set_ports,
- + .apply_config = ar8xxx_sw_hw_apply,
- + .reset_switch = ar8xxx_sw_reset_switch,
- + .get_port_link = ar8xxx_sw_get_port_link,
- +};
- +
- +static const struct ar8xxx_chip ar8216_chip = {
- + .caps = AR8XXX_CAP_MIB_COUNTERS,
- +
- + .reg_port_stats_start = 0x19000,
- + .reg_port_stats_length = 0xa0,
- +
- + .name = "Atheros AR8216",
- + .ports = AR8216_NUM_PORTS,
- + .vlans = AR8216_NUM_VLANS,
- + .swops = &ar8xxx_sw_ops,
- +
- + .hw_init = ar8216_hw_init,
- + .init_globals = ar8216_init_globals,
- + .init_port = ar8216_init_port,
- + .setup_port = ar8216_setup_port,
- + .read_port_status = ar8216_read_port_status,
- + .atu_flush = ar8216_atu_flush,
- + .atu_flush_port = ar8216_atu_flush_port,
- + .vtu_flush = ar8216_vtu_flush,
- + .vtu_load_vlan = ar8216_vtu_load_vlan,
- + .set_mirror_regs = ar8216_set_mirror_regs,
- + .get_arl_entry = ar8216_get_arl_entry,
- + .sw_hw_apply = ar8xxx_sw_hw_apply,
- +
- + .num_mibs = ARRAY_SIZE(ar8216_mibs),
- + .mib_decs = ar8216_mibs,
- + .mib_func = AR8216_REG_MIB_FUNC
- +};
- +
- +static const struct ar8xxx_chip ar8236_chip = {
- + .caps = AR8XXX_CAP_MIB_COUNTERS,
- +
- + .reg_port_stats_start = 0x20000,
- + .reg_port_stats_length = 0x100,
- +
- + .name = "Atheros AR8236",
- + .ports = AR8216_NUM_PORTS,
- + .vlans = AR8216_NUM_VLANS,
- + .swops = &ar8xxx_sw_ops,
- +
- + .hw_init = ar8216_hw_init,
- + .init_globals = ar8236_init_globals,
- + .init_port = ar8216_init_port,
- + .setup_port = ar8236_setup_port,
- + .read_port_status = ar8216_read_port_status,
- + .atu_flush = ar8216_atu_flush,
- + .atu_flush_port = ar8216_atu_flush_port,
- + .vtu_flush = ar8216_vtu_flush,
- + .vtu_load_vlan = ar8216_vtu_load_vlan,
- + .set_mirror_regs = ar8216_set_mirror_regs,
- + .get_arl_entry = ar8216_get_arl_entry,
- + .sw_hw_apply = ar8xxx_sw_hw_apply,
- +
- + .num_mibs = ARRAY_SIZE(ar8236_mibs),
- + .mib_decs = ar8236_mibs,
- + .mib_func = AR8216_REG_MIB_FUNC
- +};
- +
- +static const struct ar8xxx_chip ar8316_chip = {
- + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS,
- +
- + .reg_port_stats_start = 0x20000,
- + .reg_port_stats_length = 0x100,
- +
- + .name = "Atheros AR8316",
- + .ports = AR8216_NUM_PORTS,
- + .vlans = AR8X16_MAX_VLANS,
- + .swops = &ar8xxx_sw_ops,
- +
- + .hw_init = ar8316_hw_init,
- + .init_globals = ar8316_init_globals,
- + .init_port = ar8216_init_port,
- + .setup_port = ar8216_setup_port,
- + .read_port_status = ar8216_read_port_status,
- + .atu_flush = ar8216_atu_flush,
- + .atu_flush_port = ar8216_atu_flush_port,
- + .vtu_flush = ar8216_vtu_flush,
- + .vtu_load_vlan = ar8216_vtu_load_vlan,
- + .set_mirror_regs = ar8216_set_mirror_regs,
- + .get_arl_entry = ar8216_get_arl_entry,
- + .sw_hw_apply = ar8xxx_sw_hw_apply,
- +
- + .num_mibs = ARRAY_SIZE(ar8236_mibs),
- + .mib_decs = ar8236_mibs,
- + .mib_func = AR8216_REG_MIB_FUNC
- +};
- +
- +static int
- +ar8xxx_id_chip(struct ar8xxx_priv *priv)
- +{
- + u32 val;
- + u16 id;
- + int i;
- +
- + val = ar8xxx_read(priv, AR8216_REG_CTRL);
- + if (val == ~0)
- + return -ENODEV;
- +
- + id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION);
- + for (i = 0; i < AR8X16_PROBE_RETRIES; i++) {
- + u16 t;
- +
- + val = ar8xxx_read(priv, AR8216_REG_CTRL);
- + if (val == ~0)
- + return -ENODEV;
- +
- + t = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION);
- + if (t != id)
- + return -ENODEV;
- + }
- +
- + priv->chip_ver = (id & AR8216_CTRL_VERSION) >> AR8216_CTRL_VERSION_S;
- + priv->chip_rev = (id & AR8216_CTRL_REVISION);
- +
- + switch (priv->chip_ver) {
- + case AR8XXX_VER_AR8216:
- + priv->chip = &ar8216_chip;
- + break;
- + case AR8XXX_VER_AR8236:
- + priv->chip = &ar8236_chip;
- + break;
- + case AR8XXX_VER_AR8316:
- + priv->chip = &ar8316_chip;
- + break;
- + case AR8XXX_VER_AR8327:
- + priv->chip = &ar8327_chip;
- + break;
- + case AR8XXX_VER_AR8337:
- + priv->chip = &ar8337_chip;
- + break;
- + default:
- + pr_err("ar8216: Unknown Atheros device [ver=%d, rev=%d]\n",
- + priv->chip_ver, priv->chip_rev);
- +
- + return -ENODEV;
- + }
- +
- + return 0;
- +}
- +
- +static void
- +ar8xxx_mib_work_func(struct work_struct *work)
- +{
- + struct ar8xxx_priv *priv;
- + int err;
- +
- + priv = container_of(work, struct ar8xxx_priv, mib_work.work);
- +
- + mutex_lock(&priv->mib_lock);
- +
- + err = ar8xxx_mib_capture(priv);
- + if (err)
- + goto next_port;
- +
- + ar8xxx_mib_fetch_port_stat(priv, priv->mib_next_port, false);
- +
- +next_port:
- + priv->mib_next_port++;
- + if (priv->mib_next_port >= priv->dev.ports)
- + priv->mib_next_port = 0;
- +
- + mutex_unlock(&priv->mib_lock);
- + schedule_delayed_work(&priv->mib_work,
- + msecs_to_jiffies(AR8XXX_MIB_WORK_DELAY));
- +}
- +
- +static int
- +ar8xxx_mib_init(struct ar8xxx_priv *priv)
- +{
- + unsigned int len;
- +
- + if (!ar8xxx_has_mib_counters(priv))
- + return 0;
- +
- + BUG_ON(!priv->chip->mib_decs || !priv->chip->num_mibs);
- +
- + len = priv->dev.ports * priv->chip->num_mibs *
- + sizeof(*priv->mib_stats);
- + priv->mib_stats = kzalloc(len, GFP_KERNEL);
- +
- + if (!priv->mib_stats)
- + return -ENOMEM;
- +
- + return 0;
- +}
- +
- +static void
- +ar8xxx_mib_start(struct ar8xxx_priv *priv)
- +{
- + if (!ar8xxx_has_mib_counters(priv))
- + return;
- +
- + schedule_delayed_work(&priv->mib_work,
- + msecs_to_jiffies(AR8XXX_MIB_WORK_DELAY));
- +}
- +
- +static void
- +ar8xxx_mib_stop(struct ar8xxx_priv *priv)
- +{
- + if (!ar8xxx_has_mib_counters(priv))
- + return;
- +
- + cancel_delayed_work(&priv->mib_work);
- +}
- +
- +static struct ar8xxx_priv *
- +ar8xxx_create(void)
- +{
- + struct ar8xxx_priv *priv;
- +
- + priv = kzalloc(sizeof(struct ar8xxx_priv), GFP_KERNEL);
- + if (priv == NULL)
- + return NULL;
- +
- + mutex_init(&priv->reg_mutex);
- + mutex_init(&priv->mib_lock);
- + INIT_DELAYED_WORK(&priv->mib_work, ar8xxx_mib_work_func);
- +
- + return priv;
- +}
- +
- +static void
- +ar8xxx_free(struct ar8xxx_priv *priv)
- +{
- + if (priv->chip && priv->chip->cleanup)
- + priv->chip->cleanup(priv);
- +
- + kfree(priv->chip_data);
- + kfree(priv->mib_stats);
- + kfree(priv);
- +}
- +
- +static int
- +ar8xxx_probe_switch(struct ar8xxx_priv *priv)
- +{
- + const struct ar8xxx_chip *chip;
- + struct switch_dev *swdev;
- + int ret;
- +
- + ret = ar8xxx_id_chip(priv);
- + if (ret)
- + return ret;
- +
- + chip = priv->chip;
- +
- + swdev = &priv->dev;
- + swdev->cpu_port = AR8216_PORT_CPU;
- + swdev->name = chip->name;
- + swdev->vlans = chip->vlans;
- + swdev->ports = chip->ports;
- + swdev->ops = chip->swops;
- +
- + ret = ar8xxx_mib_init(priv);
- + if (ret)
- + return ret;
- +
- + return 0;
- +}
- +
- +static int
- +ar8xxx_start(struct ar8xxx_priv *priv)
- +{
- + int ret;
- +
- + priv->init = true;
- +
- + ret = priv->chip->hw_init(priv);
- + if (ret)
- + return ret;
- +
- + ret = ar8xxx_sw_reset_switch(&priv->dev);
- + if (ret)
- + return ret;
- +
- + priv->init = false;
- +
- + ar8xxx_mib_start(priv);
- +
- + return 0;
- +}
- +
- +static int
- +ar8xxx_phy_config_init(struct phy_device *phydev)
- +{
- + struct ar8xxx_priv *priv = phydev->priv;
- + struct net_device *dev = phydev->attached_dev;
- + int ret;
- +
- + if (WARN_ON(!priv))
- + return -ENODEV;
- +
- + if (priv->chip->config_at_probe)
- + return ar8xxx_phy_check_aneg(phydev);
- +
- + priv->phy = phydev;
- +
- + if (phydev->addr != 0) {
- + if (chip_is_ar8316(priv)) {
- + /* switch device has been initialized, reinit */
- + priv->dev.ports = (AR8216_NUM_PORTS - 1);
- + priv->initialized = false;
- + priv->port4_phy = true;
- + ar8316_hw_init(priv);
- + return 0;
- + }
- +
- + return 0;
- + }
- +
- + ret = ar8xxx_start(priv);
- + if (ret)
- + return ret;
- +
- + /* VID fixup only needed on ar8216 */
- + if (chip_is_ar8216(priv)) {
- + dev->phy_ptr = priv;
- + dev->priv_flags |= IFF_NO_IP_ALIGN;
- + dev->eth_mangle_rx = ar8216_mangle_rx;
- + dev->eth_mangle_tx = ar8216_mangle_tx;
- + }
- +
- + return 0;
- +}
- +
- +static bool
- +ar8xxx_check_link_states(struct ar8xxx_priv *priv)
- +{
- + bool link_new, changed = false;
- + u32 status;
- + int i;
- +
- + mutex_lock(&priv->reg_mutex);
- +
- + for (i = 0; i < priv->dev.ports; i++) {
- + status = priv->chip->read_port_status(priv, i);
- + link_new = !!(status & AR8216_PORT_STATUS_LINK_UP);
- + if (link_new == priv->link_up[i])
- + continue;
- +
- + priv->link_up[i] = link_new;
- + changed = true;
- + /* flush ARL entries for this port if it went down*/
- + if (!link_new)
- + priv->chip->atu_flush_port(priv, i);
- + dev_info(&priv->phy->dev, "Port %d is %s\n",
- + i, link_new ? "up" : "down");
- + }
- +
- + mutex_unlock(&priv->reg_mutex);
- +
- + return changed;
- +}
- +
- +static int
- +ar8xxx_phy_read_status(struct phy_device *phydev)
- +{
- + struct ar8xxx_priv *priv = phydev->priv;
- + struct switch_port_link link;
- +
- + /* check for switch port link changes */
- + if (phydev->state == PHY_CHANGELINK)
- + ar8xxx_check_link_states(priv);
- +
- + if (phydev->addr != 0)
- + return genphy_read_status(phydev);
- +
- + ar8216_read_port_link(priv, phydev->addr, &link);
- + phydev->link = !!link.link;
- + if (!phydev->link)
- + return 0;
- +
- + switch (link.speed) {
- + case SWITCH_PORT_SPEED_10:
- + phydev->speed = SPEED_10;
- + break;
- + case SWITCH_PORT_SPEED_100:
- + phydev->speed = SPEED_100;
- + break;
- + case SWITCH_PORT_SPEED_1000:
- + phydev->speed = SPEED_1000;
- + break;
- + default:
- + phydev->speed = 0;
- + }
- + phydev->duplex = link.duplex ? DUPLEX_FULL : DUPLEX_HALF;
- +
- + phydev->state = PHY_RUNNING;
- + netif_carrier_on(phydev->attached_dev);
- + phydev->adjust_link(phydev->attached_dev);
- +
- + return 0;
- +}
- +
- +static int
- +ar8xxx_phy_config_aneg(struct phy_device *phydev)
- +{
- + if (phydev->addr == 0)
- + return 0;
- +
- + return genphy_config_aneg(phydev);
- +}
- +
- +static const u32 ar8xxx_phy_ids[] = {
- + 0x004dd033,
- + 0x004dd034, /* AR8327 */
- + 0x004dd036, /* AR8337 */
- + 0x004dd041,
- + 0x004dd042,
- + 0x004dd043, /* AR8236 */
- +};
- +
- +static bool
- +ar8xxx_phy_match(u32 phy_id)
- +{
- + int i;
- +
- + for (i = 0; i < ARRAY_SIZE(ar8xxx_phy_ids); i++)
- + if (phy_id == ar8xxx_phy_ids[i])
- + return true;
- +
- + return false;
- +}
- +
- +static bool
- +ar8xxx_is_possible(struct mii_bus *bus)
- +{
- + unsigned i;
- +
- + for (i = 0; i < 4; i++) {
- + u32 phy_id;
- +
- + phy_id = mdiobus_read(bus, i, MII_PHYSID1) << 16;
- + phy_id |= mdiobus_read(bus, i, MII_PHYSID2);
- + if (!ar8xxx_phy_match(phy_id)) {
- + pr_debug("ar8xxx: unknown PHY at %s:%02x id:%08x\n",
- + dev_name(&bus->dev), i, phy_id);
- + return false;
- + }
- + }
- +
- + return true;
- +}
- +
- +static int
- +ar8xxx_phy_probe(struct phy_device *phydev)
- +{
- + struct ar8xxx_priv *priv;
- + struct switch_dev *swdev;
- + int ret;
- +
- + /* skip PHYs at unused adresses */
- + if (phydev->addr != 0 && phydev->addr != 4)
- + return -ENODEV;
- +
- + if (!ar8xxx_is_possible(phydev->bus))
- + return -ENODEV;
- +
- + mutex_lock(&ar8xxx_dev_list_lock);
- + list_for_each_entry(priv, &ar8xxx_dev_list, list)
- + if (priv->mii_bus == phydev->bus)
- + goto found;
- +
- + priv = ar8xxx_create();
- + if (priv == NULL) {
- + ret = -ENOMEM;
- + goto unlock;
- + }
- +
- + priv->mii_bus = phydev->bus;
- +
- + ret = ar8xxx_probe_switch(priv);
- + if (ret)
- + goto free_priv;
- +
- + swdev = &priv->dev;
- + swdev->alias = dev_name(&priv->mii_bus->dev);
- + ret = register_switch(swdev, NULL);
- + if (ret)
- + goto free_priv;
- +
- + pr_info("%s: %s rev. %u switch registered on %s\n",
- + swdev->devname, swdev->name, priv->chip_rev,
- + dev_name(&priv->mii_bus->dev));
- +
- +found:
- + priv->use_count++;
- +
- + if (phydev->addr == 0) {
- + if (ar8xxx_has_gige(priv)) {
- + phydev->supported = SUPPORTED_1000baseT_Full;
- + phydev->advertising = ADVERTISED_1000baseT_Full;
- + } else {
- + phydev->supported = SUPPORTED_100baseT_Full;
- + phydev->advertising = ADVERTISED_100baseT_Full;
- + }
- +
- + if (priv->chip->config_at_probe) {
- + priv->phy = phydev;
- +
- + ret = ar8xxx_start(priv);
- + if (ret)
- + goto err_unregister_switch;
- + }
- + } else {
- + if (ar8xxx_has_gige(priv)) {
- + phydev->supported |= SUPPORTED_1000baseT_Full;
- + phydev->advertising |= ADVERTISED_1000baseT_Full;
- + }
- + }
- +
- + phydev->priv = priv;
- +
- + list_add(&priv->list, &ar8xxx_dev_list);
- +
- + mutex_unlock(&ar8xxx_dev_list_lock);
- +
- + return 0;
- +
- +err_unregister_switch:
- + if (--priv->use_count)
- + goto unlock;
- +
- + unregister_switch(&priv->dev);
- +
- +free_priv:
- + ar8xxx_free(priv);
- +unlock:
- + mutex_unlock(&ar8xxx_dev_list_lock);
- + return ret;
- +}
- +
- +static void
- +ar8xxx_phy_remove(struct phy_device *phydev)
- +{
- + struct ar8xxx_priv *priv = phydev->priv;
- +
- + if (WARN_ON(!priv))
- + return;
- +
- + phydev->priv = NULL;
- + if (--priv->use_count > 0)
- + return;
- +
- + mutex_lock(&ar8xxx_dev_list_lock);
- + list_del(&priv->list);
- + mutex_unlock(&ar8xxx_dev_list_lock);
- +
- + unregister_switch(&priv->dev);
- + ar8xxx_mib_stop(priv);
- + ar8xxx_free(priv);
- +}
- +
- +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
- +static int
- +ar8xxx_phy_soft_reset(struct phy_device *phydev)
- +{
- + /* we don't need an extra reset */
- + return 0;
- +}
- +#endif
- +
- +static struct phy_driver ar8xxx_phy_driver = {
- + .phy_id = 0x004d0000,
- + .name = "Atheros AR8216/AR8236/AR8316",
- + .phy_id_mask = 0xffff0000,
- + .features = PHY_BASIC_FEATURES,
- + .probe = ar8xxx_phy_probe,
- + .remove = ar8xxx_phy_remove,
- + .config_init = ar8xxx_phy_config_init,
- + .config_aneg = ar8xxx_phy_config_aneg,
- + .read_status = ar8xxx_phy_read_status,
- +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)
- + .soft_reset = ar8xxx_phy_soft_reset,
- +#endif
- + .driver = { .owner = THIS_MODULE },
- +};
- +
- +int __init
- +ar8xxx_init(void)
- +{
- + return phy_driver_register(&ar8xxx_phy_driver);
- +}
- +
- +void __exit
- +ar8xxx_exit(void)
- +{
- + phy_driver_unregister(&ar8xxx_phy_driver);
- +}
- +
- +module_init(ar8xxx_init);
- +module_exit(ar8xxx_exit);
- +MODULE_LICENSE("GPL");
- +
- diff -Nur linux-4.1.6.orig/drivers/net/phy/ar8216.h linux-4.1.6/drivers/net/phy/ar8216.h
- --- linux-4.1.6.orig/drivers/net/phy/ar8216.h 1970-01-01 01:00:00.000000000 +0100
- +++ linux-4.1.6/drivers/net/phy/ar8216.h 2015-09-13 22:55:18.327374229 +0200
- @@ -0,0 +1,628 @@
- +/*
- + * ar8216.h: AR8216 switch driver
- + *
- + * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
- + *
- + * 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 2
- + * of the License, or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + */
- +
- +#ifndef __AR8216_H
- +#define __AR8216_H
- +
- +#define BITS(_s, _n) (((1UL << (_n)) - 1) << _s)
- +
- +#define AR8XXX_CAP_GIGE BIT(0)
- +#define AR8XXX_CAP_MIB_COUNTERS BIT(1)
- +
- +#define AR8XXX_NUM_PHYS 5
- +#define AR8216_PORT_CPU 0
- +#define AR8216_NUM_PORTS 6
- +#define AR8216_NUM_VLANS 16
- +#define AR8316_NUM_VLANS 4096
- +
- +/* size of the vlan table */
- +#define AR8X16_MAX_VLANS 128
- +#define AR8X16_PROBE_RETRIES 10
- +#define AR8X16_MAX_PORTS 8
- +
- +/* Atheros specific MII registers */
- +#define MII_ATH_MMD_ADDR 0x0d
- +#define MII_ATH_MMD_DATA 0x0e
- +#define MII_ATH_DBG_ADDR 0x1d
- +#define MII_ATH_DBG_DATA 0x1e
- +
- +#define AR8216_REG_CTRL 0x0000
- +#define AR8216_CTRL_REVISION BITS(0, 8)
- +#define AR8216_CTRL_REVISION_S 0
- +#define AR8216_CTRL_VERSION BITS(8, 8)
- +#define AR8216_CTRL_VERSION_S 8
- +#define AR8216_CTRL_RESET BIT(31)
- +
- +#define AR8216_REG_FLOOD_MASK 0x002C
- +#define AR8216_FM_UNI_DEST_PORTS BITS(0, 6)
- +#define AR8216_FM_MULTI_DEST_PORTS BITS(16, 6)
- +#define AR8236_FM_CPU_BROADCAST_EN BIT(26)
- +#define AR8236_FM_CPU_BCAST_FWD_EN BIT(25)
- +
- +#define AR8216_REG_GLOBAL_CTRL 0x0030
- +#define AR8216_GCTRL_MTU BITS(0, 11)
- +#define AR8236_GCTRL_MTU BITS(0, 14)
- +#define AR8316_GCTRL_MTU BITS(0, 14)
- +
- +#define AR8216_REG_VTU 0x0040
- +#define AR8216_VTU_OP BITS(0, 3)
- +#define AR8216_VTU_OP_NOOP 0x0
- +#define AR8216_VTU_OP_FLUSH 0x1
- +#define AR8216_VTU_OP_LOAD 0x2
- +#define AR8216_VTU_OP_PURGE 0x3
- +#define AR8216_VTU_OP_REMOVE_PORT 0x4
- +#define AR8216_VTU_ACTIVE BIT(3)
- +#define AR8216_VTU_FULL BIT(4)
- +#define AR8216_VTU_PORT BITS(8, 4)
- +#define AR8216_VTU_PORT_S 8
- +#define AR8216_VTU_VID BITS(16, 12)
- +#define AR8216_VTU_VID_S 16
- +#define AR8216_VTU_PRIO BITS(28, 3)
- +#define AR8216_VTU_PRIO_S 28
- +#define AR8216_VTU_PRIO_EN BIT(31)
- +
- +#define AR8216_REG_VTU_DATA 0x0044
- +#define AR8216_VTUDATA_MEMBER BITS(0, 10)
- +#define AR8236_VTUDATA_MEMBER BITS(0, 7)
- +#define AR8216_VTUDATA_VALID BIT(11)
- +
- +#define AR8216_REG_ATU_FUNC0 0x0050
- +#define AR8216_ATU_OP BITS(0, 3)
- +#define AR8216_ATU_OP_NOOP 0x0
- +#define AR8216_ATU_OP_FLUSH 0x1
- +#define AR8216_ATU_OP_LOAD 0x2
- +#define AR8216_ATU_OP_PURGE 0x3
- +#define AR8216_ATU_OP_FLUSH_UNLOCKED 0x4
- +#define AR8216_ATU_OP_FLUSH_PORT 0x5
- +#define AR8216_ATU_OP_GET_NEXT 0x6
- +#define AR8216_ATU_ACTIVE BIT(3)
- +#define AR8216_ATU_PORT_NUM BITS(8, 4)
- +#define AR8216_ATU_PORT_NUM_S 8
- +#define AR8216_ATU_FULL_VIO BIT(12)
- +#define AR8216_ATU_ADDR5 BITS(16, 8)
- +#define AR8216_ATU_ADDR5_S 16
- +#define AR8216_ATU_ADDR4 BITS(24, 8)
- +#define AR8216_ATU_ADDR4_S 24
- +
- +#define AR8216_REG_ATU_FUNC1 0x0054
- +#define AR8216_ATU_ADDR3 BITS(0, 8)
- +#define AR8216_ATU_ADDR3_S 0
- +#define AR8216_ATU_ADDR2 BITS(8, 8)
- +#define AR8216_ATU_ADDR2_S 8
- +#define AR8216_ATU_ADDR1 BITS(16, 8)
- +#define AR8216_ATU_ADDR1_S 16
- +#define AR8216_ATU_ADDR0 BITS(24, 8)
- +#define AR8216_ATU_ADDR0_S 24
- +
- +#define AR8216_REG_ATU_FUNC2 0x0058
- +#define AR8216_ATU_PORTS BITS(0, 6)
- +#define AR8216_ATU_PORT0 BIT(0)
- +#define AR8216_ATU_PORT1 BIT(1)
- +#define AR8216_ATU_PORT2 BIT(2)
- +#define AR8216_ATU_PORT3 BIT(3)
- +#define AR8216_ATU_PORT4 BIT(4)
- +#define AR8216_ATU_PORT5 BIT(5)
- +#define AR8216_ATU_STATUS BITS(16, 4)
- +#define AR8216_ATU_STATUS_S 16
- +
- +#define AR8216_REG_ATU_CTRL 0x005C
- +#define AR8216_ATU_CTRL_AGE_EN BIT(17)
- +#define AR8216_ATU_CTRL_AGE_TIME BITS(0, 16)
- +#define AR8216_ATU_CTRL_AGE_TIME_S 0
- +#define AR8236_ATU_CTRL_RES BIT(20)
- +
- +#define AR8216_REG_MIB_FUNC 0x0080
- +#define AR8216_MIB_TIMER BITS(0, 16)
- +#define AR8216_MIB_AT_HALF_EN BIT(16)
- +#define AR8216_MIB_BUSY BIT(17)
- +#define AR8216_MIB_FUNC BITS(24, 3)
- +#define AR8216_MIB_FUNC_S 24
- +#define AR8216_MIB_FUNC_NO_OP 0x0
- +#define AR8216_MIB_FUNC_FLUSH 0x1
- +#define AR8216_MIB_FUNC_CAPTURE 0x3
- +#define AR8236_MIB_EN BIT(30)
- +
- +#define AR8216_REG_GLOBAL_CPUPORT 0x0078
- +#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT BITS(4, 4)
- +#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S 4
- +
- +#define AR8216_PORT_OFFSET(_i) (0x0100 * (_i + 1))
- +#define AR8216_REG_PORT_STATUS(_i) (AR8216_PORT_OFFSET(_i) + 0x0000)
- +#define AR8216_PORT_STATUS_SPEED BITS(0,2)
- +#define AR8216_PORT_STATUS_SPEED_S 0
- +#define AR8216_PORT_STATUS_TXMAC BIT(2)
- +#define AR8216_PORT_STATUS_RXMAC BIT(3)
- +#define AR8216_PORT_STATUS_TXFLOW BIT(4)
- +#define AR8216_PORT_STATUS_RXFLOW BIT(5)
- +#define AR8216_PORT_STATUS_DUPLEX BIT(6)
- +#define AR8216_PORT_STATUS_LINK_UP BIT(8)
- +#define AR8216_PORT_STATUS_LINK_AUTO BIT(9)
- +#define AR8216_PORT_STATUS_LINK_PAUSE BIT(10)
- +
- +#define AR8216_REG_PORT_CTRL(_i) (AR8216_PORT_OFFSET(_i) + 0x0004)
- +
- +/* port forwarding state */
- +#define AR8216_PORT_CTRL_STATE BITS(0, 3)
- +#define AR8216_PORT_CTRL_STATE_S 0
- +
- +#define AR8216_PORT_CTRL_LEARN_LOCK BIT(7)
- +
- +/* egress 802.1q mode */
- +#define AR8216_PORT_CTRL_VLAN_MODE BITS(8, 2)
- +#define AR8216_PORT_CTRL_VLAN_MODE_S 8
- +
- +#define AR8216_PORT_CTRL_IGMP_SNOOP BIT(10)
- +#define AR8216_PORT_CTRL_HEADER BIT(11)
- +#define AR8216_PORT_CTRL_MAC_LOOP BIT(12)
- +#define AR8216_PORT_CTRL_SINGLE_VLAN BIT(13)
- +#define AR8216_PORT_CTRL_LEARN BIT(14)
- +#define AR8216_PORT_CTRL_MIRROR_TX BIT(16)
- +#define AR8216_PORT_CTRL_MIRROR_RX BIT(17)
- +
- +#define AR8216_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET(_i) + 0x0008)
- +
- +#define AR8216_PORT_VLAN_DEFAULT_ID BITS(0, 12)
- +#define AR8216_PORT_VLAN_DEFAULT_ID_S 0
- +
- +#define AR8216_PORT_VLAN_DEST_PORTS BITS(16, 9)
- +#define AR8216_PORT_VLAN_DEST_PORTS_S 16
- +
- +/* bit0 added to the priority field of egress frames */
- +#define AR8216_PORT_VLAN_TX_PRIO BIT(27)
- +
- +/* port default priority */
- +#define AR8216_PORT_VLAN_PRIORITY BITS(28, 2)
- +#define AR8216_PORT_VLAN_PRIORITY_S 28
- +
- +/* ingress 802.1q mode */
- +#define AR8216_PORT_VLAN_MODE BITS(30, 2)
- +#define AR8216_PORT_VLAN_MODE_S 30
- +
- +#define AR8216_REG_PORT_RATE(_i) (AR8216_PORT_OFFSET(_i) + 0x000c)
- +#define AR8216_REG_PORT_PRIO(_i) (AR8216_PORT_OFFSET(_i) + 0x0010)
- +
- +#define AR8216_STATS_RXBROAD 0x00
- +#define AR8216_STATS_RXPAUSE 0x04
- +#define AR8216_STATS_RXMULTI 0x08
- +#define AR8216_STATS_RXFCSERR 0x0c
- +#define AR8216_STATS_RXALIGNERR 0x10
- +#define AR8216_STATS_RXRUNT 0x14
- +#define AR8216_STATS_RXFRAGMENT 0x18
- +#define AR8216_STATS_RX64BYTE 0x1c
- +#define AR8216_STATS_RX128BYTE 0x20
- +#define AR8216_STATS_RX256BYTE 0x24
- +#define AR8216_STATS_RX512BYTE 0x28
- +#define AR8216_STATS_RX1024BYTE 0x2c
- +#define AR8216_STATS_RXMAXBYTE 0x30
- +#define AR8216_STATS_RXTOOLONG 0x34
- +#define AR8216_STATS_RXGOODBYTE 0x38
- +#define AR8216_STATS_RXBADBYTE 0x40
- +#define AR8216_STATS_RXOVERFLOW 0x48
- +#define AR8216_STATS_FILTERED 0x4c
- +#define AR8216_STATS_TXBROAD 0x50
- +#define AR8216_STATS_TXPAUSE 0x54
- +#define AR8216_STATS_TXMULTI 0x58
- +#define AR8216_STATS_TXUNDERRUN 0x5c
- +#define AR8216_STATS_TX64BYTE 0x60
- +#define AR8216_STATS_TX128BYTE 0x64
- +#define AR8216_STATS_TX256BYTE 0x68
- +#define AR8216_STATS_TX512BYTE 0x6c
- +#define AR8216_STATS_TX1024BYTE 0x70
- +#define AR8216_STATS_TXMAXBYTE 0x74
- +#define AR8216_STATS_TXOVERSIZE 0x78
- +#define AR8216_STATS_TXBYTE 0x7c
- +#define AR8216_STATS_TXCOLLISION 0x84
- +#define AR8216_STATS_TXABORTCOL 0x88
- +#define AR8216_STATS_TXMULTICOL 0x8c
- +#define AR8216_STATS_TXSINGLECOL 0x90
- +#define AR8216_STATS_TXEXCDEFER 0x94
- +#define AR8216_STATS_TXDEFER 0x98
- +#define AR8216_STATS_TXLATECOL 0x9c
- +
- +#define AR8236_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET((_i)) + 0x0008)
- +#define AR8236_PORT_VLAN_DEFAULT_ID BITS(16, 12)
- +#define AR8236_PORT_VLAN_DEFAULT_ID_S 16
- +#define AR8236_PORT_VLAN_PRIORITY BITS(29, 3)
- +#define AR8236_PORT_VLAN_PRIORITY_S 28
- +
- +#define AR8236_REG_PORT_VLAN2(_i) (AR8216_PORT_OFFSET((_i)) + 0x000c)
- +#define AR8236_PORT_VLAN2_MEMBER BITS(16, 7)
- +#define AR8236_PORT_VLAN2_MEMBER_S 16
- +#define AR8236_PORT_VLAN2_TX_PRIO BIT(23)
- +#define AR8236_PORT_VLAN2_VLAN_MODE BITS(30, 2)
- +#define AR8236_PORT_VLAN2_VLAN_MODE_S 30
- +
- +#define AR8236_STATS_RXBROAD 0x00
- +#define AR8236_STATS_RXPAUSE 0x04
- +#define AR8236_STATS_RXMULTI 0x08
- +#define AR8236_STATS_RXFCSERR 0x0c
- +#define AR8236_STATS_RXALIGNERR 0x10
- +#define AR8236_STATS_RXRUNT 0x14
- +#define AR8236_STATS_RXFRAGMENT 0x18
- +#define AR8236_STATS_RX64BYTE 0x1c
- +#define AR8236_STATS_RX128BYTE 0x20
- +#define AR8236_STATS_RX256BYTE 0x24
- +#define AR8236_STATS_RX512BYTE 0x28
- +#define AR8236_STATS_RX1024BYTE 0x2c
- +#define AR8236_STATS_RX1518BYTE 0x30
- +#define AR8236_STATS_RXMAXBYTE 0x34
- +#define AR8236_STATS_RXTOOLONG 0x38
- +#define AR8236_STATS_RXGOODBYTE 0x3c
- +#define AR8236_STATS_RXBADBYTE 0x44
- +#define AR8236_STATS_RXOVERFLOW 0x4c
- +#define AR8236_STATS_FILTERED 0x50
- +#define AR8236_STATS_TXBROAD 0x54
- +#define AR8236_STATS_TXPAUSE 0x58
- +#define AR8236_STATS_TXMULTI 0x5c
- +#define AR8236_STATS_TXUNDERRUN 0x60
- +#define AR8236_STATS_TX64BYTE 0x64
- +#define AR8236_STATS_TX128BYTE 0x68
- +#define AR8236_STATS_TX256BYTE 0x6c
- +#define AR8236_STATS_TX512BYTE 0x70
- +#define AR8236_STATS_TX1024BYTE 0x74
- +#define AR8236_STATS_TX1518BYTE 0x78
- +#define AR8236_STATS_TXMAXBYTE 0x7c
- +#define AR8236_STATS_TXOVERSIZE 0x80
- +#define AR8236_STATS_TXBYTE 0x84
- +#define AR8236_STATS_TXCOLLISION 0x8c
- +#define AR8236_STATS_TXABORTCOL 0x90
- +#define AR8236_STATS_TXMULTICOL 0x94
- +#define AR8236_STATS_TXSINGLECOL 0x98
- +#define AR8236_STATS_TXEXCDEFER 0x9c
- +#define AR8236_STATS_TXDEFER 0xa0
- +#define AR8236_STATS_TXLATECOL 0xa4
- +
- +#define AR8316_REG_POSTRIP 0x0008
- +#define AR8316_POSTRIP_MAC0_GMII_EN BIT(0)
- +#define AR8316_POSTRIP_MAC0_RGMII_EN BIT(1)
- +#define AR8316_POSTRIP_PHY4_GMII_EN BIT(2)
- +#define AR8316_POSTRIP_PHY4_RGMII_EN BIT(3)
- +#define AR8316_POSTRIP_MAC0_MAC_MODE BIT(4)
- +#define AR8316_POSTRIP_RTL_MODE BIT(5)
- +#define AR8316_POSTRIP_RGMII_RXCLK_DELAY_EN BIT(6)
- +#define AR8316_POSTRIP_RGMII_TXCLK_DELAY_EN BIT(7)
- +#define AR8316_POSTRIP_SERDES_EN BIT(8)
- +#define AR8316_POSTRIP_SEL_ANA_RST BIT(9)
- +#define AR8316_POSTRIP_GATE_25M_EN BIT(10)
- +#define AR8316_POSTRIP_SEL_CLK25M BIT(11)
- +#define AR8316_POSTRIP_HIB_PULSE_HW BIT(12)
- +#define AR8316_POSTRIP_DBG_MODE_I BIT(13)
- +#define AR8316_POSTRIP_MAC5_MAC_MODE BIT(14)
- +#define AR8316_POSTRIP_MAC5_PHY_MODE BIT(15)
- +#define AR8316_POSTRIP_POWER_DOWN_HW BIT(16)
- +#define AR8316_POSTRIP_LPW_STATE_EN BIT(17)
- +#define AR8316_POSTRIP_MAN_EN BIT(18)
- +#define AR8316_POSTRIP_PHY_PLL_ON BIT(19)
- +#define AR8316_POSTRIP_LPW_EXIT BIT(20)
- +#define AR8316_POSTRIP_TXDELAY_S0 BIT(21)
- +#define AR8316_POSTRIP_TXDELAY_S1 BIT(22)
- +#define AR8316_POSTRIP_RXDELAY_S0 BIT(23)
- +#define AR8316_POSTRIP_LED_OPEN_EN BIT(24)
- +#define AR8316_POSTRIP_SPI_EN BIT(25)
- +#define AR8316_POSTRIP_RXDELAY_S1 BIT(26)
- +#define AR8316_POSTRIP_POWER_ON_SEL BIT(31)
- +
- +/* port speed */
- +enum {
- + AR8216_PORT_SPEED_10M = 0,
- + AR8216_PORT_SPEED_100M = 1,
- + AR8216_PORT_SPEED_1000M = 2,
- + AR8216_PORT_SPEED_ERR = 3,
- +};
- +
- +/* ingress 802.1q mode */
- +enum {
- + AR8216_IN_PORT_ONLY = 0,
- + AR8216_IN_PORT_FALLBACK = 1,
- + AR8216_IN_VLAN_ONLY = 2,
- + AR8216_IN_SECURE = 3
- +};
- +
- +/* egress 802.1q mode */
- +enum {
- + AR8216_OUT_KEEP = 0,
- + AR8216_OUT_STRIP_VLAN = 1,
- + AR8216_OUT_ADD_VLAN = 2
- +};
- +
- +/* port forwarding state */
- +enum {
- + AR8216_PORT_STATE_DISABLED = 0,
- + AR8216_PORT_STATE_BLOCK = 1,
- + AR8216_PORT_STATE_LISTEN = 2,
- + AR8216_PORT_STATE_LEARN = 3,
- + AR8216_PORT_STATE_FORWARD = 4
- +};
- +
- +enum {
- + AR8XXX_VER_AR8216 = 0x01,
- + AR8XXX_VER_AR8236 = 0x03,
- + AR8XXX_VER_AR8316 = 0x10,
- + AR8XXX_VER_AR8327 = 0x12,
- + AR8XXX_VER_AR8337 = 0x13,
- +};
- +
- +#define AR8XXX_NUM_ARL_RECORDS 100
- +
- +enum arl_op {
- + AR8XXX_ARL_INITIALIZE,
- + AR8XXX_ARL_GET_NEXT
- +};
- +
- +struct arl_entry {
- + u8 port;
- + u8 mac[6];
- +};
- +
- +struct ar8xxx_priv;
- +
- +struct ar8xxx_mib_desc {
- + unsigned int size;
- + unsigned int offset;
- + const char *name;
- +};
- +
- +struct ar8xxx_chip {
- + unsigned long caps;
- + bool config_at_probe;
- + bool mii_lo_first;
- +
- + /* parameters to calculate REG_PORT_STATS_BASE */
- + unsigned reg_port_stats_start;
- + unsigned reg_port_stats_length;
- +
- + int (*hw_init)(struct ar8xxx_priv *priv);
- + void (*cleanup)(struct ar8xxx_priv *priv);
- +
- + const char *name;
- + int vlans;
- + int ports;
- + const struct switch_dev_ops *swops;
- +
- + void (*init_globals)(struct ar8xxx_priv *priv);
- + void (*init_port)(struct ar8xxx_priv *priv, int port);
- + void (*setup_port)(struct ar8xxx_priv *priv, int port, u32 members);
- + u32 (*read_port_status)(struct ar8xxx_priv *priv, int port);
- + u32 (*read_port_eee_status)(struct ar8xxx_priv *priv, int port);
- + int (*atu_flush)(struct ar8xxx_priv *priv);
- + int (*atu_flush_port)(struct ar8xxx_priv *priv, int port);
- + void (*vtu_flush)(struct ar8xxx_priv *priv);
- + void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask);
- + void (*phy_fixup)(struct ar8xxx_priv *priv, int phy);
- + void (*set_mirror_regs)(struct ar8xxx_priv *priv);
- + void (*get_arl_entry)(struct ar8xxx_priv *priv, struct arl_entry *a,
- + u32 *status, enum arl_op op);
- + int (*sw_hw_apply)(struct switch_dev *dev);
- +
- + const struct ar8xxx_mib_desc *mib_decs;
- + unsigned num_mibs;
- + unsigned mib_func;
- +};
- +
- +struct ar8xxx_priv {
- + struct switch_dev dev;
- + struct mii_bus *mii_bus;
- + struct phy_device *phy;
- +
- + int (*get_port_link)(unsigned port);
- +
- + const struct net_device_ops *ndo_old;
- + struct net_device_ops ndo;
- + struct mutex reg_mutex;
- + u8 chip_ver;
- + u8 chip_rev;
- + const struct ar8xxx_chip *chip;
- + void *chip_data;
- + bool initialized;
- + bool port4_phy;
- + char buf[2048];
- + struct arl_entry arl_table[AR8XXX_NUM_ARL_RECORDS];
- + char arl_buf[AR8XXX_NUM_ARL_RECORDS * 32 + 256];
- + bool link_up[AR8X16_MAX_PORTS];
- +
- + bool init;
- +
- + struct mutex mib_lock;
- + struct delayed_work mib_work;
- + int mib_next_port;
- + u64 *mib_stats;
- +
- + struct list_head list;
- + unsigned int use_count;
- +
- + /* all fields below are cleared on reset */
- + bool vlan;
- + u16 vlan_id[AR8X16_MAX_VLANS];
- + u8 vlan_table[AR8X16_MAX_VLANS];
- + u8 vlan_tagged;
- + u16 pvid[AR8X16_MAX_PORTS];
- +
- + /* mirroring */
- + bool mirror_rx;
- + bool mirror_tx;
- + int source_port;
- + int monitor_port;
- +};
- +
- +u32
- +ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum);
- +void
- +ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val);
- +u32
- +ar8xxx_read(struct ar8xxx_priv *priv, int reg);
- +void
- +ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val);
- +u32
- +ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
- +
- +void
- +ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
- + u16 dbg_addr, u16 dbg_data);
- +void
- +ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 data);
- +u16
- +ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr);
- +void
- +ar8xxx_phy_init(struct ar8xxx_priv *priv);
- +int
- +ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_set_reset_mibs(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan);
- +int
- +ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan);
- +int
- +ar8xxx_sw_hw_apply(struct switch_dev *dev);
- +int
- +ar8xxx_sw_reset_switch(struct switch_dev *dev);
- +int
- +ar8xxx_sw_get_port_link(struct switch_dev *dev, int port,
- + struct switch_port_link *link);
- +int
- +ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_get_port_mib(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_get_arl_table(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val);
- +int
- +ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
- +
- +static inline struct ar8xxx_priv *
- +swdev_to_ar8xxx(struct switch_dev *swdev)
- +{
- + return container_of(swdev, struct ar8xxx_priv, dev);
- +}
- +
- +static inline bool ar8xxx_has_gige(struct ar8xxx_priv *priv)
- +{
- + return priv->chip->caps & AR8XXX_CAP_GIGE;
- +}
- +
- +static inline bool ar8xxx_has_mib_counters(struct ar8xxx_priv *priv)
- +{
- + return priv->chip->caps & AR8XXX_CAP_MIB_COUNTERS;
- +}
- +
- +static inline bool chip_is_ar8216(struct ar8xxx_priv *priv)
- +{
- + return priv->chip_ver == AR8XXX_VER_AR8216;
- +}
- +
- +static inline bool chip_is_ar8236(struct ar8xxx_priv *priv)
- +{
- + return priv->chip_ver == AR8XXX_VER_AR8236;
- +}
- +
- +static inline bool chip_is_ar8316(struct ar8xxx_priv *priv)
- +{
- + return priv->chip_ver == AR8XXX_VER_AR8316;
- +}
- +
- +static inline bool chip_is_ar8327(struct ar8xxx_priv *priv)
- +{
- + return priv->chip_ver == AR8XXX_VER_AR8327;
- +}
- +
- +static inline bool chip_is_ar8337(struct ar8xxx_priv *priv)
- +{
- + return priv->chip_ver == AR8XXX_VER_AR8337;
- +}
- +
- +static inline void
- +ar8xxx_reg_set(struct ar8xxx_priv *priv, int reg, u32 val)
- +{
- + ar8xxx_rmw(priv, reg, 0, val);
- +}
- +
- +static inline void
- +ar8xxx_reg_clear(struct ar8xxx_priv *priv, int reg, u32 val)
- +{
- + ar8xxx_rmw(priv, reg, val, 0);
- +}
- +
- +static inline void
- +split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
- +{
- + regaddr >>= 1;
- + *r1 = regaddr & 0x1e;
- +
- + regaddr >>= 5;
- + *r2 = regaddr & 0x7;
- +
- + regaddr >>= 3;
- + *page = regaddr & 0x1ff;
- +}
- +
- +static inline void
- +wait_for_page_switch(void)
- +{
- + udelay(5);
- +}
- +
- +#endif
- diff -Nur linux-4.1.6.orig/drivers/net/phy/ar8327.c linux-4.1.6/drivers/net/phy/ar8327.c
- --- linux-4.1.6.orig/drivers/net/phy/ar8327.c 1970-01-01 01:00:00.000000000 +0100
- +++ linux-4.1.6/drivers/net/phy/ar8327.c 2015-09-13 22:55:18.331373990 +0200
- @@ -0,0 +1,1268 @@
- +/*
- + * ar8327.c: AR8216 switch driver
- + *
- + * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
- + * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
- + *
- + * 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 2
- + * of the License, or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + */
- +
- +#include <linux/list.h>
- +#include <linux/bitops.h>
- +#include <linux/switch.h>
- +#include <linux/delay.h>
- +#include <linux/phy.h>
- +#include <linux/lockdep.h>
- +#include <linux/ar8216_platform.h>
- +#include <linux/workqueue.h>
- +#include <linux/of_device.h>
- +#include <linux/leds.h>
- +#include <linux/mdio.h>
- +
- +#include "ar8216.h"
- +#include "ar8327.h"
- +
- +extern const struct ar8xxx_mib_desc ar8236_mibs[39];
- +extern const struct switch_attr ar8xxx_sw_attr_vlan[1];
- +
- +static u32
- +ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg)
- +{
- + u32 t;
- +
- + if (!cfg)
- + return 0;
- +
- + t = 0;
- + switch (cfg->mode) {
- + case AR8327_PAD_NC:
- + break;
- +
- + case AR8327_PAD_MAC2MAC_MII:
- + t = AR8327_PAD_MAC_MII_EN;
- + if (cfg->rxclk_sel)
- + t |= AR8327_PAD_MAC_MII_RXCLK_SEL;
- + if (cfg->txclk_sel)
- + t |= AR8327_PAD_MAC_MII_TXCLK_SEL;
- + break;
- +
- + case AR8327_PAD_MAC2MAC_GMII:
- + t = AR8327_PAD_MAC_GMII_EN;
- + if (cfg->rxclk_sel)
- + t |= AR8327_PAD_MAC_GMII_RXCLK_SEL;
- + if (cfg->txclk_sel)
- + t |= AR8327_PAD_MAC_GMII_TXCLK_SEL;
- + break;
- +
- + case AR8327_PAD_MAC_SGMII:
- + t = AR8327_PAD_SGMII_EN;
- +
- + /*
- + * WAR for the QUalcomm Atheros AP136 board.
- + * It seems that RGMII TX/RX delay settings needs to be
- + * applied for SGMII mode as well, The ethernet is not
- + * reliable without this.
- + */
- + t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S;
- + t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S;
- + if (cfg->rxclk_delay_en)
- + t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN;
- + if (cfg->txclk_delay_en)
- + t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN;
- +
- + if (cfg->sgmii_delay_en)
- + t |= AR8327_PAD_SGMII_DELAY_EN;
- +
- + break;
- +
- + case AR8327_PAD_MAC2PHY_MII:
- + t = AR8327_PAD_PHY_MII_EN;
- + if (cfg->rxclk_sel)
- + t |= AR8327_PAD_PHY_MII_RXCLK_SEL;
- + if (cfg->txclk_sel)
- + t |= AR8327_PAD_PHY_MII_TXCLK_SEL;
- + break;
- +
- + case AR8327_PAD_MAC2PHY_GMII:
- + t = AR8327_PAD_PHY_GMII_EN;
- + if (cfg->pipe_rxclk_sel)
- + t |= AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL;
- + if (cfg->rxclk_sel)
- + t |= AR8327_PAD_PHY_GMII_RXCLK_SEL;
- + if (cfg->txclk_sel)
- + t |= AR8327_PAD_PHY_GMII_TXCLK_SEL;
- + break;
- +
- + case AR8327_PAD_MAC_RGMII:
- + t = AR8327_PAD_RGMII_EN;
- + t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S;
- + t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S;
- + if (cfg->rxclk_delay_en)
- + t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN;
- + if (cfg->txclk_delay_en)
- + t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN;
- + break;
- +
- + case AR8327_PAD_PHY_GMII:
- + t = AR8327_PAD_PHYX_GMII_EN;
- + break;
- +
- + case AR8327_PAD_PHY_RGMII:
- + t = AR8327_PAD_PHYX_RGMII_EN;
- + break;
- +
- + case AR8327_PAD_PHY_MII:
- + t = AR8327_PAD_PHYX_MII_EN;
- + break;
- + }
- +
- + if (cfg->mac06_exchange_en)
- + t |= AR8337_PAD_MAC06_EXCHANGE_EN;
- +
- + return t;
- +}
- +
- +static void
- +ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy)
- +{
- + switch (priv->chip_rev) {
- + case 1:
- + /* For 100M waveform */
- + ar8xxx_phy_dbg_write(priv, phy, 0, 0x02ea);
- + /* Turn on Gigabit clock */
- + ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x68a0);
- + break;
- +
- + case 2:
- + ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x3c);
- + ar8xxx_phy_mmd_write(priv, phy, 0x4007, 0x0);
- + /* fallthrough */
- + case 4:
- + ar8xxx_phy_mmd_write(priv, phy, 0x3, 0x800d);
- + ar8xxx_phy_mmd_write(priv, phy, 0x4003, 0x803f);
- +
- + ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x6860);
- + ar8xxx_phy_dbg_write(priv, phy, 0x5, 0x2c46);
- + ar8xxx_phy_dbg_write(priv, phy, 0x3c, 0x6000);
- + break;
- + }
- +}
- +
- +static u32
- +ar8327_get_port_init_status(struct ar8327_port_cfg *cfg)
- +{
- + u32 t;
- +
- + if (!cfg->force_link)
- + return AR8216_PORT_STATUS_LINK_AUTO;
- +
- + t = AR8216_PORT_STATUS_TXMAC | AR8216_PORT_STATUS_RXMAC;
- + t |= cfg->duplex ? AR8216_PORT_STATUS_DUPLEX : 0;
- + t |= cfg->rxpause ? AR8216_PORT_STATUS_RXFLOW : 0;
- + t |= cfg->txpause ? AR8216_PORT_STATUS_TXFLOW : 0;
- +
- + switch (cfg->speed) {
- + case AR8327_PORT_SPEED_10:
- + t |= AR8216_PORT_SPEED_10M;
- + break;
- + case AR8327_PORT_SPEED_100:
- + t |= AR8216_PORT_SPEED_100M;
- + break;
- + case AR8327_PORT_SPEED_1000:
- + t |= AR8216_PORT_SPEED_1000M;
- + break;
- + }
- +
- + return t;
- +}
- +
- +#define AR8327_LED_ENTRY(_num, _reg, _shift) \
- + [_num] = { .reg = (_reg), .shift = (_shift) }
- +
- +static const struct ar8327_led_entry
- +ar8327_led_map[AR8327_NUM_LEDS] = {
- + AR8327_LED_ENTRY(AR8327_LED_PHY0_0, 0, 14),
- + AR8327_LED_ENTRY(AR8327_LED_PHY0_1, 1, 14),
- + AR8327_LED_ENTRY(AR8327_LED_PHY0_2, 2, 14),
- +
- + AR8327_LED_ENTRY(AR8327_LED_PHY1_0, 3, 8),
- + AR8327_LED_ENTRY(AR8327_LED_PHY1_1, 3, 10),
- + AR8327_LED_ENTRY(AR8327_LED_PHY1_2, 3, 12),
- +
- + AR8327_LED_ENTRY(AR8327_LED_PHY2_0, 3, 14),
- + AR8327_LED_ENTRY(AR8327_LED_PHY2_1, 3, 16),
- + AR8327_LED_ENTRY(AR8327_LED_PHY2_2, 3, 18),
- +
- + AR8327_LED_ENTRY(AR8327_LED_PHY3_0, 3, 20),
- + AR8327_LED_ENTRY(AR8327_LED_PHY3_1, 3, 22),
- + AR8327_LED_ENTRY(AR8327_LED_PHY3_2, 3, 24),
- +
- + AR8327_LED_ENTRY(AR8327_LED_PHY4_0, 0, 30),
- + AR8327_LED_ENTRY(AR8327_LED_PHY4_1, 1, 30),
- + AR8327_LED_ENTRY(AR8327_LED_PHY4_2, 2, 30),
- +};
- +
- +static void
- +ar8327_set_led_pattern(struct ar8xxx_priv *priv, unsigned int led_num,
- + enum ar8327_led_pattern pattern)
- +{
- + const struct ar8327_led_entry *entry;
- +
- + entry = &ar8327_led_map[led_num];
- + ar8xxx_rmw(priv, AR8327_REG_LED_CTRL(entry->reg),
- + (3 << entry->shift), pattern << entry->shift);
- +}
- +
- +static void
- +ar8327_led_work_func(struct work_struct *work)
- +{
- + struct ar8327_led *aled;
- + u8 pattern;
- +
- + aled = container_of(work, struct ar8327_led, led_work);
- +
- + spin_lock(&aled->lock);
- + pattern = aled->pattern;
- + spin_unlock(&aled->lock);
- +
- + ar8327_set_led_pattern(aled->sw_priv, aled->led_num,
- + pattern);
- +}
- +
- +static void
- +ar8327_led_schedule_change(struct ar8327_led *aled, u8 pattern)
- +{
- + if (aled->pattern == pattern)
- + return;
- +
- + aled->pattern = pattern;
- + schedule_work(&aled->led_work);
- +}
- +
- +static inline struct ar8327_led *
- +led_cdev_to_ar8327_led(struct led_classdev *led_cdev)
- +{
- + return container_of(led_cdev, struct ar8327_led, cdev);
- +}
- +
- +static int
- +ar8327_led_blink_set(struct led_classdev *led_cdev,
- + unsigned long *delay_on,
- + unsigned long *delay_off)
- +{
- + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
- +
- + if (*delay_on == 0 && *delay_off == 0) {
- + *delay_on = 125;
- + *delay_off = 125;
- + }
- +
- + if (*delay_on != 125 || *delay_off != 125) {
- + /*
- + * The hardware only supports blinking at 4Hz. Fall back
- + * to software implementation in other cases.
- + */
- + return -EINVAL;
- + }
- +
- + spin_lock(&aled->lock);
- +
- + aled->enable_hw_mode = false;
- + ar8327_led_schedule_change(aled, AR8327_LED_PATTERN_BLINK);
- +
- + spin_unlock(&aled->lock);
- +
- + return 0;
- +}
- +
- +static void
- +ar8327_led_set_brightness(struct led_classdev *led_cdev,
- + enum led_brightness brightness)
- +{
- + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
- + u8 pattern;
- + bool active;
- +
- + active = (brightness != LED_OFF);
- + active ^= aled->active_low;
- +
- + pattern = (active) ? AR8327_LED_PATTERN_ON :
- + AR8327_LED_PATTERN_OFF;
- +
- + spin_lock(&aled->lock);
- +
- + aled->enable_hw_mode = false;
- + ar8327_led_schedule_change(aled, pattern);
- +
- + spin_unlock(&aled->lock);
- +}
- +
- +static ssize_t
- +ar8327_led_enable_hw_mode_show(struct device *dev,
- + struct device_attribute *attr,
- + char *buf)
- +{
- + struct led_classdev *led_cdev = dev_get_drvdata(dev);
- + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
- + ssize_t ret = 0;
- +
- + spin_lock(&aled->lock);
- + ret += sprintf(buf, "%d\n", aled->enable_hw_mode);
- + spin_unlock(&aled->lock);
- +
- + return ret;
- +}
- +
- +static ssize_t
- +ar8327_led_enable_hw_mode_store(struct device *dev,
- + struct device_attribute *attr,
- + const char *buf,
- + size_t size)
- +{
- + struct led_classdev *led_cdev = dev_get_drvdata(dev);
- + struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
- + u8 pattern;
- + u8 value;
- + int ret;
- +
- + ret = kstrtou8(buf, 10, &value);
- + if (ret < 0)
- + return -EINVAL;
- +
- + spin_lock(&aled->lock);
- +
- + aled->enable_hw_mode = !!value;
- + if (aled->enable_hw_mode)
- + pattern = AR8327_LED_PATTERN_RULE;
- + else
- + pattern = AR8327_LED_PATTERN_OFF;
- +
- + ar8327_led_schedule_change(aled, pattern);
- +
- + spin_unlock(&aled->lock);
- +
- + return size;
- +}
- +
- +static DEVICE_ATTR(enable_hw_mode, S_IRUGO | S_IWUSR,
- + ar8327_led_enable_hw_mode_show,
- + ar8327_led_enable_hw_mode_store);
- +
- +static int
- +ar8327_led_register(struct ar8327_led *aled)
- +{
- + int ret;
- +
- + ret = led_classdev_register(NULL, &aled->cdev);
- + if (ret < 0)
- + return ret;
- +
- + if (aled->mode == AR8327_LED_MODE_HW) {
- + ret = device_create_file(aled->cdev.dev,
- + &dev_attr_enable_hw_mode);
- + if (ret)
- + goto err_unregister;
- + }
- +
- + return 0;
- +
- +err_unregister:
- + led_classdev_unregister(&aled->cdev);
- + return ret;
- +}
- +
- +static void
- +ar8327_led_unregister(struct ar8327_led *aled)
- +{
- + if (aled->mode == AR8327_LED_MODE_HW)
- + device_remove_file(aled->cdev.dev, &dev_attr_enable_hw_mode);
- +
- + led_classdev_unregister(&aled->cdev);
- + cancel_work_sync(&aled->led_work);
- +}
- +
- +static int
- +ar8327_led_create(struct ar8xxx_priv *priv,
- + const struct ar8327_led_info *led_info)
- +{
- + struct ar8327_data *data = priv->chip_data;
- + struct ar8327_led *aled;
- + int ret;
- +
- + if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS))
- + return 0;
- +
- + if (!led_info->name)
- + return -EINVAL;
- +
- + if (led_info->led_num >= AR8327_NUM_LEDS)
- + return -EINVAL;
- +
- + aled = kzalloc(sizeof(*aled) + strlen(led_info->name) + 1,
- + GFP_KERNEL);
- + if (!aled)
- + return -ENOMEM;
- +
- + aled->sw_priv = priv;
- + aled->led_num = led_info->led_num;
- + aled->active_low = led_info->active_low;
- + aled->mode = led_info->mode;
- +
- + if (aled->mode == AR8327_LED_MODE_HW)
- + aled->enable_hw_mode = true;
- +
- + aled->name = (char *)(aled + 1);
- + strcpy(aled->name, led_info->name);
- +
- + aled->cdev.name = aled->name;
- + aled->cdev.brightness_set = ar8327_led_set_brightness;
- + aled->cdev.blink_set = ar8327_led_blink_set;
- + aled->cdev.default_trigger = led_info->default_trigger;
- +
- + spin_lock_init(&aled->lock);
- + mutex_init(&aled->mutex);
- + INIT_WORK(&aled->led_work, ar8327_led_work_func);
- +
- + ret = ar8327_led_register(aled);
- + if (ret)
- + goto err_free;
- +
- + data->leds[data->num_leds++] = aled;
- +
- + return 0;
- +
- +err_free:
- + kfree(aled);
- + return ret;
- +}
- +
- +static void
- +ar8327_led_destroy(struct ar8327_led *aled)
- +{
- + ar8327_led_unregister(aled);
- + kfree(aled);
- +}
- +
- +static void
- +ar8327_leds_init(struct ar8xxx_priv *priv)
- +{
- + struct ar8327_data *data = priv->chip_data;
- + unsigned i;
- +
- + if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS))
- + return;
- +
- + for (i = 0; i < data->num_leds; i++) {
- + struct ar8327_led *aled;
- +
- + aled = data->leds[i];
- +
- + if (aled->enable_hw_mode)
- + aled->pattern = AR8327_LED_PATTERN_RULE;
- + else
- + aled->pattern = AR8327_LED_PATTERN_OFF;
- +
- + ar8327_set_led_pattern(priv, aled->led_num, aled->pattern);
- + }
- +}
- +
- +static void
- +ar8327_leds_cleanup(struct ar8xxx_priv *priv)
- +{
- + struct ar8327_data *data = priv->chip_data;
- + unsigned i;
- +
- + if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS))
- + return;
- +
- + for (i = 0; i < data->num_leds; i++) {
- + struct ar8327_led *aled;
- +
- + aled = data->leds[i];
- + ar8327_led_destroy(aled);
- + }
- +
- + kfree(data->leds);
- +}
- +
- +static int
- +ar8327_hw_config_pdata(struct ar8xxx_priv *priv,
- + struct ar8327_platform_data *pdata)
- +{
- + struct ar8327_led_cfg *led_cfg;
- + struct ar8327_data *data = priv->chip_data;
- + u32 pos, new_pos;
- + u32 t;
- +
- + if (!pdata)
- + return -EINVAL;
- +
- + priv->get_port_link = pdata->get_port_link;
- +
- + data->port0_status = ar8327_get_port_init_status(&pdata->port0_cfg);
- + data->port6_status = ar8327_get_port_init_status(&pdata->port6_cfg);
- +
- + t = ar8327_get_pad_cfg(pdata->pad0_cfg);
- + ar8xxx_write(priv, AR8327_REG_PAD0_MODE, t);
- + t = ar8327_get_pad_cfg(pdata->pad5_cfg);
- + ar8xxx_write(priv, AR8327_REG_PAD5_MODE, t);
- + t = ar8327_get_pad_cfg(pdata->pad6_cfg);
- + ar8xxx_write(priv, AR8327_REG_PAD6_MODE, t);
- +
- + pos = ar8xxx_read(priv, AR8327_REG_POWER_ON_STRIP);
- + new_pos = pos;
- +
- + led_cfg = pdata->led_cfg;
- + if (led_cfg) {
- + if (led_cfg->open_drain)
- + new_pos |= AR8327_POWER_ON_STRIP_LED_OPEN_EN;
- + else
- + new_pos &= ~AR8327_POWER_ON_STRIP_LED_OPEN_EN;
- +
- + ar8xxx_write(priv, AR8327_REG_LED_CTRL0, led_cfg->led_ctrl0);
- + ar8xxx_write(priv, AR8327_REG_LED_CTRL1, led_cfg->led_ctrl1);
- + ar8xxx_write(priv, AR8327_REG_LED_CTRL2, led_cfg->led_ctrl2);
- + ar8xxx_write(priv, AR8327_REG_LED_CTRL3, led_cfg->led_ctrl3);
- +
- + if (new_pos != pos)
- + new_pos |= AR8327_POWER_ON_STRIP_POWER_ON_SEL;
- + }
- +
- + if (pdata->sgmii_cfg) {
- + t = pdata->sgmii_cfg->sgmii_ctrl;
- + if (priv->chip_rev == 1)
- + t |= AR8327_SGMII_CTRL_EN_PLL |
- + AR8327_SGMII_CTRL_EN_RX |
- + AR8327_SGMII_CTRL_EN_TX;
- + else
- + t &= ~(AR8327_SGMII_CTRL_EN_PLL |
- + AR8327_SGMII_CTRL_EN_RX |
- + AR8327_SGMII_CTRL_EN_TX);
- +
- + ar8xxx_write(priv, AR8327_REG_SGMII_CTRL, t);
- +
- + if (pdata->sgmii_cfg->serdes_aen)
- + new_pos &= ~AR8327_POWER_ON_STRIP_SERDES_AEN;
- + else
- + new_pos |= AR8327_POWER_ON_STRIP_SERDES_AEN;
- + }
- +
- + ar8xxx_write(priv, AR8327_REG_POWER_ON_STRIP, new_pos);
- +
- + if (pdata->leds && pdata->num_leds) {
- + int i;
- +
- + data->leds = kzalloc(pdata->num_leds * sizeof(void *),
- + GFP_KERNEL);
- + if (!data->leds)
- + return -ENOMEM;
- +
- + for (i = 0; i < pdata->num_leds; i++)
- + ar8327_led_create(priv, &pdata->leds[i]);
- + }
- +
- + return 0;
- +}
- +
- +#ifdef CONFIG_OF
- +static int
- +ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np)
- +{
- + struct ar8327_data *data = priv->chip_data;
- + const __be32 *paddr;
- + int len;
- + int i;
- +
- + paddr = of_get_property(np, "qca,ar8327-initvals", &len);
- + if (!paddr || len < (2 * sizeof(*paddr)))
- + return -EINVAL;
- +
- + len /= sizeof(*paddr);
- +
- + for (i = 0; i < len - 1; i += 2) {
- + u32 reg;
- + u32 val;
- +
- + reg = be32_to_cpup(paddr + i);
- + val = be32_to_cpup(paddr + i + 1);
- +
- + switch (reg) {
- + case AR8327_REG_PORT_STATUS(0):
- + data->port0_status = val;
- + break;
- + case AR8327_REG_PORT_STATUS(6):
- + data->port6_status = val;
- + break;
- + default:
- + ar8xxx_write(priv, reg, val);
- + break;
- + }
- + }
- +
- + return 0;
- +}
- +#else
- +static inline int
- +ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np)
- +{
- + return -EINVAL;
- +}
- +#endif
- +
- +static int
- +ar8327_hw_init(struct ar8xxx_priv *priv)
- +{
- + int ret;
- +
- + priv->chip_data = kzalloc(sizeof(struct ar8327_data), GFP_KERNEL);
- + if (!priv->chip_data)
- + return -ENOMEM;
- +
- + if (priv->phy->dev.of_node)
- + ret = ar8327_hw_config_of(priv, priv->phy->dev.of_node);
- + else
- + ret = ar8327_hw_config_pdata(priv,
- + priv->phy->dev.platform_data);
- +
- + if (ret)
- + return ret;
- +
- + ar8327_leds_init(priv);
- +
- + ar8xxx_phy_init(priv);
- +
- + return 0;
- +}
- +
- +static void
- +ar8327_cleanup(struct ar8xxx_priv *priv)
- +{
- + ar8327_leds_cleanup(priv);
- +}
- +
- +static void
- +ar8327_init_globals(struct ar8xxx_priv *priv)
- +{
- + struct ar8327_data *data = priv->chip_data;
- + u32 t;
- + int i;
- +
- + /* enable CPU port and disable mirror port */
- + t = AR8327_FWD_CTRL0_CPU_PORT_EN |
- + AR8327_FWD_CTRL0_MIRROR_PORT;
- + ar8xxx_write(priv, AR8327_REG_FWD_CTRL0, t);
- +
- + /* forward multicast and broadcast frames to CPU */
- + t = (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_UC_FLOOD_S) |
- + (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_MC_FLOOD_S) |
- + (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_BC_FLOOD_S);
- + ar8xxx_write(priv, AR8327_REG_FWD_CTRL1, t);
- +
- + /* enable jumbo frames */
- + ar8xxx_rmw(priv, AR8327_REG_MAX_FRAME_SIZE,
- + AR8327_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2);
- +
- + /* Enable MIB counters */
- + ar8xxx_reg_set(priv, AR8327_REG_MODULE_EN,
- + AR8327_MODULE_EN_MIB);
- +
- + /* Disable EEE on all phy's due to stability issues */
- + for (i = 0; i < AR8XXX_NUM_PHYS; i++)
- + data->eee[i] = false;
- +}
- +
- +static void
- +ar8327_init_port(struct ar8xxx_priv *priv, int port)
- +{
- + struct ar8327_data *data = priv->chip_data;
- + u32 t;
- +
- + if (port == AR8216_PORT_CPU)
- + t = data->port0_status;
- + else if (port == 6)
- + t = data->port6_status;
- + else
- + t = AR8216_PORT_STATUS_LINK_AUTO;
- +
- + ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), t);
- + ar8xxx_write(priv, AR8327_REG_PORT_HEADER(port), 0);
- +
- + t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S;
- + t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S;
- + ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), t);
- +
- + t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S;
- + ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t);
- +
- + t = AR8327_PORT_LOOKUP_LEARN;
- + t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S;
- + ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t);
- +}
- +
- +static u32
- +ar8327_read_port_status(struct ar8xxx_priv *priv, int port)
- +{
- + u32 t;
- +
- + t = ar8xxx_read(priv, AR8327_REG_PORT_STATUS(port));
- + /* map the flow control autoneg result bits to the flow control bits
- + * used in forced mode to allow ar8216_read_port_link detect
- + * flow control properly if autoneg is used
- + */
- + if (t & AR8216_PORT_STATUS_LINK_UP &&
- + t & AR8216_PORT_STATUS_LINK_AUTO) {
- + t &= ~(AR8216_PORT_STATUS_TXFLOW | AR8216_PORT_STATUS_RXFLOW);
- + if (t & AR8327_PORT_STATUS_TXFLOW_AUTO)
- + t |= AR8216_PORT_STATUS_TXFLOW;
- + if (t & AR8327_PORT_STATUS_RXFLOW_AUTO)
- + t |= AR8216_PORT_STATUS_RXFLOW;
- + }
- +
- + return t;
- +}
- +
- +static u32
- +ar8327_read_port_eee_status(struct ar8xxx_priv *priv, int port)
- +{
- + int phy;
- + u16 t;
- +
- + if (port >= priv->dev.ports)
- + return 0;
- +
- + if (port == 0 || port == 6)
- + return 0;
- +
- + phy = port - 1;
- +
- + /* EEE Ability Auto-negotiation Result */
- + ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x8000);
- + t = ar8xxx_phy_mmd_read(priv, phy, 0x4007);
- +
- + return mmd_eee_adv_to_ethtool_adv_t(t);
- +}
- +
- +static int
- +ar8327_atu_flush(struct ar8xxx_priv *priv)
- +{
- + int ret;
- +
- + ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC,
- + AR8327_ATU_FUNC_BUSY, 0);
- + if (!ret)
- + ar8xxx_write(priv, AR8327_REG_ATU_FUNC,
- + AR8327_ATU_FUNC_OP_FLUSH |
- + AR8327_ATU_FUNC_BUSY);
- +
- + return ret;
- +}
- +
- +static int
- +ar8327_atu_flush_port(struct ar8xxx_priv *priv, int port)
- +{
- + u32 t;
- + int ret;
- +
- + ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC,
- + AR8327_ATU_FUNC_BUSY, 0);
- + if (!ret) {
- + t = (port << AR8327_ATU_PORT_NUM_S);
- + t |= AR8327_ATU_FUNC_OP_FLUSH_PORT;
- + t |= AR8327_ATU_FUNC_BUSY;
- + ar8xxx_write(priv, AR8327_REG_ATU_FUNC, t);
- + }
- +
- + return ret;
- +}
- +
- +static void
- +ar8327_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val)
- +{
- + if (ar8216_wait_bit(priv, AR8327_REG_VTU_FUNC1,
- + AR8327_VTU_FUNC1_BUSY, 0))
- + return;
- +
- + if ((op & AR8327_VTU_FUNC1_OP) == AR8327_VTU_FUNC1_OP_LOAD)
- + ar8xxx_write(priv, AR8327_REG_VTU_FUNC0, val);
- +
- + op |= AR8327_VTU_FUNC1_BUSY;
- + ar8xxx_write(priv, AR8327_REG_VTU_FUNC1, op);
- +}
- +
- +static void
- +ar8327_vtu_flush(struct ar8xxx_priv *priv)
- +{
- + ar8327_vtu_op(priv, AR8327_VTU_FUNC1_OP_FLUSH, 0);
- +}
- +
- +static void
- +ar8327_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask)
- +{
- + u32 op;
- + u32 val;
- + int i;
- +
- + op = AR8327_VTU_FUNC1_OP_LOAD | (vid << AR8327_VTU_FUNC1_VID_S);
- + val = AR8327_VTU_FUNC0_VALID | AR8327_VTU_FUNC0_IVL;
- + for (i = 0; i < AR8327_NUM_PORTS; i++) {
- + u32 mode;
- +
- + if ((port_mask & BIT(i)) == 0)
- + mode = AR8327_VTU_FUNC0_EG_MODE_NOT;
- + else if (priv->vlan == 0)
- + mode = AR8327_VTU_FUNC0_EG_MODE_KEEP;
- + else if ((priv->vlan_tagged & BIT(i)) || (priv->vlan_id[priv->pvid[i]] != vid))
- + mode = AR8327_VTU_FUNC0_EG_MODE_TAG;
- + else
- + mode = AR8327_VTU_FUNC0_EG_MODE_UNTAG;
- +
- + val |= mode << AR8327_VTU_FUNC0_EG_MODE_S(i);
- + }
- + ar8327_vtu_op(priv, op, val);
- +}
- +
- +static void
- +ar8327_setup_port(struct ar8xxx_priv *priv, int port, u32 members)
- +{
- + u32 t;
- + u32 egress, ingress;
- + u32 pvid = priv->vlan_id[priv->pvid[port]];
- +
- + if (priv->vlan) {
- + egress = AR8327_PORT_VLAN1_OUT_MODE_UNMOD;
- + ingress = AR8216_IN_SECURE;
- + } else {
- + egress = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH;
- + ingress = AR8216_IN_PORT_ONLY;
- + }
- +
- + t = pvid << AR8327_PORT_VLAN0_DEF_SVID_S;
- + t |= pvid << AR8327_PORT_VLAN0_DEF_CVID_S;
- + ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), t);
- +
- + t = AR8327_PORT_VLAN1_PORT_VLAN_PROP;
- + t |= egress << AR8327_PORT_VLAN1_OUT_MODE_S;
- + ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t);
- +
- + t = members;
- + t |= AR8327_PORT_LOOKUP_LEARN;
- + t |= ingress << AR8327_PORT_LOOKUP_IN_MODE_S;
- + t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S;
- + ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t);
- +}
- +
- +static int
- +ar8327_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + u8 ports = priv->vlan_table[val->port_vlan];
- + int i;
- +
- + val->len = 0;
- + for (i = 0; i < dev->ports; i++) {
- + struct switch_port *p;
- +
- + if (!(ports & (1 << i)))
- + continue;
- +
- + p = &val->value.ports[val->len++];
- + p->id = i;
- + if ((priv->vlan_tagged & (1 << i)) || (priv->pvid[i] != val->port_vlan))
- + p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
- + else
- + p->flags = 0;
- + }
- + return 0;
- +}
- +
- +static int
- +ar8327_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + u8 *vt = &priv->vlan_table[val->port_vlan];
- + int i;
- +
- + *vt = 0;
- + for (i = 0; i < val->len; i++) {
- + struct switch_port *p = &val->value.ports[i];
- +
- + if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
- + if (val->port_vlan == priv->pvid[p->id]) {
- + priv->vlan_tagged |= (1 << p->id);
- + }
- + } else {
- + priv->vlan_tagged &= ~(1 << p->id);
- + priv->pvid[p->id] = val->port_vlan;
- + }
- +
- + *vt |= 1 << p->id;
- + }
- + return 0;
- +}
- +
- +static void
- +ar8327_set_mirror_regs(struct ar8xxx_priv *priv)
- +{
- + int port;
- +
- + /* reset all mirror registers */
- + ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0,
- + AR8327_FWD_CTRL0_MIRROR_PORT,
- + (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S));
- + for (port = 0; port < AR8327_NUM_PORTS; port++) {
- + ar8xxx_reg_clear(priv, AR8327_REG_PORT_LOOKUP(port),
- + AR8327_PORT_LOOKUP_ING_MIRROR_EN);
- +
- + ar8xxx_reg_clear(priv, AR8327_REG_PORT_HOL_CTRL1(port),
- + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN);
- + }
- +
- + /* now enable mirroring if necessary */
- + if (priv->source_port >= AR8327_NUM_PORTS ||
- + priv->monitor_port >= AR8327_NUM_PORTS ||
- + priv->source_port == priv->monitor_port) {
- + return;
- + }
- +
- + ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0,
- + AR8327_FWD_CTRL0_MIRROR_PORT,
- + (priv->monitor_port << AR8327_FWD_CTRL0_MIRROR_PORT_S));
- +
- + if (priv->mirror_rx)
- + ar8xxx_reg_set(priv, AR8327_REG_PORT_LOOKUP(priv->source_port),
- + AR8327_PORT_LOOKUP_ING_MIRROR_EN);
- +
- + if (priv->mirror_tx)
- + ar8xxx_reg_set(priv, AR8327_REG_PORT_HOL_CTRL1(priv->source_port),
- + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN);
- +}
- +
- +static int
- +ar8327_sw_set_eee(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + struct ar8327_data *data = priv->chip_data;
- + int port = val->port_vlan;
- + int phy;
- +
- + if (port >= dev->ports)
- + return -EINVAL;
- + if (port == 0 || port == 6)
- + return -EOPNOTSUPP;
- +
- + phy = port - 1;
- +
- + data->eee[phy] = !!(val->value.i);
- +
- + return 0;
- +}
- +
- +static int
- +ar8327_sw_get_eee(struct switch_dev *dev,
- + const struct switch_attr *attr,
- + struct switch_val *val)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + const struct ar8327_data *data = priv->chip_data;
- + int port = val->port_vlan;
- + int phy;
- +
- + if (port >= dev->ports)
- + return -EINVAL;
- + if (port == 0 || port == 6)
- + return -EOPNOTSUPP;
- +
- + phy = port - 1;
- +
- + val->value.i = data->eee[phy];
- +
- + return 0;
- +}
- +
- +static void
- +ar8327_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1)
- +{
- + int timeout = 20;
- +
- + while (ar8xxx_mii_read32(priv, r2, r1) & AR8327_ATU_FUNC_BUSY && --timeout)
- + udelay(10);
- +
- + if (!timeout)
- + pr_err("ar8327: timeout waiting for atu to become ready\n");
- +}
- +
- +static void ar8327_get_arl_entry(struct ar8xxx_priv *priv,
- + struct arl_entry *a, u32 *status, enum arl_op op)
- +{
- + struct mii_bus *bus = priv->mii_bus;
- + u16 r2, page;
- + u16 r1_data0, r1_data1, r1_data2, r1_func;
- + u32 t, val0, val1, val2;
- + int i;
- +
- + split_addr(AR8327_REG_ATU_DATA0, &r1_data0, &r2, &page);
- + r2 |= 0x10;
- +
- + r1_data1 = (AR8327_REG_ATU_DATA1 >> 1) & 0x1e;
- + r1_data2 = (AR8327_REG_ATU_DATA2 >> 1) & 0x1e;
- + r1_func = (AR8327_REG_ATU_FUNC >> 1) & 0x1e;
- +
- + switch (op) {
- + case AR8XXX_ARL_INITIALIZE:
- + /* all ATU registers are on the same page
- + * therefore set page only once
- + */
- + bus->write(bus, 0x18, 0, page);
- + wait_for_page_switch();
- +
- + ar8327_wait_atu_ready(priv, r2, r1_func);
- +
- + ar8xxx_mii_write32(priv, r2, r1_data0, 0);
- + ar8xxx_mii_write32(priv, r2, r1_data1, 0);
- + ar8xxx_mii_write32(priv, r2, r1_data2, 0);
- + break;
- + case AR8XXX_ARL_GET_NEXT:
- + ar8xxx_mii_write32(priv, r2, r1_func,
- + AR8327_ATU_FUNC_OP_GET_NEXT |
- + AR8327_ATU_FUNC_BUSY);
- + ar8327_wait_atu_ready(priv, r2, r1_func);
- +
- + val0 = ar8xxx_mii_read32(priv, r2, r1_data0);
- + val1 = ar8xxx_mii_read32(priv, r2, r1_data1);
- + val2 = ar8xxx_mii_read32(priv, r2, r1_data2);
- +
- + *status = val2 & AR8327_ATU_STATUS;
- + if (!*status)
- + break;
- +
- + i = 0;
- + t = AR8327_ATU_PORT0;
- + while (!(val1 & t) && ++i < AR8327_NUM_PORTS)
- + t <<= 1;
- +
- + a->port = i;
- + a->mac[0] = (val0 & AR8327_ATU_ADDR0) >> AR8327_ATU_ADDR0_S;
- + a->mac[1] = (val0 & AR8327_ATU_ADDR1) >> AR8327_ATU_ADDR1_S;
- + a->mac[2] = (val0 & AR8327_ATU_ADDR2) >> AR8327_ATU_ADDR2_S;
- + a->mac[3] = (val0 & AR8327_ATU_ADDR3) >> AR8327_ATU_ADDR3_S;
- + a->mac[4] = (val1 & AR8327_ATU_ADDR4) >> AR8327_ATU_ADDR4_S;
- + a->mac[5] = (val1 & AR8327_ATU_ADDR5) >> AR8327_ATU_ADDR5_S;
- + break;
- + }
- +}
- +
- +static int
- +ar8327_sw_hw_apply(struct switch_dev *dev)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + const struct ar8327_data *data = priv->chip_data;
- + int ret, i;
- +
- + ret = ar8xxx_sw_hw_apply(dev);
- + if (ret)
- + return ret;
- +
- + for (i=0; i < AR8XXX_NUM_PHYS; i++) {
- + if (data->eee[i])
- + ar8xxx_reg_clear(priv, AR8327_REG_EEE_CTRL,
- + AR8327_EEE_CTRL_DISABLE_PHY(i));
- + else
- + ar8xxx_reg_set(priv, AR8327_REG_EEE_CTRL,
- + AR8327_EEE_CTRL_DISABLE_PHY(i));
- + }
- +
- + return 0;
- +}
- +
- +static const struct switch_attr ar8327_sw_attr_globals[] = {
- + {
- + .type = SWITCH_TYPE_INT,
- + .name = "enable_vlan",
- + .description = "Enable VLAN mode",
- + .set = ar8xxx_sw_set_vlan,
- + .get = ar8xxx_sw_get_vlan,
- + .max = 1
- + },
- + {
- + .type = SWITCH_TYPE_NOVAL,
- + .name = "reset_mibs",
- + .description = "Reset all MIB counters",
- + .set = ar8xxx_sw_set_reset_mibs,
- + },
- + {
- + .type = SWITCH_TYPE_INT,
- + .name = "enable_mirror_rx",
- + .description = "Enable mirroring of RX packets",
- + .set = ar8xxx_sw_set_mirror_rx_enable,
- + .get = ar8xxx_sw_get_mirror_rx_enable,
- + .max = 1
- + },
- + {
- + .type = SWITCH_TYPE_INT,
- + .name = "enable_mirror_tx",
- + .description = "Enable mirroring of TX packets",
- + .set = ar8xxx_sw_set_mirror_tx_enable,
- + .get = ar8xxx_sw_get_mirror_tx_enable,
- + .max = 1
- + },
- + {
- + .type = SWITCH_TYPE_INT,
- + .name = "mirror_monitor_port",
- + .description = "Mirror monitor port",
- + .set = ar8xxx_sw_set_mirror_monitor_port,
- + .get = ar8xxx_sw_get_mirror_monitor_port,
- + .max = AR8327_NUM_PORTS - 1
- + },
- + {
- + .type = SWITCH_TYPE_INT,
- + .name = "mirror_source_port",
- + .description = "Mirror source port",
- + .set = ar8xxx_sw_set_mirror_source_port,
- + .get = ar8xxx_sw_get_mirror_source_port,
- + .max = AR8327_NUM_PORTS - 1
- + },
- + {
- + .type = SWITCH_TYPE_STRING,
- + .name = "arl_table",
- + .description = "Get ARL table",
- + .set = NULL,
- + .get = ar8xxx_sw_get_arl_table,
- + },
- + {
- + .type = SWITCH_TYPE_NOVAL,
- + .name = "flush_arl_table",
- + .description = "Flush ARL table",
- + .set = ar8xxx_sw_set_flush_arl_table,
- + },
- +};
- +
- +static const struct switch_attr ar8327_sw_attr_port[] = {
- + {
- + .type = SWITCH_TYPE_NOVAL,
- + .name = "reset_mib",
- + .description = "Reset single port MIB counters",
- + .set = ar8xxx_sw_set_port_reset_mib,
- + },
- + {
- + .type = SWITCH_TYPE_STRING,
- + .name = "mib",
- + .description = "Get port's MIB counters",
- + .set = NULL,
- + .get = ar8xxx_sw_get_port_mib,
- + },
- + {
- + .type = SWITCH_TYPE_INT,
- + .name = "enable_eee",
- + .description = "Enable EEE PHY sleep mode",
- + .set = ar8327_sw_set_eee,
- + .get = ar8327_sw_get_eee,
- + .max = 1,
- + },
- + {
- + .type = SWITCH_TYPE_NOVAL,
- + .name = "flush_arl_table",
- + .description = "Flush port's ARL table entries",
- + .set = ar8xxx_sw_set_flush_port_arl_table,
- + },
- +};
- +
- +static const struct switch_dev_ops ar8327_sw_ops = {
- + .attr_global = {
- + .attr = ar8327_sw_attr_globals,
- + .n_attr = ARRAY_SIZE(ar8327_sw_attr_globals),
- + },
- + .attr_port = {
- + .attr = ar8327_sw_attr_port,
- + .n_attr = ARRAY_SIZE(ar8327_sw_attr_port),
- + },
- + .attr_vlan = {
- + .attr = ar8xxx_sw_attr_vlan,
- + .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan),
- + },
- + .get_port_pvid = ar8xxx_sw_get_pvid,
- + .set_port_pvid = ar8xxx_sw_set_pvid,
- + .get_vlan_ports = ar8327_sw_get_ports,
- + .set_vlan_ports = ar8327_sw_set_ports,
- + .apply_config = ar8327_sw_hw_apply,
- + .reset_switch = ar8xxx_sw_reset_switch,
- + .get_port_link = ar8xxx_sw_get_port_link,
- +};
- +
- +const struct ar8xxx_chip ar8327_chip = {
- + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS,
- + .config_at_probe = true,
- + .mii_lo_first = true,
- +
- + .name = "Atheros AR8327",
- + .ports = AR8327_NUM_PORTS,
- + .vlans = AR8X16_MAX_VLANS,
- + .swops = &ar8327_sw_ops,
- +
- + .reg_port_stats_start = 0x1000,
- + .reg_port_stats_length = 0x100,
- +
- + .hw_init = ar8327_hw_init,
- + .cleanup = ar8327_cleanup,
- + .init_globals = ar8327_init_globals,
- + .init_port = ar8327_init_port,
- + .setup_port = ar8327_setup_port,
- + .read_port_status = ar8327_read_port_status,
- + .read_port_eee_status = ar8327_read_port_eee_status,
- + .atu_flush = ar8327_atu_flush,
- + .atu_flush_port = ar8327_atu_flush_port,
- + .vtu_flush = ar8327_vtu_flush,
- + .vtu_load_vlan = ar8327_vtu_load_vlan,
- + .phy_fixup = ar8327_phy_fixup,
- + .set_mirror_regs = ar8327_set_mirror_regs,
- + .get_arl_entry = ar8327_get_arl_entry,
- + .sw_hw_apply = ar8327_sw_hw_apply,
- +
- + .num_mibs = ARRAY_SIZE(ar8236_mibs),
- + .mib_decs = ar8236_mibs,
- + .mib_func = AR8327_REG_MIB_FUNC
- +};
- +
- +const struct ar8xxx_chip ar8337_chip = {
- + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS,
- + .config_at_probe = true,
- + .mii_lo_first = true,
- +
- + .name = "Atheros AR8337",
- + .ports = AR8327_NUM_PORTS,
- + .vlans = AR8X16_MAX_VLANS,
- + .swops = &ar8327_sw_ops,
- +
- + .reg_port_stats_start = 0x1000,
- + .reg_port_stats_length = 0x100,
- +
- + .hw_init = ar8327_hw_init,
- + .cleanup = ar8327_cleanup,
- + .init_globals = ar8327_init_globals,
- + .init_port = ar8327_init_port,
- + .setup_port = ar8327_setup_port,
- + .read_port_status = ar8327_read_port_status,
- + .read_port_eee_status = ar8327_read_port_eee_status,
- + .atu_flush = ar8327_atu_flush,
- + .atu_flush_port = ar8327_atu_flush_port,
- + .vtu_flush = ar8327_vtu_flush,
- + .vtu_load_vlan = ar8327_vtu_load_vlan,
- + .phy_fixup = ar8327_phy_fixup,
- + .set_mirror_regs = ar8327_set_mirror_regs,
- + .get_arl_entry = ar8327_get_arl_entry,
- + .sw_hw_apply = ar8327_sw_hw_apply,
- +
- + .num_mibs = ARRAY_SIZE(ar8236_mibs),
- + .mib_decs = ar8236_mibs,
- + .mib_func = AR8327_REG_MIB_FUNC
- +};
- +
- diff -Nur linux-4.1.6.orig/drivers/net/phy/ar8327.h linux-4.1.6/drivers/net/phy/ar8327.h
- --- linux-4.1.6.orig/drivers/net/phy/ar8327.h 1970-01-01 01:00:00.000000000 +0100
- +++ linux-4.1.6/drivers/net/phy/ar8327.h 2015-09-13 22:55:18.331373990 +0200
- @@ -0,0 +1,252 @@
- +/*
- + * ar8327.h: AR8216 switch driver
- + *
- + * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
- + *
- + * 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 2
- + * of the License, or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + */
- +
- +#ifndef __AR8327_H
- +#define __AR8327_H
- +
- +#define AR8327_NUM_PORTS 7
- +#define AR8327_NUM_LEDS 15
- +#define AR8327_PORTS_ALL 0x7f
- +#define AR8327_NUM_LED_CTRL_REGS 4
- +
- +#define AR8327_REG_MASK 0x000
- +
- +#define AR8327_REG_PAD0_MODE 0x004
- +#define AR8327_REG_PAD5_MODE 0x008
- +#define AR8327_REG_PAD6_MODE 0x00c
- +#define AR8327_PAD_MAC_MII_RXCLK_SEL BIT(0)
- +#define AR8327_PAD_MAC_MII_TXCLK_SEL BIT(1)
- +#define AR8327_PAD_MAC_MII_EN BIT(2)
- +#define AR8327_PAD_MAC_GMII_RXCLK_SEL BIT(4)
- +#define AR8327_PAD_MAC_GMII_TXCLK_SEL BIT(5)
- +#define AR8327_PAD_MAC_GMII_EN BIT(6)
- +#define AR8327_PAD_SGMII_EN BIT(7)
- +#define AR8327_PAD_PHY_MII_RXCLK_SEL BIT(8)
- +#define AR8327_PAD_PHY_MII_TXCLK_SEL BIT(9)
- +#define AR8327_PAD_PHY_MII_EN BIT(10)
- +#define AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL BIT(11)
- +#define AR8327_PAD_PHY_GMII_RXCLK_SEL BIT(12)
- +#define AR8327_PAD_PHY_GMII_TXCLK_SEL BIT(13)
- +#define AR8327_PAD_PHY_GMII_EN BIT(14)
- +#define AR8327_PAD_PHYX_GMII_EN BIT(16)
- +#define AR8327_PAD_PHYX_RGMII_EN BIT(17)
- +#define AR8327_PAD_PHYX_MII_EN BIT(18)
- +#define AR8327_PAD_SGMII_DELAY_EN BIT(19)
- +#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL BITS(20, 2)
- +#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S 20
- +#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL BITS(22, 2)
- +#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S 22
- +#define AR8327_PAD_RGMII_RXCLK_DELAY_EN BIT(24)
- +#define AR8327_PAD_RGMII_TXCLK_DELAY_EN BIT(25)
- +#define AR8327_PAD_RGMII_EN BIT(26)
- +
- +#define AR8327_REG_POWER_ON_STRIP 0x010
- +#define AR8327_POWER_ON_STRIP_POWER_ON_SEL BIT(31)
- +#define AR8327_POWER_ON_STRIP_LED_OPEN_EN BIT(24)
- +#define AR8327_POWER_ON_STRIP_SERDES_AEN BIT(7)
- +
- +#define AR8327_REG_INT_STATUS0 0x020
- +#define AR8327_INT0_VT_DONE BIT(20)
- +
- +#define AR8327_REG_INT_STATUS1 0x024
- +#define AR8327_REG_INT_MASK0 0x028
- +#define AR8327_REG_INT_MASK1 0x02c
- +
- +#define AR8327_REG_MODULE_EN 0x030
- +#define AR8327_MODULE_EN_MIB BIT(0)
- +
- +#define AR8327_REG_MIB_FUNC 0x034
- +#define AR8327_MIB_CPU_KEEP BIT(20)
- +
- +#define AR8327_REG_SERVICE_TAG 0x048
- +#define AR8327_REG_LED_CTRL(_i) (0x050 + (_i) * 4)
- +#define AR8327_REG_LED_CTRL0 0x050
- +#define AR8327_REG_LED_CTRL1 0x054
- +#define AR8327_REG_LED_CTRL2 0x058
- +#define AR8327_REG_LED_CTRL3 0x05c
- +#define AR8327_REG_MAC_ADDR0 0x060
- +#define AR8327_REG_MAC_ADDR1 0x064
- +
- +#define AR8327_REG_MAX_FRAME_SIZE 0x078
- +#define AR8327_MAX_FRAME_SIZE_MTU BITS(0, 14)
- +
- +#define AR8327_REG_PORT_STATUS(_i) (0x07c + (_i) * 4)
- +#define AR8327_PORT_STATUS_TXFLOW_AUTO BIT(10)
- +#define AR8327_PORT_STATUS_RXFLOW_AUTO BIT(11)
- +
- +#define AR8327_REG_HEADER_CTRL 0x098
- +#define AR8327_REG_PORT_HEADER(_i) (0x09c + (_i) * 4)
- +
- +#define AR8327_REG_SGMII_CTRL 0x0e0
- +#define AR8327_SGMII_CTRL_EN_PLL BIT(1)
- +#define AR8327_SGMII_CTRL_EN_RX BIT(2)
- +#define AR8327_SGMII_CTRL_EN_TX BIT(3)
- +
- +#define AR8327_REG_EEE_CTRL 0x100
- +#define AR8327_EEE_CTRL_DISABLE_PHY(_i) BIT(4 + (_i) * 2)
- +
- +#define AR8327_REG_PORT_VLAN0(_i) (0x420 + (_i) * 0x8)
- +#define AR8327_PORT_VLAN0_DEF_SVID BITS(0, 12)
- +#define AR8327_PORT_VLAN0_DEF_SVID_S 0
- +#define AR8327_PORT_VLAN0_DEF_CVID BITS(16, 12)
- +#define AR8327_PORT_VLAN0_DEF_CVID_S 16
- +
- +#define AR8327_REG_PORT_VLAN1(_i) (0x424 + (_i) * 0x8)
- +#define AR8327_PORT_VLAN1_PORT_VLAN_PROP BIT(6)
- +#define AR8327_PORT_VLAN1_OUT_MODE BITS(12, 2)
- +#define AR8327_PORT_VLAN1_OUT_MODE_S 12
- +#define AR8327_PORT_VLAN1_OUT_MODE_UNMOD 0
- +#define AR8327_PORT_VLAN1_OUT_MODE_UNTAG 1
- +#define AR8327_PORT_VLAN1_OUT_MODE_TAG 2
- +#define AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH 3
- +
- +#define AR8327_REG_ATU_DATA0 0x600
- +#define AR8327_ATU_ADDR0 BITS(0, 8)
- +#define AR8327_ATU_ADDR0_S 0
- +#define AR8327_ATU_ADDR1 BITS(8, 8)
- +#define AR8327_ATU_ADDR1_S 8
- +#define AR8327_ATU_ADDR2 BITS(16, 8)
- +#define AR8327_ATU_ADDR2_S 16
- +#define AR8327_ATU_ADDR3 BITS(24, 8)
- +#define AR8327_ATU_ADDR3_S 24
- +#define AR8327_REG_ATU_DATA1 0x604
- +#define AR8327_ATU_ADDR4 BITS(0, 8)
- +#define AR8327_ATU_ADDR4_S 0
- +#define AR8327_ATU_ADDR5 BITS(8, 8)
- +#define AR8327_ATU_ADDR5_S 8
- +#define AR8327_ATU_PORTS BITS(16, 7)
- +#define AR8327_ATU_PORT0 BIT(16)
- +#define AR8327_ATU_PORT1 BIT(17)
- +#define AR8327_ATU_PORT2 BIT(18)
- +#define AR8327_ATU_PORT3 BIT(19)
- +#define AR8327_ATU_PORT4 BIT(20)
- +#define AR8327_ATU_PORT5 BIT(21)
- +#define AR8327_ATU_PORT6 BIT(22)
- +#define AR8327_REG_ATU_DATA2 0x608
- +#define AR8327_ATU_STATUS BITS(0, 4)
- +
- +#define AR8327_REG_ATU_FUNC 0x60c
- +#define AR8327_ATU_FUNC_OP BITS(0, 4)
- +#define AR8327_ATU_FUNC_OP_NOOP 0x0
- +#define AR8327_ATU_FUNC_OP_FLUSH 0x1
- +#define AR8327_ATU_FUNC_OP_LOAD 0x2
- +#define AR8327_ATU_FUNC_OP_PURGE 0x3
- +#define AR8327_ATU_FUNC_OP_FLUSH_UNLOCKED 0x4
- +#define AR8327_ATU_FUNC_OP_FLUSH_PORT 0x5
- +#define AR8327_ATU_FUNC_OP_GET_NEXT 0x6
- +#define AR8327_ATU_FUNC_OP_SEARCH_MAC 0x7
- +#define AR8327_ATU_FUNC_OP_CHANGE_TRUNK 0x8
- +#define AR8327_ATU_PORT_NUM BITS(8, 4)
- +#define AR8327_ATU_PORT_NUM_S 8
- +#define AR8327_ATU_FUNC_BUSY BIT(31)
- +
- +#define AR8327_REG_VTU_FUNC0 0x0610
- +#define AR8327_VTU_FUNC0_EG_MODE BITS(4, 14)
- +#define AR8327_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2)
- +#define AR8327_VTU_FUNC0_EG_MODE_KEEP 0
- +#define AR8327_VTU_FUNC0_EG_MODE_UNTAG 1
- +#define AR8327_VTU_FUNC0_EG_MODE_TAG 2
- +#define AR8327_VTU_FUNC0_EG_MODE_NOT 3
- +#define AR8327_VTU_FUNC0_IVL BIT(19)
- +#define AR8327_VTU_FUNC0_VALID BIT(20)
- +
- +#define AR8327_REG_VTU_FUNC1 0x0614
- +#define AR8327_VTU_FUNC1_OP BITS(0, 3)
- +#define AR8327_VTU_FUNC1_OP_NOOP 0
- +#define AR8327_VTU_FUNC1_OP_FLUSH 1
- +#define AR8327_VTU_FUNC1_OP_LOAD 2
- +#define AR8327_VTU_FUNC1_OP_PURGE 3
- +#define AR8327_VTU_FUNC1_OP_REMOVE_PORT 4
- +#define AR8327_VTU_FUNC1_OP_GET_NEXT 5
- +#define AR8327_VTU_FUNC1_OP_GET_ONE 6
- +#define AR8327_VTU_FUNC1_FULL BIT(4)
- +#define AR8327_VTU_FUNC1_PORT BIT(8, 4)
- +#define AR8327_VTU_FUNC1_PORT_S 8
- +#define AR8327_VTU_FUNC1_VID BIT(16, 12)
- +#define AR8327_VTU_FUNC1_VID_S 16
- +#define AR8327_VTU_FUNC1_BUSY BIT(31)
- +
- +#define AR8327_REG_FWD_CTRL0 0x620
- +#define AR8327_FWD_CTRL0_CPU_PORT_EN BIT(10)
- +#define AR8327_FWD_CTRL0_MIRROR_PORT BITS(4, 4)
- +#define AR8327_FWD_CTRL0_MIRROR_PORT_S 4
- +
- +#define AR8327_REG_FWD_CTRL1 0x624
- +#define AR8327_FWD_CTRL1_UC_FLOOD BITS(0, 7)
- +#define AR8327_FWD_CTRL1_UC_FLOOD_S 0
- +#define AR8327_FWD_CTRL1_MC_FLOOD BITS(8, 7)
- +#define AR8327_FWD_CTRL1_MC_FLOOD_S 8
- +#define AR8327_FWD_CTRL1_BC_FLOOD BITS(16, 7)
- +#define AR8327_FWD_CTRL1_BC_FLOOD_S 16
- +#define AR8327_FWD_CTRL1_IGMP BITS(24, 7)
- +#define AR8327_FWD_CTRL1_IGMP_S 24
- +
- +#define AR8327_REG_PORT_LOOKUP(_i) (0x660 + (_i) * 0xc)
- +#define AR8327_PORT_LOOKUP_MEMBER BITS(0, 7)
- +#define AR8327_PORT_LOOKUP_IN_MODE BITS(8, 2)
- +#define AR8327_PORT_LOOKUP_IN_MODE_S 8
- +#define AR8327_PORT_LOOKUP_STATE BITS(16, 3)
- +#define AR8327_PORT_LOOKUP_STATE_S 16
- +#define AR8327_PORT_LOOKUP_LEARN BIT(20)
- +#define AR8327_PORT_LOOKUP_ING_MIRROR_EN BIT(25)
- +
- +#define AR8327_REG_PORT_PRIO(_i) (0x664 + (_i) * 0xc)
- +
- +#define AR8327_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8)
- +#define AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16)
- +
- +#define AR8337_PAD_MAC06_EXCHANGE_EN BIT(31)
- +
- +enum ar8327_led_pattern {
- + AR8327_LED_PATTERN_OFF = 0,
- + AR8327_LED_PATTERN_BLINK,
- + AR8327_LED_PATTERN_ON,
- + AR8327_LED_PATTERN_RULE,
- +};
- +
- +struct ar8327_led_entry {
- + unsigned reg;
- + unsigned shift;
- +};
- +
- +struct ar8327_led {
- + struct led_classdev cdev;
- + struct ar8xxx_priv *sw_priv;
- +
- + char *name;
- + bool active_low;
- + u8 led_num;
- + enum ar8327_led_mode mode;
- +
- + struct mutex mutex;
- + spinlock_t lock;
- + struct work_struct led_work;
- + bool enable_hw_mode;
- + enum ar8327_led_pattern pattern;
- +};
- +
- +struct ar8327_data {
- + u32 port0_status;
- + u32 port6_status;
- +
- + struct ar8327_led **leds;
- + unsigned int num_leds;
- +
- + /* all fields below are cleared on reset */
- + bool eee[AR8XXX_NUM_PHYS];
- +};
- +
- +#endif
- diff -Nur linux-4.1.6.orig/drivers/net/phy/Kconfig linux-4.1.6/drivers/net/phy/Kconfig
- --- linux-4.1.6.orig/drivers/net/phy/Kconfig 2015-08-17 05:52:51.000000000 +0200
- +++ linux-4.1.6/drivers/net/phy/Kconfig 2015-09-13 22:33:30.867723129 +0200
- @@ -119,6 +119,15 @@
- ---help---
- Supports the KSZ9021, VSC8201, KS8001 PHYs.
-
- +config AR8216_PHY
- + tristate "Driver for Atheros AR8216 switches"
- + select ETHERNET_PACKET_MANGLE
- + select SWCONFIG
- +
- +config AR8216_PHY_LEDS
- + bool "Atheros AR8216 switch LED support"
- + depends on (AR8216_PHY && LEDS_CLASS)
- +
- config FIXED_PHY
- tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
- depends on PHYLIB
- diff -Nur linux-4.1.6.orig/drivers/net/phy/Makefile linux-4.1.6/drivers/net/phy/Makefile
- --- linux-4.1.6.orig/drivers/net/phy/Makefile 2015-08-17 05:52:51.000000000 +0200
- +++ linux-4.1.6/drivers/net/phy/Makefile 2015-09-13 22:55:35.466351180 +0200
- @@ -16,6 +16,7 @@
- obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o
- obj-$(CONFIG_ICPLUS_PHY) += icplus.o
- obj-$(CONFIG_REALTEK_PHY) += realtek.o
- +obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o
- obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
- obj-$(CONFIG_FIXED_PHY) += fixed_phy.o
- obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
- diff -Nur linux-4.1.6.orig/include/linux/ar8216_platform.h linux-4.1.6/include/linux/ar8216_platform.h
- --- linux-4.1.6.orig/include/linux/ar8216_platform.h 1970-01-01 01:00:00.000000000 +0100
- +++ linux-4.1.6/include/linux/ar8216_platform.h 2015-09-13 22:33:30.871722898 +0200
- @@ -0,0 +1,133 @@
- +/*
- + * AR8216 switch driver platform data
- + *
- + * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
- + *
- + * 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 2
- + * of the License, or (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + */
- +
- +#ifndef AR8216_PLATFORM_H
- +#define AR8216_PLATFORM_H
- +
- +enum ar8327_pad_mode {
- + AR8327_PAD_NC = 0,
- + AR8327_PAD_MAC2MAC_MII,
- + AR8327_PAD_MAC2MAC_GMII,
- + AR8327_PAD_MAC_SGMII,
- + AR8327_PAD_MAC2PHY_MII,
- + AR8327_PAD_MAC2PHY_GMII,
- + AR8327_PAD_MAC_RGMII,
- + AR8327_PAD_PHY_GMII,
- + AR8327_PAD_PHY_RGMII,
- + AR8327_PAD_PHY_MII,
- +};
- +
- +enum ar8327_clk_delay_sel {
- + AR8327_CLK_DELAY_SEL0 = 0,
- + AR8327_CLK_DELAY_SEL1,
- + AR8327_CLK_DELAY_SEL2,
- + AR8327_CLK_DELAY_SEL3,
- +};
- +
- +struct ar8327_pad_cfg {
- + enum ar8327_pad_mode mode;
- + bool rxclk_sel;
- + bool txclk_sel;
- + bool pipe_rxclk_sel;
- + bool txclk_delay_en;
- + bool rxclk_delay_en;
- + bool sgmii_delay_en;
- + enum ar8327_clk_delay_sel txclk_delay_sel;
- + enum ar8327_clk_delay_sel rxclk_delay_sel;
- + bool mac06_exchange_en;
- +};
- +
- +enum ar8327_port_speed {
- + AR8327_PORT_SPEED_10 = 0,
- + AR8327_PORT_SPEED_100,
- + AR8327_PORT_SPEED_1000,
- +};
- +
- +struct ar8327_port_cfg {
- + int force_link:1;
- + enum ar8327_port_speed speed;
- + int txpause:1;
- + int rxpause:1;
- + int duplex:1;
- +};
- +
- +struct ar8327_sgmii_cfg {
- + u32 sgmii_ctrl;
- + bool serdes_aen;
- +};
- +
- +struct ar8327_led_cfg {
- + u32 led_ctrl0;
- + u32 led_ctrl1;
- + u32 led_ctrl2;
- + u32 led_ctrl3;
- + bool open_drain;
- +};
- +
- +enum ar8327_led_num {
- + AR8327_LED_PHY0_0 = 0,
- + AR8327_LED_PHY0_1,
- + AR8327_LED_PHY0_2,
- + AR8327_LED_PHY1_0,
- + AR8327_LED_PHY1_1,
- + AR8327_LED_PHY1_2,
- + AR8327_LED_PHY2_0,
- + AR8327_LED_PHY2_1,
- + AR8327_LED_PHY2_2,
- + AR8327_LED_PHY3_0,
- + AR8327_LED_PHY3_1,
- + AR8327_LED_PHY3_2,
- + AR8327_LED_PHY4_0,
- + AR8327_LED_PHY4_1,
- + AR8327_LED_PHY4_2,
- +};
- +
- +enum ar8327_led_mode {
- + AR8327_LED_MODE_HW = 0,
- + AR8327_LED_MODE_SW,
- +};
- +
- +struct ar8327_led_info {
- + const char *name;
- + const char *default_trigger;
- + bool active_low;
- + enum ar8327_led_num led_num;
- + enum ar8327_led_mode mode;
- +};
- +
- +#define AR8327_LED_INFO(_led, _mode, _name) { \
- + .name = (_name), \
- + .led_num = AR8327_LED_ ## _led, \
- + .mode = AR8327_LED_MODE_ ## _mode \
- +}
- +
- +struct ar8327_platform_data {
- + struct ar8327_pad_cfg *pad0_cfg;
- + struct ar8327_pad_cfg *pad5_cfg;
- + struct ar8327_pad_cfg *pad6_cfg;
- + struct ar8327_sgmii_cfg *sgmii_cfg;
- + struct ar8327_port_cfg port0_cfg;
- + struct ar8327_port_cfg port6_cfg;
- + struct ar8327_led_cfg *led_cfg;
- +
- + int (*get_port_link)(unsigned port);
- +
- + unsigned num_leds;
- + const struct ar8327_led_info *leds;
- +};
- +
- +#endif /* AR8216_PLATFORM_H */
- +
|