12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671 |
- From 6137bedf972f576765c6e5d4373a488951371609 Mon Sep 17 00:00:00 2001
- From: Phil Sutter <phil@nwl.cc>
- Date: Tue, 13 May 2014 00:37:30 +0200
- Subject: [PATCH] phy: add ar8216 PHY support
- ---
- drivers/net/phy/Kconfig | 9 +
- drivers/net/phy/Makefile | 1 +
- drivers/net/phy/ar8216.c | 2978 +++++++++++++++++++++++++++++++++++++++
- drivers/net/phy/ar8216.h | 492 +++++++
- include/linux/ar8216_platform.h | 131 ++
- 5 files changed, 3611 insertions(+)
- create mode 100644 drivers/net/phy/ar8216.c
- create mode 100644 drivers/net/phy/ar8216.h
- create mode 100644 include/linux/ar8216_platform.h
- diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
- index 36a13fc..0414889 100644
- --- a/drivers/net/phy/Kconfig
- +++ b/drivers/net/phy/Kconfig
- @@ -116,6 +116,15 @@ config MICREL_PHY
- ---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
- bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
- depends on PHYLIB=y
- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
- index b510bd6..3c76ff8 100644
- --- a/drivers/net/phy/Makefile
- +++ b/drivers/net/phy/Makefile
- @@ -16,6 +16,7 @@ obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
- obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o
- obj-$(CONFIG_ICPLUS_PHY) += icplus.o
- obj-$(CONFIG_REALTEK_PHY) += realtek.o
- +obj-$(CONFIG_AR8216_PHY) += ar8216.o
- obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
- obj-$(CONFIG_FIXED_PHY) += fixed.o
- obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
- diff --git a/drivers/net/phy/ar8216.c b/drivers/net/phy/ar8216.c
- new file mode 100644
- index 0000000..3f60878
- --- /dev/null
- +++ b/drivers/net/phy/ar8216.c
- @@ -0,0 +1,2978 @@
- +/*
- + * 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/of_device.h>
- +#include <linux/leds.h>
- +#include <linux/gpio.h>
- +
- +#include "ar8216.h"
- +
- +/* size of the vlan table */
- +#define AR8X16_MAX_VLANS 128
- +#define AR8X16_PROBE_RETRIES 10
- +#define AR8X16_MAX_PORTS 8
- +
- +#define AR8XXX_MIB_WORK_DELAY 2000 /* msecs */
- +
- +struct ar8xxx_priv;
- +
- +#define AR8XXX_CAP_GIGE BIT(0)
- +#define AR8XXX_CAP_MIB_COUNTERS BIT(1)
- +
- +enum {
- + AR8XXX_VER_AR8216 = 0x01,
- + AR8XXX_VER_AR8236 = 0x03,
- + AR8XXX_VER_AR8316 = 0x10,
- + AR8XXX_VER_AR8327 = 0x12,
- + AR8XXX_VER_AR8337 = 0x13,
- +};
- +
- +struct ar8xxx_mib_desc {
- + unsigned int size;
- + unsigned int offset;
- + const char *name;
- +};
- +
- +struct ar8xxx_chip {
- + unsigned long caps;
- +
- + int (*hw_init)(struct ar8xxx_priv *priv);
- + void (*cleanup)(struct ar8xxx_priv *priv);
- +
- + 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 egress,
- + u32 ingress, u32 members, u32 pvid);
- + u32 (*read_port_status)(struct ar8xxx_priv *priv, int port);
- + int (*atu_flush)(struct ar8xxx_priv *priv);
- + void (*vtu_flush)(struct ar8xxx_priv *priv);
- + void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask);
- +
- + const struct ar8xxx_mib_desc *mib_decs;
- + unsigned num_mibs;
- +};
- +
- +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;
- +};
- +
- +struct ar8xxx_priv {
- + struct switch_dev dev;
- + struct mii_bus *mii_bus;
- + struct phy_device *phy;
- +
- + u32 (*read)(struct ar8xxx_priv *priv, int reg);
- + void (*write)(struct ar8xxx_priv *priv, int reg, u32 val);
- + u32 (*rmw)(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
- +
- + 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;
- + union {
- + struct ar8327_data ar8327;
- + } chip_data;
- + bool initialized;
- + bool port4_phy;
- + char buf[2048];
- +
- + bool init;
- + bool mii_lo_first;
- +
- + 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;
- +};
- +
- +#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"),
- +};
- +
- +static const struct ar8xxx_mib_desc ar8236_mibs[] = {
- + 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);
- +
- +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
- +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 u32
- +ar8xxx_mii_read(struct ar8xxx_priv *priv, int reg)
- +{
- + struct mii_bus *bus = priv->mii_bus;
- + u16 r1, r2, page;
- + u16 lo, hi;
- +
- + split_addr((u32) reg, &r1, &r2, &page);
- +
- + mutex_lock(&bus->mdio_lock);
- +
- + bus->write(bus, 0x18, 0, page);
- + usleep_range(1000, 2000); /* wait for the page switch to propagate */
- + lo = bus->read(bus, 0x10 | r2, r1);
- + hi = bus->read(bus, 0x10 | r2, r1 + 1);
- +
- + mutex_unlock(&bus->mdio_lock);
- +
- + return (hi << 16) | lo;
- +}
- +
- +static void
- +ar8xxx_mii_write(struct ar8xxx_priv *priv, int reg, u32 val)
- +{
- + struct mii_bus *bus = priv->mii_bus;
- + u16 r1, r2, r3;
- + u16 lo, hi;
- +
- + split_addr((u32) reg, &r1, &r2, &r3);
- + lo = val & 0xffff;
- + hi = (u16) (val >> 16);
- +
- + mutex_lock(&bus->mdio_lock);
- +
- + bus->write(bus, 0x18, 0, r3);
- + usleep_range(1000, 2000); /* wait for the page switch to propagate */
- + if (priv->mii_lo_first) {
- + bus->write(bus, 0x10 | r2, r1, lo);
- + bus->write(bus, 0x10 | r2, r1 + 1, hi);
- + } else {
- + bus->write(bus, 0x10 | r2, r1 + 1, hi);
- + bus->write(bus, 0x10 | r2, r1, lo);
- + }
- +
- + mutex_unlock(&bus->mdio_lock);
- +}
- +
- +static u32
- +ar8xxx_mii_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
- +{
- + struct mii_bus *bus = priv->mii_bus;
- + u16 r1, r2, page;
- + u16 lo, hi;
- + u32 ret;
- +
- + split_addr((u32) reg, &r1, &r2, &page);
- +
- + mutex_lock(&bus->mdio_lock);
- +
- + bus->write(bus, 0x18, 0, page);
- + usleep_range(1000, 2000); /* wait for the page switch to propagate */
- +
- + lo = bus->read(bus, 0x10 | r2, r1);
- + hi = bus->read(bus, 0x10 | r2, r1 + 1);
- +
- + ret = hi << 16 | lo;
- + ret &= ~mask;
- + ret |= val;
- +
- + lo = ret & 0xffff;
- + hi = (u16) (ret >> 16);
- +
- + if (priv->mii_lo_first) {
- + bus->write(bus, 0x10 | r2, r1, lo);
- + bus->write(bus, 0x10 | r2, r1 + 1, hi);
- + } else {
- + bus->write(bus, 0x10 | r2, r1 + 1, hi);
- + bus->write(bus, 0x10 | r2, r1, lo);
- + }
- +
- + mutex_unlock(&bus->mdio_lock);
- +
- + return ret;
- +}
- +
- +
- +static 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);
- +}
- +
- +static 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);
- +}
- +
- +static inline u32
- +ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
- +{
- + return priv->rmw(priv, reg, mask, val);
- +}
- +
- +static inline void
- +ar8xxx_reg_set(struct ar8xxx_priv *priv, int reg, u32 val)
- +{
- + priv->rmw(priv, reg, 0, val);
- +}
- +
- +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 = priv->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;
- + int ret;
- +
- + lockdep_assert_held(&priv->mib_lock);
- +
- + if (chip_is_ar8327(priv) || chip_is_ar8337(priv))
- + mib_func = AR8327_REG_MIB_FUNC;
- + else
- + mib_func = AR8216_REG_MIB_FUNC;
- +
- + /* 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);
- +
- + if (chip_is_ar8327(priv) || chip_is_ar8337(priv))
- + base = AR8327_REG_PORT_STATS_BASE(port);
- + else if (chip_is_ar8236(priv) ||
- + chip_is_ar8316(priv))
- + base = AR8236_REG_PORT_STATS_BASE(port);
- + else
- + base = AR8216_REG_PORT_STATS_BASE(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 = priv->read(priv, base + mib->offset);
- + if (mib->size == 2) {
- + u64 hi;
- +
- + hi = priv->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);
- +
- + 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;
- +}
- +
- +static int
- +ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
- +{
- + int timeout = 20;
- + u32 t = 0;
- +
- + while (1) {
- + t = priv->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;
- + priv->write(priv, AR8216_REG_VTU_DATA, val);
- + }
- + op |= AR8216_VTU_ACTIVE;
- + priv->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, AR8216_ATU_ACTIVE, 0);
- + if (!ret)
- + priv->write(priv, AR8216_REG_ATU, AR8216_ATU_OP_FLUSH);
- +
- + return ret;
- +}
- +
- +static u32
- +ar8216_read_port_status(struct ar8xxx_priv *priv, int port)
- +{
- + return priv->read(priv, AR8216_REG_PORT_STATUS(port));
- +}
- +
- +static void
- +ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 egress, u32 ingress,
- + u32 members, u32 pvid)
- +{
- + u32 header;
- +
- + 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)
- +{
- + return 0;
- +}
- +
- +static void
- +ar8216_init_globals(struct ar8xxx_priv *priv)
- +{
- + /* standard atheros magic */
- + priv->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 */
- + priv->write(priv, AR8216_REG_PORT_CTRL(port),
- + AR8216_PORT_CTRL_LEARN |
- + (4 << AR8216_PORT_CTRL_STATE_S));
- +
- + priv->write(priv, AR8216_REG_PORT_VLAN(port), 0);
- +
- + if (port == AR8216_PORT_CPU) {
- + priv->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 {
- + priv->write(priv, AR8216_REG_PORT_STATUS(port),
- + AR8216_PORT_STATUS_LINK_AUTO);
- + }
- +}
- +
- +static const struct ar8xxx_chip ar8216_chip = {
- + .caps = AR8XXX_CAP_MIB_COUNTERS,
- +
- + .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,
- + .vtu_flush = ar8216_vtu_flush,
- + .vtu_load_vlan = ar8216_vtu_load_vlan,
- +
- + .num_mibs = ARRAY_SIZE(ar8216_mibs),
- + .mib_decs = ar8216_mibs,
- +};
- +
- +static void
- +ar8236_setup_port(struct ar8xxx_priv *priv, int port, u32 egress, u32 ingress,
- + u32 members, u32 pvid)
- +{
- + 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 int
- +ar8236_hw_init(struct ar8xxx_priv *priv)
- +{
- + int i;
- + struct mii_bus *bus;
- +
- + if (priv->initialized)
- + return 0;
- +
- + /* Initialize the PHYs */
- + bus = priv->mii_bus;
- + for (i = 0; i < 5; i++) {
- + mdiobus_write(bus, i, MII_ADVERTISE,
- + ADVERTISE_ALL | ADVERTISE_PAUSE_CAP |
- + ADVERTISE_PAUSE_ASYM);
- + mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
- + }
- + msleep(1000);
- +
- + priv->initialized = true;
- + return 0;
- +}
- +
- +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 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 const struct ar8xxx_chip ar8236_chip = {
- + .caps = AR8XXX_CAP_MIB_COUNTERS,
- + .hw_init = ar8236_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,
- + .vtu_flush = ar8216_vtu_flush,
- + .vtu_load_vlan = ar8216_vtu_load_vlan,
- +
- + .num_mibs = ARRAY_SIZE(ar8236_mibs),
- + .mib_decs = ar8236_mibs,
- +};
- +
- +static int
- +ar8316_hw_init(struct ar8xxx_priv *priv)
- +{
- + int i;
- + u32 val, newval;
- + struct mii_bus *bus;
- +
- + val = priv->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;
- +
- + priv->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);
- + }
- +
- + /* Initialize the ports */
- + bus = priv->mii_bus;
- + for (i = 0; i < 5; i++) {
- + /* initialize the port itself */
- + mdiobus_write(bus, i, MII_ADVERTISE,
- + ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
- + mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL);
- + mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
- + }
- +
- + msleep(1000);
- +
- +out:
- + priv->initialized = true;
- + return 0;
- +}
- +
- +static void
- +ar8316_init_globals(struct ar8xxx_priv *priv)
- +{
- + /* standard atheros magic */
- + priv->write(priv, 0x38, 0xc000050e);
- +
- + /* enable cpu port to receive multicast and broadcast frames */
- + priv->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);
- +}
- +
- +static const struct ar8xxx_chip ar8316_chip = {
- + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS,
- + .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,
- + .vtu_flush = ar8216_vtu_flush,
- + .vtu_load_vlan = ar8216_vtu_load_vlan,
- +
- + .num_mibs = ARRAY_SIZE(ar8236_mibs),
- + .mib_decs = ar8236_mibs,
- +};
- +
- +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;
- + }
- +
- + 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 ar8xxx_priv *priv, 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.ar8327;
- + 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(priv, 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;
- + unsigned i;
- +
- + if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS))
- + return;
- +
- + data = &priv->chip_data.ar8327;
- +
- + 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.ar8327;
- + 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;
- + u32 pos, new_pos;
- + u32 t;
- +
- + if (!pdata)
- + return -EINVAL;
- +
- + priv->get_port_link = pdata->get_port_link;
- +
- + data = &priv->chip_data.ar8327;
- +
- + 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);
- + if (chip_is_ar8337(priv))
- + t |= AR8337_PAD_MAC06_EXCHANGE_EN;
- +
- + priv->write(priv, AR8327_REG_PAD0_MODE, t);
- + t = ar8327_get_pad_cfg(pdata->pad5_cfg);
- + priv->write(priv, AR8327_REG_PAD5_MODE, t);
- + t = ar8327_get_pad_cfg(pdata->pad6_cfg);
- + priv->write(priv, AR8327_REG_PAD6_MODE, t);
- +
- + pos = priv->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;
- +
- + priv->write(priv, AR8327_REG_LED_CTRL0, led_cfg->led_ctrl0);
- + priv->write(priv, AR8327_REG_LED_CTRL1, led_cfg->led_ctrl1);
- + priv->write(priv, AR8327_REG_LED_CTRL2, led_cfg->led_ctrl2);
- + priv->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);
- +
- + priv->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;
- + }
- +
- + priv->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)
- +{
- + 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):
- + priv->chip_data.ar8327.port0_status = val;
- + break;
- + case AR8327_REG_PORT_STATUS(6):
- + priv->chip_data.ar8327.port6_status = val;
- + break;
- + default:
- + priv->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)
- +{
- + struct mii_bus *bus;
- + int ret;
- + int i;
- +
- + 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);
- +
- + bus = priv->mii_bus;
- + for (i = 0; i < AR8327_NUM_PHYS; i++) {
- + ar8327_phy_fixup(priv, i);
- +
- + /* start aneg on the PHY */
- + mdiobus_write(bus, i, MII_ADVERTISE, ADVERTISE_ALL |
- + ADVERTISE_PAUSE_CAP |
- + ADVERTISE_PAUSE_ASYM);
- + mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL);
- + mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
- + }
- +
- + msleep(1000);
- +
- + return 0;
- +}
- +
- +static void
- +ar8327_cleanup(struct ar8xxx_priv *priv)
- +{
- + ar8327_leds_cleanup(priv);
- +}
- +
- +static void
- +ar8327_init_globals(struct ar8xxx_priv *priv)
- +{
- + u32 t;
- +
- + /* enable CPU port and disable mirror port */
- + t = AR8327_FWD_CTRL0_CPU_PORT_EN |
- + AR8327_FWD_CTRL0_MIRROR_PORT;
- + priv->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);
- + priv->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);
- +}
- +
- +static void
- +ar8327_init_port(struct ar8xxx_priv *priv, int port)
- +{
- + u32 t;
- +
- + if (port == AR8216_PORT_CPU)
- + t = priv->chip_data.ar8327.port0_status;
- + else if (port == 6)
- + t = priv->chip_data.ar8327.port6_status;
- + else
- + t = AR8216_PORT_STATUS_LINK_AUTO;
- +
- + priv->write(priv, AR8327_REG_PORT_STATUS(port), t);
- + priv->write(priv, AR8327_REG_PORT_HEADER(port), 0);
- +
- + t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S;
- + t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S;
- + priv->write(priv, AR8327_REG_PORT_VLAN0(port), t);
- +
- + t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S;
- + priv->write(priv, AR8327_REG_PORT_VLAN1(port), t);
- +
- + t = AR8327_PORT_LOOKUP_LEARN;
- + t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S;
- + priv->write(priv, AR8327_REG_PORT_LOOKUP(port), t);
- +}
- +
- +static u32
- +ar8327_read_port_status(struct ar8xxx_priv *priv, int port)
- +{
- + return priv->read(priv, AR8327_REG_PORT_STATUS(port));
- +}
- +
- +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)
- + priv->write(priv, AR8327_REG_ATU_FUNC,
- + AR8327_ATU_FUNC_OP_FLUSH);
- +
- + 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)
- + priv->write(priv, AR8327_REG_VTU_FUNC0, val);
- +
- + op |= AR8327_VTU_FUNC1_BUSY;
- + priv->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))
- + 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 egress, u32 ingress,
- + u32 members, u32 pvid)
- +{
- + u32 t;
- + u32 mode;
- +
- + t = pvid << AR8327_PORT_VLAN0_DEF_SVID_S;
- + t |= pvid << AR8327_PORT_VLAN0_DEF_CVID_S;
- + priv->write(priv, AR8327_REG_PORT_VLAN0(port), t);
- +
- + mode = AR8327_PORT_VLAN1_OUT_MODE_UNMOD;
- + switch (egress) {
- + case AR8216_OUT_KEEP:
- + mode = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH;
- + break;
- + case AR8216_OUT_STRIP_VLAN:
- + mode = AR8327_PORT_VLAN1_OUT_MODE_UNTAG;
- + break;
- + case AR8216_OUT_ADD_VLAN:
- + mode = AR8327_PORT_VLAN1_OUT_MODE_TAG;
- + break;
- + }
- +
- + t = AR8327_PORT_VLAN1_PORT_VLAN_PROP;
- + t |= mode << AR8327_PORT_VLAN1_OUT_MODE_S;
- + priv->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;
- + priv->write(priv, AR8327_REG_PORT_LOOKUP(port), t);
- +}
- +
- +static const struct ar8xxx_chip ar8327_chip = {
- + .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS,
- + .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,
- + .atu_flush = ar8327_atu_flush,
- + .vtu_flush = ar8327_vtu_flush,
- + .vtu_load_vlan = ar8327_vtu_load_vlan,
- +
- + .num_mibs = ARRAY_SIZE(ar8236_mibs),
- + .mib_decs = ar8236_mibs,
- +};
- +
- +static 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;
- +}
- +
- +static 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;
- +}
- +
- +
- +static 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;
- +}
- +
- +static 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;
- +}
- +
- +static 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
- +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_rmw(priv, AR8327_REG_PORT_LOOKUP(port),
- + AR8327_PORT_LOOKUP_ING_MIRROR_EN,
- + 0);
- +
- + ar8xxx_rmw(priv, AR8327_REG_PORT_HOL_CTRL1(port),
- + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN,
- + 0);
- + }
- +
- + /* 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_rmw(priv, AR8327_REG_PORT_LOOKUP(priv->source_port),
- + AR8327_PORT_LOOKUP_ING_MIRROR_EN,
- + AR8327_PORT_LOOKUP_ING_MIRROR_EN);
- +
- + if (priv->mirror_tx)
- + ar8xxx_rmw(priv, AR8327_REG_PORT_HOL_CTRL1(priv->source_port),
- + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN,
- + AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN);
- +}
- +
- +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_rmw(priv, AR8216_REG_PORT_CTRL(port),
- + AR8216_PORT_CTRL_MIRROR_RX,
- + 0);
- +
- + ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
- + AR8216_PORT_CTRL_MIRROR_TX,
- + 0);
- + }
- +
- + /* 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_rmw(priv, AR8216_REG_PORT_CTRL(priv->source_port),
- + AR8216_PORT_CTRL_MIRROR_RX,
- + AR8216_PORT_CTRL_MIRROR_RX);
- +
- + if (priv->mirror_tx)
- + ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(priv->source_port),
- + AR8216_PORT_CTRL_MIRROR_TX,
- + AR8216_PORT_CTRL_MIRROR_TX);
- +}
- +
- +static void
- +ar8xxx_set_mirror_regs(struct ar8xxx_priv *priv)
- +{
- + if (chip_is_ar8327(priv) || chip_is_ar8337(priv)) {
- + ar8327_set_mirror_regs(priv);
- + } else {
- + ar8216_set_mirror_regs(priv);
- + }
- +}
- +
- +static 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++) {
- + int egress, ingress;
- + int pvid;
- +
- + if (priv->vlan) {
- + pvid = priv->vlan_id[priv->pvid[i]];
- + if (priv->vlan_tagged & (1 << i))
- + egress = AR8216_OUT_ADD_VLAN;
- + else
- + egress = AR8216_OUT_STRIP_VLAN;
- + ingress = AR8216_IN_SECURE;
- + } else {
- + pvid = i;
- + egress = AR8216_OUT_KEEP;
- + ingress = AR8216_IN_PORT_ONLY;
- + }
- +
- + priv->chip->setup_port(priv, i, egress, ingress, portmask[i],
- + pvid);
- + }
- +
- + ar8xxx_set_mirror_regs(priv);
- +
- + mutex_unlock(&priv->reg_mutex);
- + return 0;
- +}
- +
- +static int
- +ar8xxx_sw_reset_switch(struct switch_dev *dev)
- +{
- + struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
- + 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++)
- + priv->chip->init_port(priv, i);
- +
- + priv->mirror_rx = false;
- + priv->mirror_tx = false;
- + priv->source_port = 0;
- + priv->monitor_port = 0;
- +
- + priv->chip->init_globals(priv);
- +
- + mutex_unlock(&priv->reg_mutex);
- +
- + return ar8xxx_sw_hw_apply(dev);
- +}
- +
- +static 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;
- +}
- +
- +static 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;
- + ar8xxx_set_mirror_regs(priv);
- + mutex_unlock(&priv->reg_mutex);
- +
- + return 0;
- +}
- +
- +static 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;
- +}
- +
- +static 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;
- + ar8xxx_set_mirror_regs(priv);
- + mutex_unlock(&priv->reg_mutex);
- +
- + return 0;
- +}
- +
- +static 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;
- +}
- +
- +static 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;
- + ar8xxx_set_mirror_regs(priv);
- + mutex_unlock(&priv->reg_mutex);
- +
- + return 0;
- +}
- +
- +static 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;
- +}
- +
- +static 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;
- + ar8xxx_set_mirror_regs(priv);
- + mutex_unlock(&priv->reg_mutex);
- +
- + return 0;
- +}
- +
- +static 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;
- +}
- +
- +static 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;
- +}
- +
- +static 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;
- +}
- +
- +static 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
- + },
- +};
- +
- +static 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
- + },
- +};
- +
- +static 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,
- + },
- +};
- +
- +static struct switch_attr ar8xxx_sw_attr_vlan[] = {
- + {
- + .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 switch_dev_ops ar8327_sw_ops = {
- + .attr_global = {
- + .attr = ar8327_sw_attr_globals,
- + .n_attr = ARRAY_SIZE(ar8327_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 int
- +ar8xxx_id_chip(struct ar8xxx_priv *priv)
- +{
- + u32 val;
- + u16 id;
- + int i;
- +
- + val = priv->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 = priv->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->mii_lo_first = true;
- + priv->chip = &ar8327_chip;
- + break;
- + case AR8XXX_VER_AR8337:
- + priv->mii_lo_first = true;
- + priv->chip = &ar8327_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->mib_stats);
- + kfree(priv);
- +}
- +
- +static struct ar8xxx_priv *
- +ar8xxx_create_mii(struct mii_bus *bus)
- +{
- + struct ar8xxx_priv *priv;
- +
- + priv = ar8xxx_create();
- + if (priv) {
- + priv->mii_bus = bus;
- + priv->read = ar8xxx_mii_read;
- + priv->write = ar8xxx_mii_write;
- + priv->rmw = ar8xxx_mii_rmw;
- + }
- +
- + return priv;
- +}
- +
- +static int
- +ar8xxx_probe_switch(struct ar8xxx_priv *priv)
- +{
- + struct switch_dev *swdev;
- + int ret;
- +
- + ret = ar8xxx_id_chip(priv);
- + if (ret)
- + return ret;
- +
- + swdev = &priv->dev;
- + swdev->cpu_port = AR8216_PORT_CPU;
- + swdev->ops = &ar8xxx_sw_ops;
- +
- + if (chip_is_ar8316(priv)) {
- + swdev->name = "Atheros AR8316";
- + swdev->vlans = AR8X16_MAX_VLANS;
- + swdev->ports = AR8216_NUM_PORTS;
- + } else if (chip_is_ar8236(priv)) {
- + swdev->name = "Atheros AR8236";
- + swdev->vlans = AR8216_NUM_VLANS;
- + swdev->ports = AR8216_NUM_PORTS;
- + } else if (chip_is_ar8327(priv)) {
- + swdev->name = "Atheros AR8327";
- + swdev->vlans = AR8X16_MAX_VLANS;
- + swdev->ports = AR8327_NUM_PORTS;
- + swdev->ops = &ar8327_sw_ops;
- + } else if (chip_is_ar8337(priv)) {
- + swdev->name = "Atheros AR8337";
- + swdev->vlans = AR8X16_MAX_VLANS;
- + swdev->ports = AR8327_NUM_PORTS;
- + swdev->ops = &ar8327_sw_ops;
- + } else {
- + swdev->name = "Atheros AR8216";
- + swdev->vlans = AR8216_NUM_VLANS;
- + swdev->ports = AR8216_NUM_PORTS;
- + }
- +
- + 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 (chip_is_ar8327(priv) || chip_is_ar8337(priv))
- + return 0;
- +
- + 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 int
- +ar8xxx_phy_read_status(struct phy_device *phydev)
- +{
- + struct ar8xxx_priv *priv = phydev->priv;
- + struct switch_port_link link;
- + int ret;
- +
- + 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;
- +
- + /* flush the address translation unit */
- + mutex_lock(&priv->reg_mutex);
- + ret = priv->chip->atu_flush(priv);
- + mutex_unlock(&priv->reg_mutex);
- +
- + phydev->state = PHY_RUNNING;
- + netif_carrier_on(phydev->attached_dev);
- + phydev->adjust_link(phydev->attached_dev);
- +
- + return ret;
- +}
- +
- +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,
- +};
- +
- +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_mii(phydev->bus);
- + if (priv == NULL) {
- + ret = -ENOMEM;
- + goto unlock;
- + }
- +
- + 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 (chip_is_ar8327(priv) || chip_is_ar8337(priv)) {
- + 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_detach(struct phy_device *phydev)
- +{
- + struct net_device *dev = phydev->attached_dev;
- +
- + if (!dev)
- + return;
- +
- + dev->phy_ptr = NULL;
- + dev->priv_flags &= ~IFF_NO_IP_ALIGN;
- + dev->eth_mangle_rx = NULL;
- + dev->eth_mangle_tx = NULL;
- +}
- +
- +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);
- +}
- +
- +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,
- + .detach = ar8xxx_phy_detach,
- + .config_init = ar8xxx_phy_config_init,
- + .config_aneg = ar8xxx_phy_config_aneg,
- + .read_status = ar8xxx_phy_read_status,
- + .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 --git a/drivers/net/phy/ar8216.h b/drivers/net/phy/ar8216.h
- new file mode 100644
- index 0000000..00d6d7f
- --- /dev/null
- +++ b/drivers/net/phy/ar8216.h
- @@ -0,0 +1,492 @@
- +/*
- + * 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 AR8216_PORT_CPU 0
- +#define AR8216_NUM_PORTS 6
- +#define AR8216_NUM_VLANS 16
- +#define AR8316_NUM_VLANS 4096
- +
- +/* 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 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 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_LOCKED 0x4
- +#define AR8216_ATU_OP_FLUSH_UNICAST 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_FULL_VIO BIT(12)
- +#define AR8216_ATU_ADDR4 BITS(16, 8)
- +#define AR8216_ATU_ADDR5 BITS(24, 8)
- +
- +#define AR8216_REG_ATU_DATA 0x0054
- +#define AR8216_ATU_ADDR3 BITS(0, 8)
- +#define AR8216_ATU_ADDR2 BITS(8, 8)
- +#define AR8216_ATU_ADDR1 BITS(16, 8)
- +#define AR8216_ATU_ADDR0 BITS(24, 8)
- +
- +#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 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_REG_PORT_STATS_BASE(_i) (0x19000 + (_i) * 0xa0)
- +
- +#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_REG_PORT_STATS_BASE(_i) (0x20000 + (_i) * 0x100)
- +
- +#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)
- +
- +#define AR8327_NUM_PORTS 7
- +#define AR8327_NUM_LEDS 15
- +#define AR8327_NUM_PHYS 5
- +#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_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_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_REG_ATU_DATA1 0x604
- +#define AR8327_REG_ATU_DATA2 0x608
- +
- +#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_LOCKED 0x4
- +#define AR8327_ATU_FUNC_OP_FLUSH_UNICAST 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_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 AR8327_REG_PORT_STATS_BASE(_i) (0x1000 + (_i) * 0x100)
- +
- +#define AR8337_PAD_MAC06_EXCHANGE_EN 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
- +};
- +
- +#endif
- diff --git a/include/linux/ar8216_platform.h b/include/linux/ar8216_platform.h
- new file mode 100644
- index 0000000..4935ad3
- --- /dev/null
- +++ b/include/linux/ar8216_platform.h
- @@ -0,0 +1,131 @@
- +/*
- + * 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;
- +};
- +
- +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 */
- \ No newline at end of file
- --
- 1.8.5.3
|