12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918 |
- From 54bcaca10728c1a1c8adfa48124ea79cce4ef929 Mon Sep 17 00:00:00 2001
- From: Razvan Stefanescu <razvan.stefanescu@freescale.com>
- Date: Tue, 22 Sep 2015 08:43:08 +0300
- Subject: [PATCH 215/226] dpaa2-evb: Added Edge Virtual Bridge driver
- This is a commit of the cummulative, squashed dpaa2-evb patches.
- All the commit logs are preserved below.
- Signed-off-by: Stuart Yoder <stuart.yoder@nxp.com>
- ----------------------------------------------------------------
- dpaa2-evb: Added Edge Virtual Bridge driver
- This contains the following patches migrated from linux-v4.0:
- staging: fsl-dpaa2: evb: Added Edge Virtual Bridge driver
- staging: fsl-dpaa2: evb: Added ethtool port counters
- staging: fsl-dpaa2: evb: Include by default in configuration
- staging: fsl-dpaa2: evb: Rebasing onto kernel 4.0
- staging: fsl-dpaa2: evb: Port to MC-0.7 FLibs
- dpaa2-evb: Set carrier state on port open
- dpaa2-evb: Add support for link state update
- dpaa2-evb: Update flib to MC 8.0.1
- staging: fsl-mc: migrated remaining flibs for MC fw 8.0.0 (split)
- Inital patches have been signed-off by:
- Alex Marginean <alexandru.marginean@freescale.com>
- J. German Rivera <German.Rivera@freescale.com>
- Bogdan Hamciuc <bogdan.hamciuc@freescale.com>
- Razvan Stefanescu <razvan.stefanescu@freescale.com>
- And reviewed by:
- Stuart Yoder <stuart.yoder@freescale.com>
- Porting to linux-v4.1 requires changes related to iflink usage and
- ndo_bridge_getlink() parameters list.
- Signed-off-by: Razvan Stefanescu <razvan.stefanescu@freescale.com>
- dpaa2-evb: Port to linux-v4.1
- Update iflink usage.
- Update evb_getlink() parameter list to match ndo_bridge_getlink().
- Signed-off-by: Razvan Stefanescu <razvan.stefanescu@freescale.com>
- dpaa2-evb: Add VLAN_8021Q dependency
- EVB traffic steering methods related to VLAN require VLAN support in kernel.
- Signed-off-by: Razvan Stefanescu <razvan.stefanescu@freescale.com>
- dpaa2-evb: Update dpdmux binary interface to 5.0
- This corresponds to MC release 0.8.0.
- Signed-off-by: Razvan Stefanescu <razvan.stefanescu@freescale.com>
- dpaa2-evb: Add support to set max frame length.
- All the packets bigger than max_frame_length will be dropped.
- Signed-off-by: Mihaela Panescu <mihaela.panescu@freescale.com>
- dpaa2-evb: resolve compile issues on uprev to 4.5
- -irq_number field no longer exists in fsl-mc interrupt
- struct
- -netdev_master_upper_dev_link() has 2 new parameters, which
- are set to NULL for now
- Signed-off-by: Stuart Yoder <stuart.yoder@nxp.com>
- ---
- MAINTAINERS | 6 +
- drivers/staging/fsl-dpaa2/Kconfig | 1 +
- drivers/staging/fsl-dpaa2/Makefile | 1 +
- drivers/staging/fsl-dpaa2/evb/Kconfig | 8 +
- drivers/staging/fsl-dpaa2/evb/Makefile | 10 +
- drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h | 256 ++++++
- drivers/staging/fsl-dpaa2/evb/dpdmux.c | 567 +++++++++++++
- drivers/staging/fsl-dpaa2/evb/dpdmux.h | 724 +++++++++++++++++
- drivers/staging/fsl-dpaa2/evb/evb.c | 1216 ++++++++++++++++++++++++++++
- 9 files changed, 2789 insertions(+)
- create mode 100644 drivers/staging/fsl-dpaa2/evb/Kconfig
- create mode 100644 drivers/staging/fsl-dpaa2/evb/Makefile
- create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h
- create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux.c
- create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux.h
- create mode 100644 drivers/staging/fsl-dpaa2/evb/evb.c
- --- a/MAINTAINERS
- +++ b/MAINTAINERS
- @@ -4560,6 +4560,12 @@ L: linux-kernel@vger.kernel.org
- S: Maintained
- F: drivers/staging/fsl-dpaa2/mac/
-
- ++FREESCALE DPAA2 EDGE VIRTUAL BRIDGE DRIVER
- +M: Alex Marginean <Alexandru.Marginean@freescale.com>
- +L: linux-kernel@vger.kernel.org
- +S: Maintained
- +F: drivers/staging/fsl-dpaa2/evb/
- +
- FREEVXFS FILESYSTEM
- M: Christoph Hellwig <hch@infradead.org>
- W: ftp://ftp.openlinux.org/pub/people/hch/vxfs
- --- a/drivers/staging/fsl-dpaa2/Kconfig
- +++ b/drivers/staging/fsl-dpaa2/Kconfig
- @@ -10,3 +10,4 @@ config FSL_DPAA2
- # TODO move DPIO driver in-here?
- source "drivers/staging/fsl-dpaa2/ethernet/Kconfig"
- source "drivers/staging/fsl-dpaa2/mac/Kconfig"
- +source "drivers/staging/fsl-dpaa2/evb/Kconfig"
- --- a/drivers/staging/fsl-dpaa2/Makefile
- +++ b/drivers/staging/fsl-dpaa2/Makefile
- @@ -4,3 +4,4 @@
-
- obj-$(CONFIG_FSL_DPAA2_ETH) += ethernet/
- obj-$(CONFIG_FSL_DPAA2_MAC) += mac/
- +obj-$(CONFIG_FSL_DPAA2_EVB) += evb/
- --- /dev/null
- +++ b/drivers/staging/fsl-dpaa2/evb/Kconfig
- @@ -0,0 +1,8 @@
- +config FSL_DPAA2_EVB
- + tristate "DPAA2 Edge Virtual Bridge"
- + depends on FSL_MC_BUS && FSL_DPAA2 && FSL_DPAA2_ETH
- + select FSL_DPAA2_MAC
- + select VLAN_8021Q
- + default y
- + ---help---
- + Prototype driver for DPAA2 Edge Virtual Bridge.
- --- /dev/null
- +++ b/drivers/staging/fsl-dpaa2/evb/Makefile
- @@ -0,0 +1,10 @@
- +
- +obj-$(CONFIG_FSL_DPAA2_EVB) += dpaa2-evb.o
- +
- +dpaa2-evb-objs := evb.o dpdmux.o
- +
- +all:
- + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
- +
- +clean:
- + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
- --- /dev/null
- +++ b/drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h
- @@ -0,0 +1,256 @@
- +/* Copyright 2013-2015 Freescale Semiconductor Inc.
- + *
- + * Redistribution and use in source and binary forms, with or without
- + * modification, are permitted provided that the following conditions are met:
- + * * Redistributions of source code must retain the above copyright
- + * notice, this list of conditions and the following disclaimer.
- + * * Redistributions in binary form must reproduce the above copyright
- + * notice, this list of conditions and the following disclaimer in the
- + * documentation and/or other materials provided with the distribution.
- + * * Neither the name of the above-listed copyright holders nor the
- + * names of any contributors may be used to endorse or promote products
- + * derived from this software without specific prior written permission.
- + *
- + *
- + * ALTERNATIVELY, this software may be distributed under the terms of the
- + * GNU General Public License ("GPL") as published by the Free Software
- + * Foundation, either version 2 of that License or (at your option) any
- + * later version.
- + *
- + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- + * POSSIBILITY OF SUCH DAMAGE.
- + */
- +#ifndef _FSL_DPDMUX_CMD_H
- +#define _FSL_DPDMUX_CMD_H
- +
- +/* DPDMUX Version */
- +#define DPDMUX_VER_MAJOR 5
- +#define DPDMUX_VER_MINOR 0
- +
- +/* Command IDs */
- +#define DPDMUX_CMDID_CLOSE 0x800
- +#define DPDMUX_CMDID_OPEN 0x806
- +#define DPDMUX_CMDID_CREATE 0x906
- +#define DPDMUX_CMDID_DESTROY 0x900
- +
- +#define DPDMUX_CMDID_ENABLE 0x002
- +#define DPDMUX_CMDID_DISABLE 0x003
- +#define DPDMUX_CMDID_GET_ATTR 0x004
- +#define DPDMUX_CMDID_RESET 0x005
- +#define DPDMUX_CMDID_IS_ENABLED 0x006
- +
- +#define DPDMUX_CMDID_SET_IRQ 0x010
- +#define DPDMUX_CMDID_GET_IRQ 0x011
- +#define DPDMUX_CMDID_SET_IRQ_ENABLE 0x012
- +#define DPDMUX_CMDID_GET_IRQ_ENABLE 0x013
- +#define DPDMUX_CMDID_SET_IRQ_MASK 0x014
- +#define DPDMUX_CMDID_GET_IRQ_MASK 0x015
- +#define DPDMUX_CMDID_GET_IRQ_STATUS 0x016
- +#define DPDMUX_CMDID_CLEAR_IRQ_STATUS 0x017
- +
- +#define DPDMUX_CMDID_UL_SET_MAX_FRAME_LENGTH 0x0a1
- +
- +#define DPDMUX_CMDID_UL_RESET_COUNTERS 0x0a3
- +
- +#define DPDMUX_CMDID_IF_SET_ACCEPTED_FRAMES 0x0a7
- +#define DPDMUX_CMDID_IF_GET_ATTR 0x0a8
- +
- +#define DPDMUX_CMDID_IF_ADD_L2_RULE 0x0b0
- +#define DPDMUX_CMDID_IF_REMOVE_L2_RULE 0x0b1
- +#define DPDMUX_CMDID_IF_GET_COUNTER 0x0b2
- +#define DPDMUX_CMDID_IF_SET_LINK_CFG 0x0b3
- +#define DPDMUX_CMDID_IF_GET_LINK_STATE 0x0b4
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_OPEN(cmd, dpdmux_id) \
- + MC_CMD_OP(cmd, 0, 0, 32, int, dpdmux_id)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_CREATE(cmd, cfg) \
- +do { \
- + MC_CMD_OP(cmd, 0, 0, 8, enum dpdmux_method, cfg->method);\
- + MC_CMD_OP(cmd, 0, 8, 8, enum dpdmux_manip, cfg->manip);\
- + MC_CMD_OP(cmd, 0, 16, 16, uint16_t, cfg->num_ifs);\
- + MC_CMD_OP(cmd, 1, 0, 16, uint16_t, cfg->adv.max_dmat_entries);\
- + MC_CMD_OP(cmd, 1, 16, 16, uint16_t, cfg->adv.max_mc_groups);\
- + MC_CMD_OP(cmd, 1, 32, 16, uint16_t, cfg->adv.max_vlan_ids);\
- + MC_CMD_OP(cmd, 2, 0, 64, uint64_t, cfg->adv.options);\
- +} while (0)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_RSP_IS_ENABLED(cmd, en) \
- + MC_RSP_OP(cmd, 0, 0, 1, int, en)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_SET_IRQ(cmd, irq_index, irq_cfg) \
- +do { \
- + MC_CMD_OP(cmd, 0, 0, 8, uint8_t, irq_index);\
- + MC_CMD_OP(cmd, 0, 32, 32, uint32_t, irq_cfg->val);\
- + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, irq_cfg->addr);\
- + MC_CMD_OP(cmd, 2, 0, 32, int, irq_cfg->irq_num); \
- +} while (0)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_GET_IRQ(cmd, irq_index) \
- + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_RSP_GET_IRQ(cmd, type, irq_cfg) \
- +do { \
- + MC_RSP_OP(cmd, 0, 0, 32, uint32_t, irq_cfg->val); \
- + MC_RSP_OP(cmd, 1, 0, 64, uint64_t, irq_cfg->addr); \
- + MC_RSP_OP(cmd, 2, 0, 32, int, irq_cfg->irq_num); \
- + MC_RSP_OP(cmd, 2, 32, 32, int, type); \
- +} while (0)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_SET_IRQ_ENABLE(cmd, irq_index, en) \
- +do { \
- + MC_CMD_OP(cmd, 0, 0, 8, uint8_t, en);\
- + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index);\
- +} while (0)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_GET_IRQ_ENABLE(cmd, irq_index) \
- + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_RSP_GET_IRQ_ENABLE(cmd, en) \
- + MC_RSP_OP(cmd, 0, 0, 8, uint8_t, en)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_SET_IRQ_MASK(cmd, irq_index, mask) \
- +do { \
- + MC_CMD_OP(cmd, 0, 0, 32, uint32_t, mask); \
- + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index); \
- +} while (0)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_GET_IRQ_MASK(cmd, irq_index) \
- + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_RSP_GET_IRQ_MASK(cmd, mask) \
- + MC_RSP_OP(cmd, 0, 0, 32, uint32_t, mask)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_GET_IRQ_STATUS(cmd, irq_index, status) \
- +do { \
- + MC_CMD_OP(cmd, 0, 0, 32, uint32_t, status);\
- + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index);\
- +} while (0)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_RSP_GET_IRQ_STATUS(cmd, status) \
- + MC_RSP_OP(cmd, 0, 0, 32, uint32_t, status) \
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_CLEAR_IRQ_STATUS(cmd, irq_index, status) \
- +do { \
- + MC_CMD_OP(cmd, 0, 0, 32, uint32_t, status); \
- + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index); \
- +} while (0)
- +
- +#define DPDMUX_RSP_GET_ATTR(cmd, attr) \
- +do { \
- + MC_RSP_OP(cmd, 0, 0, 8, enum dpdmux_method, attr->method);\
- + MC_RSP_OP(cmd, 0, 8, 8, enum dpdmux_manip, attr->manip);\
- + MC_RSP_OP(cmd, 0, 16, 16, uint16_t, attr->num_ifs);\
- + MC_RSP_OP(cmd, 0, 32, 16, uint16_t, attr->mem_size);\
- + MC_RSP_OP(cmd, 2, 0, 32, int, attr->id);\
- + MC_RSP_OP(cmd, 3, 0, 64, uint64_t, attr->options);\
- + MC_RSP_OP(cmd, 4, 0, 16, uint16_t, attr->version.major);\
- + MC_RSP_OP(cmd, 4, 16, 16, uint16_t, attr->version.minor);\
- +} while (0)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_UL_SET_MAX_FRAME_LENGTH(cmd, max_frame_length) \
- + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, max_frame_length)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_IF_SET_ACCEPTED_FRAMES(cmd, if_id, cfg) \
- +do { \
- + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id);\
- + MC_CMD_OP(cmd, 0, 16, 4, enum dpdmux_accepted_frames_type, cfg->type);\
- + MC_CMD_OP(cmd, 0, 20, 4, enum dpdmux_unaccepted_frames_action, \
- + cfg->unaccept_act);\
- +} while (0)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_IF_GET_ATTR(cmd, if_id) \
- + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_RSP_IF_GET_ATTR(cmd, attr) \
- +do { \
- + MC_RSP_OP(cmd, 0, 56, 4, enum dpdmux_accepted_frames_type, \
- + attr->accept_frame_type);\
- + MC_RSP_OP(cmd, 0, 24, 1, int, attr->enabled);\
- + MC_RSP_OP(cmd, 1, 0, 32, uint32_t, attr->rate);\
- +} while (0)
- +
- +#define DPDMUX_CMD_IF_REMOVE_L2_RULE(cmd, if_id, l2_rule) \
- +do { \
- + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id);\
- + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, l2_rule->mac_addr[5]);\
- + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, l2_rule->mac_addr[4]);\
- + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, l2_rule->mac_addr[3]);\
- + MC_CMD_OP(cmd, 0, 40, 8, uint8_t, l2_rule->mac_addr[2]);\
- + MC_CMD_OP(cmd, 0, 48, 8, uint8_t, l2_rule->mac_addr[1]);\
- + MC_CMD_OP(cmd, 0, 56, 8, uint8_t, l2_rule->mac_addr[0]);\
- + MC_CMD_OP(cmd, 1, 32, 16, uint16_t, l2_rule->vlan_id);\
- +} while (0)
- +
- +#define DPDMUX_CMD_IF_ADD_L2_RULE(cmd, if_id, l2_rule) \
- +do { \
- + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id);\
- + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, l2_rule->mac_addr[5]);\
- + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, l2_rule->mac_addr[4]);\
- + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, l2_rule->mac_addr[3]);\
- + MC_CMD_OP(cmd, 0, 40, 8, uint8_t, l2_rule->mac_addr[2]);\
- + MC_CMD_OP(cmd, 0, 48, 8, uint8_t, l2_rule->mac_addr[1]);\
- + MC_CMD_OP(cmd, 0, 56, 8, uint8_t, l2_rule->mac_addr[0]);\
- + MC_CMD_OP(cmd, 1, 32, 16, uint16_t, l2_rule->vlan_id);\
- +} while (0)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_IF_GET_COUNTER(cmd, if_id, counter_type) \
- +do { \
- + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id);\
- + MC_CMD_OP(cmd, 0, 16, 8, enum dpdmux_counter_type, counter_type);\
- +} while (0)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_RSP_IF_GET_COUNTER(cmd, counter) \
- + MC_RSP_OP(cmd, 1, 0, 64, uint64_t, counter)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_IF_SET_LINK_CFG(cmd, if_id, cfg) \
- +do { \
- + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id);\
- + MC_CMD_OP(cmd, 1, 0, 32, uint32_t, cfg->rate);\
- + MC_CMD_OP(cmd, 2, 0, 64, uint64_t, cfg->options);\
- +} while (0)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_CMD_IF_GET_LINK_STATE(cmd, if_id) \
- + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, if_id)
- +
- +/* cmd, param, offset, width, type, arg_name */
- +#define DPDMUX_RSP_IF_GET_LINK_STATE(cmd, state) \
- +do { \
- + MC_RSP_OP(cmd, 0, 32, 1, int, state->up);\
- + MC_RSP_OP(cmd, 1, 0, 32, uint32_t, state->rate);\
- + MC_RSP_OP(cmd, 2, 0, 64, uint64_t, state->options);\
- +} while (0)
- +
- +#endif /* _FSL_DPDMUX_CMD_H */
- --- /dev/null
- +++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.c
- @@ -0,0 +1,567 @@
- +/* Copyright 2013-2015 Freescale Semiconductor Inc.
- + *
- + * Redistribution and use in source and binary forms, with or without
- + * modification, are permitted provided that the following conditions are met:
- + * * Redistributions of source code must retain the above copyright
- + * notice, this list of conditions and the following disclaimer.
- + * * Redistributions in binary form must reproduce the above copyright
- + * notice, this list of conditions and the following disclaimer in the
- + * documentation and/or other materials provided with the distribution.
- + * * Neither the name of the above-listed copyright holders nor the
- + * names of any contributors may be used to endorse or promote products
- + * derived from this software without specific prior written permission.
- + *
- + *
- + * ALTERNATIVELY, this software may be distributed under the terms of the
- + * GNU General Public License ("GPL") as published by the Free Software
- + * Foundation, either version 2 of that License or (at your option) any
- + * later version.
- + *
- + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- + * POSSIBILITY OF SUCH DAMAGE.
- + */
- +#include "../../fsl-mc/include/mc-sys.h"
- +#include "../../fsl-mc/include/mc-cmd.h"
- +#include "dpdmux.h"
- +#include "dpdmux-cmd.h"
- +
- +int dpdmux_open(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + int dpdmux_id,
- + uint16_t *token)
- +{
- + struct mc_command cmd = { 0 };
- + int err;
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_OPEN,
- + cmd_flags,
- + 0);
- + DPDMUX_CMD_OPEN(cmd, dpdmux_id);
- +
- + /* send command to mc*/
- + err = mc_send_command(mc_io, &cmd);
- + if (err)
- + return err;
- +
- + /* retrieve response parameters */
- + *token = MC_CMD_HDR_READ_TOKEN(cmd.header);
- +
- + return 0;
- +}
- +
- +int dpdmux_close(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CLOSE,
- + cmd_flags,
- + token);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_create(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + const struct dpdmux_cfg *cfg,
- + uint16_t *token)
- +{
- + struct mc_command cmd = { 0 };
- + int err;
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CREATE,
- + cmd_flags,
- + 0);
- + DPDMUX_CMD_CREATE(cmd, cfg);
- +
- + /* send command to mc*/
- + err = mc_send_command(mc_io, &cmd);
- + if (err)
- + return err;
- +
- + /* retrieve response parameters */
- + *token = MC_CMD_HDR_READ_TOKEN(cmd.header);
- +
- + return 0;
- +}
- +
- +int dpdmux_destroy(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_DESTROY,
- + cmd_flags,
- + token);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_enable(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_ENABLE,
- + cmd_flags,
- + token);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_disable(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_DISABLE,
- + cmd_flags,
- + token);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_is_enabled(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + int *en)
- +{
- + struct mc_command cmd = { 0 };
- + int err;
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IS_ENABLED,
- + cmd_flags,
- + token);
- +
- + /* send command to mc*/
- + err = mc_send_command(mc_io, &cmd);
- + if (err)
- + return err;
- +
- + /* retrieve response parameters */
- + DPDMUX_RSP_IS_ENABLED(cmd, *en);
- +
- + return 0;
- +}
- +
- +int dpdmux_reset(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_RESET,
- + cmd_flags,
- + token);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_set_irq(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + struct dpdmux_irq_cfg *irq_cfg)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_SET_IRQ(cmd, irq_index, irq_cfg);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_get_irq(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + int *type,
- + struct dpdmux_irq_cfg *irq_cfg)
- +{
- + struct mc_command cmd = { 0 };
- + int err;
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_GET_IRQ(cmd, irq_index);
- +
- + /* send command to mc*/
- + err = mc_send_command(mc_io, &cmd);
- + if (err)
- + return err;
- +
- + /* retrieve response parameters */
- + DPDMUX_RSP_GET_IRQ(cmd, *type, irq_cfg);
- +
- + return 0;
- +}
- +
- +int dpdmux_set_irq_enable(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + uint8_t en)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ_ENABLE,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_SET_IRQ_ENABLE(cmd, irq_index, en);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_get_irq_enable(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + uint8_t *en)
- +{
- + struct mc_command cmd = { 0 };
- + int err;
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_ENABLE,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_GET_IRQ_ENABLE(cmd, irq_index);
- +
- + /* send command to mc*/
- + err = mc_send_command(mc_io, &cmd);
- + if (err)
- + return err;
- +
- + /* retrieve response parameters */
- + DPDMUX_RSP_GET_IRQ_ENABLE(cmd, *en);
- +
- + return 0;
- +}
- +
- +int dpdmux_set_irq_mask(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + uint32_t mask)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ_MASK,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_SET_IRQ_MASK(cmd, irq_index, mask);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_get_irq_mask(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + uint32_t *mask)
- +{
- + struct mc_command cmd = { 0 };
- + int err;
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_MASK,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_GET_IRQ_MASK(cmd, irq_index);
- +
- + /* send command to mc*/
- + err = mc_send_command(mc_io, &cmd);
- + if (err)
- + return err;
- +
- + /* retrieve response parameters */
- + DPDMUX_RSP_GET_IRQ_MASK(cmd, *mask);
- +
- + return 0;
- +}
- +
- +int dpdmux_get_irq_status(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + uint32_t *status)
- +{
- + struct mc_command cmd = { 0 };
- + int err;
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_STATUS,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_GET_IRQ_STATUS(cmd, irq_index, *status);
- +
- + /* send command to mc*/
- + err = mc_send_command(mc_io, &cmd);
- + if (err)
- + return err;
- +
- + /* retrieve response parameters */
- + DPDMUX_RSP_GET_IRQ_STATUS(cmd, *status);
- +
- + return 0;
- +}
- +
- +int dpdmux_clear_irq_status(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + uint32_t status)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CLEAR_IRQ_STATUS,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_CLEAR_IRQ_STATUS(cmd, irq_index, status);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_get_attributes(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + struct dpdmux_attr *attr)
- +{
- + struct mc_command cmd = { 0 };
- + int err;
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_ATTR,
- + cmd_flags,
- + token);
- +
- + /* send command to mc*/
- + err = mc_send_command(mc_io, &cmd);
- + if (err)
- + return err;
- +
- + /* retrieve response parameters */
- + DPDMUX_RSP_GET_ATTR(cmd, attr);
- +
- + return 0;
- +}
- +
- +int dpdmux_ul_set_max_frame_length(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t max_frame_length)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_UL_SET_MAX_FRAME_LENGTH,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_UL_SET_MAX_FRAME_LENGTH(cmd, max_frame_length);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_ul_reset_counters(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_UL_RESET_COUNTERS,
- + cmd_flags,
- + token);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_if_set_accepted_frames(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + const struct dpdmux_accepted_frames *cfg)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_SET_ACCEPTED_FRAMES,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_IF_SET_ACCEPTED_FRAMES(cmd, if_id, cfg);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_if_get_attributes(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + struct dpdmux_if_attr *attr)
- +{
- + struct mc_command cmd = { 0 };
- + int err;
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_ATTR,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_IF_GET_ATTR(cmd, if_id);
- +
- + /* send command to mc*/
- + err = mc_send_command(mc_io, &cmd);
- + if (err)
- + return err;
- +
- + /* retrieve response parameters */
- + DPDMUX_RSP_IF_GET_ATTR(cmd, attr);
- +
- + return 0;
- +}
- +
- +int dpdmux_if_remove_l2_rule(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + const struct dpdmux_l2_rule *rule)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_REMOVE_L2_RULE,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_IF_REMOVE_L2_RULE(cmd, if_id, rule);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_if_add_l2_rule(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + const struct dpdmux_l2_rule *rule)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_ADD_L2_RULE,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_IF_ADD_L2_RULE(cmd, if_id, rule);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_if_get_counter(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + enum dpdmux_counter_type counter_type,
- + uint64_t *counter)
- +{
- + struct mc_command cmd = { 0 };
- + int err;
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_COUNTER,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_IF_GET_COUNTER(cmd, if_id, counter_type);
- +
- + /* send command to mc*/
- + err = mc_send_command(mc_io, &cmd);
- + if (err)
- + return err;
- +
- + /* retrieve response parameters */
- + DPDMUX_RSP_IF_GET_COUNTER(cmd, *counter);
- +
- + return 0;
- +}
- +
- +int dpdmux_if_set_link_cfg(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + struct dpdmux_link_cfg *cfg)
- +{
- + struct mc_command cmd = { 0 };
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_SET_LINK_CFG,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_IF_SET_LINK_CFG(cmd, if_id, cfg);
- +
- + /* send command to mc*/
- + return mc_send_command(mc_io, &cmd);
- +}
- +
- +int dpdmux_if_get_link_state(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + struct dpdmux_link_state *state)
- +{
- + struct mc_command cmd = { 0 };
- + int err;
- +
- + /* prepare command */
- + cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_LINK_STATE,
- + cmd_flags,
- + token);
- + DPDMUX_CMD_IF_GET_LINK_STATE(cmd, if_id);
- +
- + /* send command to mc*/
- + err = mc_send_command(mc_io, &cmd);
- + if (err)
- + return err;
- +
- + /* retrieve response parameters */
- + DPDMUX_RSP_IF_GET_LINK_STATE(cmd, state);
- +
- + return 0;
- +}
- --- /dev/null
- +++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.h
- @@ -0,0 +1,724 @@
- +/* Copyright 2013-2015 Freescale Semiconductor Inc.
- + *
- + * Redistribution and use in source and binary forms, with or without
- + * modification, are permitted provided that the following conditions are met:
- + * * Redistributions of source code must retain the above copyright
- + * notice, this list of conditions and the following disclaimer.
- + * * Redistributions in binary form must reproduce the above copyright
- + * notice, this list of conditions and the following disclaimer in the
- + * documentation and/or other materials provided with the distribution.
- + * * Neither the name of the above-listed copyright holders nor the
- + * names of any contributors may be used to endorse or promote products
- + * derived from this software without specific prior written permission.
- + *
- + *
- + * ALTERNATIVELY, this software may be distributed under the terms of the
- + * GNU General Public License ("GPL") as published by the Free Software
- + * Foundation, either version 2 of that License or (at your option) any
- + * later version.
- + *
- + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
- + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- + * POSSIBILITY OF SUCH DAMAGE.
- + */
- +#ifndef __FSL_DPDMUX_H
- +#define __FSL_DPDMUX_H
- +
- +#include "../../fsl-mc/include/net.h"
- +
- +struct fsl_mc_io;
- +
- +/* Data Path Demux API
- + * Contains API for handling DPDMUX topology and functionality
- + */
- +
- +/**
- + * dpdmux_open() - Open a control session for the specified object
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @dpdmux_id: DPDMUX unique ID
- + * @token: Returned token; use in subsequent API calls
- + *
- + * This function can be used to open a control session for an
- + * already created object; an object may have been declared in
- + * the DPL or by calling the dpdmux_create() function.
- + * This function returns a unique authentication token,
- + * associated with the specific object ID and the specific MC
- + * portal; this token must be used in all subsequent commands for
- + * this specific object.
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_open(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + int dpdmux_id,
- + uint16_t *token);
- +
- +/**
- + * dpdmux_close() - Close the control session of the object
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + *
- + * After this function is called, no further operations are
- + * allowed on the object without opening a new control session.
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_close(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token);
- +
- +/**
- + * DPDMUX general options
- + */
- +
- +/**
- + * Enable bridging between internal interfaces
- + */
- +#define DPDMUX_OPT_BRIDGE_EN 0x0000000000000002ULL
- +
- +#define DPDMUX_IRQ_INDEX_IF 0x0000
- +#define DPDMUX_IRQ_INDEX 0x0001
- +
- +/**
- + * IRQ event - Indicates that the link state changed
- + */
- +#define DPDMUX_IRQ_EVENT_LINK_CHANGED 0x0001
- +
- +/**
- + * enum dpdmux_manip - DPDMUX manipulation operations
- + * @DPDMUX_MANIP_NONE: No manipulation on frames
- + * @DPDMUX_MANIP_ADD_REMOVE_S_VLAN: Add S-VLAN on egress, remove it on ingress
- + */
- +enum dpdmux_manip {
- + DPDMUX_MANIP_NONE = 0x0,
- + DPDMUX_MANIP_ADD_REMOVE_S_VLAN = 0x1
- +};
- +
- +/**
- + * enum dpdmux_method - DPDMUX method options
- + * @DPDMUX_METHOD_NONE: no DPDMUX method
- + * @DPDMUX_METHOD_C_VLAN_MAC: DPDMUX based on C-VLAN and MAC address
- + * @DPDMUX_METHOD_MAC: DPDMUX based on MAC address
- + * @DPDMUX_METHOD_C_VLAN: DPDMUX based on C-VLAN
- + * @DPDMUX_METHOD_S_VLAN: DPDMUX based on S-VLAN
- + */
- +enum dpdmux_method {
- + DPDMUX_METHOD_NONE = 0x0,
- + DPDMUX_METHOD_C_VLAN_MAC = 0x1,
- + DPDMUX_METHOD_MAC = 0x2,
- + DPDMUX_METHOD_C_VLAN = 0x3,
- + DPDMUX_METHOD_S_VLAN = 0x4
- +};
- +
- +/**
- + * struct dpdmux_cfg - DPDMUX configuration parameters
- + * @method: Defines the operation method for the DPDMUX address table
- + * @manip: Required manipulation operation
- + * @num_ifs: Number of interfaces (excluding the uplink interface)
- + * @adv: Advanced parameters; default is all zeros;
- + * use this structure to change default settings
- + */
- +struct dpdmux_cfg {
- + enum dpdmux_method method;
- + enum dpdmux_manip manip;
- + uint16_t num_ifs;
- + /**
- + * struct adv - Advanced parameters
- + * @options: DPDMUX options - combination of 'DPDMUX_OPT_<X>' flags
- + * @max_dmat_entries: Maximum entries in DPDMUX address table
- + * 0 - indicates default: 64 entries per interface.
- + * @max_mc_groups: Number of multicast groups in DPDMUX table
- + * 0 - indicates default: 32 multicast groups
- + * @max_vlan_ids: max vlan ids allowed in the system -
- + * relevant only case of working in mac+vlan method.
- + * 0 - indicates default 16 vlan ids.
- + */
- + struct {
- + uint64_t options;
- + uint16_t max_dmat_entries;
- + uint16_t max_mc_groups;
- + uint16_t max_vlan_ids;
- + } adv;
- +};
- +
- +/**
- + * dpdmux_create() - Create the DPDMUX object
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @cfg: Configuration structure
- + * @token: Returned token; use in subsequent API calls
- + *
- + * Create the DPDMUX object, allocate required resources and
- + * perform required initialization.
- + *
- + * The object can be created either by declaring it in the
- + * DPL file, or by calling this function.
- + *
- + * This function returns a unique authentication token,
- + * associated with the specific object ID and the specific MC
- + * portal; this token must be used in all subsequent calls to
- + * this specific object. For objects that are created using the
- + * DPL file, call dpdmux_open() function to get an authentication
- + * token first.
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_create(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + const struct dpdmux_cfg *cfg,
- + uint16_t *token);
- +
- +/**
- + * dpdmux_destroy() - Destroy the DPDMUX object and release all its resources.
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + *
- + * Return: '0' on Success; error code otherwise.
- + */
- +int dpdmux_destroy(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token);
- +
- +/**
- + * dpdmux_enable() - Enable DPDMUX functionality
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_enable(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token);
- +
- +/**
- + * dpdmux_disable() - Disable DPDMUX functionality
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_disable(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token);
- +
- +/**
- + * dpdmux_is_enabled() - Check if the DPDMUX is enabled.
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @en: Returns '1' if object is enabled; '0' otherwise
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_is_enabled(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + int *en);
- +
- +/**
- + * dpdmux_reset() - Reset the DPDMUX, returns the object to initial state.
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_reset(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token);
- +
- +/**
- + * struct dpdmux_irq_cfg - IRQ configuration
- + * @addr: Address that must be written to signal a message-based interrupt
- + * @val: Value to write into irq_addr address
- + * @irq_num: A user defined number associated with this IRQ
- + */
- +struct dpdmux_irq_cfg {
- + uint64_t addr;
- + uint32_t val;
- + int irq_num;
- +};
- +
- +/**
- + * dpdmux_set_irq() - Set IRQ information for the DPDMUX to trigger an interrupt.
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @irq_index: Identifies the interrupt index to configure
- + * @irq_cfg: IRQ configuration
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_set_irq(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + struct dpdmux_irq_cfg *irq_cfg);
- +
- +/**
- + * dpdmux_get_irq() - Get IRQ information from the DPDMUX.
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @irq_index: The interrupt index to configure
- + * @type: Interrupt type: 0 represents message interrupt
- + * type (both irq_addr and irq_val are valid)
- + * @irq_cfg: IRQ attributes
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_get_irq(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + int *type,
- + struct dpdmux_irq_cfg *irq_cfg);
- +
- +/**
- + * dpdmux_set_irq_enable() - Set overall interrupt state.
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @irq_index: The interrupt index to configure
- + * @en: Interrupt state - enable = 1, disable = 0
- + *
- + * Allows GPP software to control when interrupts are generated.
- + * Each interrupt can have up to 32 causes. The enable/disable control's the
- + * overall interrupt state. if the interrupt is disabled no causes will cause
- + * an interrupt.
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_set_irq_enable(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + uint8_t en);
- +
- +/**
- + * dpdmux_get_irq_enable() - Get overall interrupt state.
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @irq_index: The interrupt index to configure
- + * @en: Returned interrupt state - enable = 1, disable = 0
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_get_irq_enable(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + uint8_t *en);
- +
- +/**
- + * dpdmux_set_irq_mask() - Set interrupt mask.
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @irq_index: The interrupt index to configure
- + * @mask: event mask to trigger interrupt;
- + * each bit:
- + * 0 = ignore event
- + * 1 = consider event for asserting IRQ
- + *
- + * Every interrupt can have up to 32 causes and the interrupt model supports
- + * masking/unmasking each cause independently
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_set_irq_mask(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + uint32_t mask);
- +
- +/**
- + * dpdmux_get_irq_mask() - Get interrupt mask.
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @irq_index: The interrupt index to configure
- + * @mask: Returned event mask to trigger interrupt
- + *
- + * Every interrupt can have up to 32 causes and the interrupt model supports
- + * masking/unmasking each cause independently
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_get_irq_mask(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + uint32_t *mask);
- +
- +/**
- + * dpdmux_get_irq_status() - Get the current status of any pending interrupts.
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @irq_index: The interrupt index to configure
- + * @status: Returned interrupts status - one bit per cause:
- + * 0 = no interrupt pending
- + * 1 = interrupt pending
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_get_irq_status(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + uint32_t *status);
- +
- +/**
- + * dpdmux_clear_irq_status() - Clear a pending interrupt's status
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @irq_index: The interrupt index to configure
- + * @status: bits to clear (W1C) - one bit per cause:
- + * 0 = don't change
- + * 1 = clear status bit
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_clear_irq_status(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint8_t irq_index,
- + uint32_t status);
- +
- +/**
- + * struct dpdmux_attr - Structure representing DPDMUX attributes
- + * @id: DPDMUX object ID
- + * @version: DPDMUX version
- + * @options: Configuration options (bitmap)
- + * @method: DPDMUX address table method
- + * @manip: DPDMUX manipulation type
- + * @num_ifs: Number of interfaces (excluding the uplink interface)
- + * @mem_size: DPDMUX frame storage memory size
- + */
- +struct dpdmux_attr {
- + int id;
- + /**
- + * struct version - DPDMUX version
- + * @major: DPDMUX major version
- + * @minor: DPDMUX minor version
- + */
- + struct {
- + uint16_t major;
- + uint16_t minor;
- + } version;
- + uint64_t options;
- + enum dpdmux_method method;
- + enum dpdmux_manip manip;
- + uint16_t num_ifs;
- + uint16_t mem_size;
- +};
- +
- +/**
- + * dpdmux_get_attributes() - Retrieve DPDMUX attributes
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @attr: Returned object's attributes
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_get_attributes(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + struct dpdmux_attr *attr);
- +
- +/**
- + * dpdmux_ul_set_max_frame_length() - Set the maximum frame length in DPDMUX
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @max_frame_length: The required maximum frame length
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_ul_set_max_frame_length(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t max_frame_length);
- +
- +/**
- + * enum dpdmux_counter_type - Counter types
- + * @DPDMUX_CNT_ING_FRAME: Counts ingress frames
- + * @DPDMUX_CNT_ING_BYTE: Counts ingress bytes
- + * @DPDMUX_CNT_ING_FLTR_FRAME: Counts filtered ingress frames
- + * @DPDMUX_CNT_ING_FRAME_DISCARD: Counts discarded ingress frames
- + * @DPDMUX_CNT_ING_MCAST_FRAME: Counts ingress multicast frames
- + * @DPDMUX_CNT_ING_MCAST_BYTE: Counts ingress multicast bytes
- + * @DPDMUX_CNT_ING_BCAST_FRAME: Counts ingress broadcast frames
- + * @DPDMUX_CNT_ING_BCAST_BYTES: Counts ingress broadcast bytes
- + * @DPDMUX_CNT_EGR_FRAME: Counts egress frames
- + * @DPDMUX_CNT_EGR_BYTE: Counts egress bytes
- + * @DPDMUX_CNT_EGR_FRAME_DISCARD: Counts discarded egress frames
- + */
- +enum dpdmux_counter_type {
- + DPDMUX_CNT_ING_FRAME = 0x0,
- + DPDMUX_CNT_ING_BYTE = 0x1,
- + DPDMUX_CNT_ING_FLTR_FRAME = 0x2,
- + DPDMUX_CNT_ING_FRAME_DISCARD = 0x3,
- + DPDMUX_CNT_ING_MCAST_FRAME = 0x4,
- + DPDMUX_CNT_ING_MCAST_BYTE = 0x5,
- + DPDMUX_CNT_ING_BCAST_FRAME = 0x6,
- + DPDMUX_CNT_ING_BCAST_BYTES = 0x7,
- + DPDMUX_CNT_EGR_FRAME = 0x8,
- + DPDMUX_CNT_EGR_BYTE = 0x9,
- + DPDMUX_CNT_EGR_FRAME_DISCARD = 0xa
- +};
- +
- +/**
- + * enum dpdmux_accepted_frames_type - DPDMUX frame types
- + * @DPDMUX_ADMIT_ALL: The device accepts VLAN tagged, untagged and
- + * priority-tagged frames
- + * @DPDMUX_ADMIT_ONLY_VLAN_TAGGED: The device discards untagged frames or
- + * priority-tagged frames that are received on this
- + * interface
- + * @DPDMUX_ADMIT_ONLY_UNTAGGED: Untagged frames or priority-tagged frames
- + * received on this interface are accepted
- + */
- +enum dpdmux_accepted_frames_type {
- + DPDMUX_ADMIT_ALL = 0,
- + DPDMUX_ADMIT_ONLY_VLAN_TAGGED = 1,
- + DPDMUX_ADMIT_ONLY_UNTAGGED = 2
- +};
- +
- +/**
- + * enum dpdmux_action - DPDMUX action for un-accepted frames
- + * @DPDMUX_ACTION_DROP: Drop un-accepted frames
- + * @DPDMUX_ACTION_REDIRECT_TO_CTRL: Redirect un-accepted frames to the
- + * control interface
- + */
- +enum dpdmux_action {
- + DPDMUX_ACTION_DROP = 0,
- + DPDMUX_ACTION_REDIRECT_TO_CTRL = 1
- +};
- +
- +/**
- + * struct dpdmux_accepted_frames - Frame types configuration
- + * @type: Defines ingress accepted frames
- + * @unaccept_act: Defines action on frames not accepted
- + */
- +struct dpdmux_accepted_frames {
- + enum dpdmux_accepted_frames_type type;
- + enum dpdmux_action unaccept_act;
- +};
- +
- +/**
- + * dpdmux_if_set_accepted_frames() - Set the accepted frame types
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @if_id: Interface ID (0 for uplink, or 1-num_ifs);
- + * @cfg: Frame types configuration
- + *
- + * if 'DPDMUX_ADMIT_ONLY_VLAN_TAGGED' is set - untagged frames or
- + * priority-tagged frames are discarded.
- + * if 'DPDMUX_ADMIT_ONLY_UNTAGGED' is set - untagged frames or
- + * priority-tagged frames are accepted.
- + * if 'DPDMUX_ADMIT_ALL' is set (default mode) - all VLAN tagged,
- + * untagged and priority-tagged frame are accepted;
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_if_set_accepted_frames(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + const struct dpdmux_accepted_frames *cfg);
- +
- +/**
- + * struct dpdmux_if_attr - Structure representing frame types configuration
- + * @rate: Configured interface rate (in bits per second)
- + * @enabled: Indicates if interface is enabled
- + * @accept_frame_type: Indicates type of accepted frames for the interface
- + */
- +struct dpdmux_if_attr {
- + uint32_t rate;
- + int enabled;
- + enum dpdmux_accepted_frames_type accept_frame_type;
- +};
- +
- +/**
- + * dpdmux_if_get_attributes() - Obtain DPDMUX interface attributes
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @if_id: Interface ID (0 for uplink, or 1-num_ifs);
- + * @attr: Interface attributes
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_if_get_attributes(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + struct dpdmux_if_attr *attr);
- +
- +/**
- + * struct dpdmux_l2_rule - Structure representing L2 rule
- + * @mac_addr: MAC address
- + * @vlan_id: VLAN ID
- + */
- +struct dpdmux_l2_rule {
- + uint8_t mac_addr[6];
- + uint16_t vlan_id;
- +};
- +
- +/**
- + * dpdmux_if_remove_l2_rule() - Remove L2 rule from DPDMUX table
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @if_id: Destination interface ID
- + * @rule: L2 rule
- + *
- + * Function removes a L2 rule from DPDMUX table
- + * or adds an interface to an existing multicast address
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_if_remove_l2_rule(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + const struct dpdmux_l2_rule *rule);
- +
- +/**
- + * dpdmux_if_add_l2_rule() - Add L2 rule into DPDMUX table
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPDMUX object
- + * @if_id: Destination interface ID
- + * @rule: L2 rule
- + *
- + * Function adds a L2 rule into DPDMUX table
- + * or adds an interface to an existing multicast address
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_if_add_l2_rule(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + const struct dpdmux_l2_rule *rule);
- +
- +/**
- +* dpdmux_if_get_counter() - Functions obtains specific counter of an interface
- +* @mc_io: Pointer to MC portal's I/O object
- +* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- +* @token: Token of DPDMUX object
- +* @if_id: Interface Id
- +* @counter_type: counter type
- +* @counter: Returned specific counter information
- +*
- +* Return: '0' on Success; Error code otherwise.
- +*/
- +int dpdmux_if_get_counter(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + enum dpdmux_counter_type counter_type,
- + uint64_t *counter);
- +
- +/**
- +* dpdmux_ul_reset_counters() - Function resets the uplink counter
- +* @mc_io: Pointer to MC portal's I/O object
- +* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- +* @token: Token of DPDMUX object
- +*
- +* Return: '0' on Success; Error code otherwise.
- +*/
- +int dpdmux_ul_reset_counters(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token);
- +
- +/**
- + * Enable auto-negotiation
- + */
- +#define DPDMUX_LINK_OPT_AUTONEG 0x0000000000000001ULL
- +/**
- + * Enable half-duplex mode
- + */
- +#define DPDMUX_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL
- +/**
- + * Enable pause frames
- + */
- +#define DPDMUX_LINK_OPT_PAUSE 0x0000000000000004ULL
- +/**
- + * Enable a-symmetric pause frames
- + */
- +#define DPDMUX_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL
- +
- +/**
- + * struct dpdmux_link_cfg - Structure representing DPDMUX link configuration
- + * @rate: Rate
- + * @options: Mask of available options; use 'DPDMUX_LINK_OPT_<X>' values
- + */
- +struct dpdmux_link_cfg {
- + uint32_t rate;
- + uint64_t options;
- +};
- +
- +/**
- + * dpdmux_if_set_link_cfg() - set the link configuration.
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPSW object
- + * @if_id: interface id
- + * @cfg: Link configuration
- + *
- + * Return: '0' on Success; Error code otherwise.
- + */
- +int dpdmux_if_set_link_cfg(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + struct dpdmux_link_cfg *cfg);
- +/**
- + * struct dpdmux_link_state - Structure representing DPDMUX link state
- + * @rate: Rate
- + * @options: Mask of available options; use 'DPDMUX_LINK_OPT_<X>' values
- + * @up: 0 - down, 1 - up
- + */
- +struct dpdmux_link_state {
- + uint32_t rate;
- + uint64_t options;
- + int up;
- +};
- +
- +/**
- + * dpdmux_if_get_link_state - Return the link state
- + * @mc_io: Pointer to MC portal's I/O object
- + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- + * @token: Token of DPSW object
- + * @if_id: interface id
- + * @state: link state
- + *
- + * @returns '0' on Success; Error code otherwise.
- + */
- +int dpdmux_if_get_link_state(struct fsl_mc_io *mc_io,
- + uint32_t cmd_flags,
- + uint16_t token,
- + uint16_t if_id,
- + struct dpdmux_link_state *state);
- +
- +#endif /* __FSL_DPDMUX_H */
- --- /dev/null
- +++ b/drivers/staging/fsl-dpaa2/evb/evb.c
- @@ -0,0 +1,1216 @@
- +/* Copyright 2015 Freescale Semiconductor Inc.
- + *
- + * Redistribution and use in source and binary forms, with or without
- + * modification, are permitted provided that the following conditions are met:
- + * * Redistributions of source code must retain the above copyright
- + * notice, this list of conditions and the following disclaimer.
- + * * Redistributions in binary form must reproduce the above copyright
- + * notice, this list of conditions and the following disclaimer in the
- + * documentation and/or other materials provided with the distribution.
- + * * Neither the name of Freescale Semiconductor nor the
- + * names of its contributors may be used to endorse or promote products
- + * derived from this software without specific prior written permission.
- + *
- + *
- + * ALTERNATIVELY, this software may be distributed under the terms of the
- + * GNU General Public License ("GPL") as published by the Free Software
- + * Foundation, either version 2 of that License or (at your option) any
- + * later version.
- + *
- + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
- + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
- + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- + */
- +#include <linux/module.h>
- +#include <linux/netdevice.h>
- +#include <linux/etherdevice.h>
- +#include <linux/rtnetlink.h>
- +#include <linux/if_vlan.h>
- +#include <linux/interrupt.h>
- +#include <linux/msi.h>
- +
- +#include <uapi/linux/if_bridge.h>
- +#include <net/netlink.h>
- +
- +#include "../../fsl-mc/include/mc.h"
- +
- +#include "dpdmux.h"
- +#include "dpdmux-cmd.h"
- +
- +/* IRQ index */
- +#define DPDMUX_MAX_IRQ_NUM 2
- +
- +/* MAX FRAME LENGTH (currently 10k) */
- +#define EVB_MAX_FRAME_LENGTH (10 * 1024)
- +/* MIN FRAME LENGTH (64 bytes + 4 bytes CRC) */
- +#define EVB_MIN_FRAME_LENGTH 68
- +
- +struct evb_port_priv {
- + struct net_device *netdev;
- + struct list_head list;
- + u16 port_index;
- + struct evb_priv *evb_priv;
- + u8 vlans[VLAN_VID_MASK+1];
- +};
- +
- +struct evb_priv {
- + /* keep first */
- + struct evb_port_priv uplink;
- +
- + struct fsl_mc_io *mc_io;
- + struct list_head port_list;
- + struct dpdmux_attr attr;
- + uint16_t mux_handle;
- + int dev_id;
- +};
- +
- +static int _evb_port_carrier_state_sync(struct net_device *netdev)
- +{
- + struct evb_port_priv *port_priv = netdev_priv(netdev);
- + struct dpdmux_link_state state;
- + int err;
- +
- + err = dpdmux_if_get_link_state(port_priv->evb_priv->mc_io, 0,
- + port_priv->evb_priv->mux_handle,
- + port_priv->port_index, &state);
- + if (unlikely(err)) {
- + netdev_err(netdev, "dpdmux_if_get_link_state() err %d\n", err);
- + return err;
- + }
- +
- + WARN_ONCE(state.up > 1, "Garbage read into link_state");
- +
- + if (state.up)
- + netif_carrier_on(port_priv->netdev);
- + else
- + netif_carrier_off(port_priv->netdev);
- +
- + return 0;
- +}
- +
- +static int evb_port_open(struct net_device *netdev)
- +{
- + int err;
- +
- + /* FIXME: enable port when support added */
- +
- + err = _evb_port_carrier_state_sync(netdev);
- + if (err) {
- + netdev_err(netdev, "ethsw_port_carrier_state_sync err %d\n",
- + err);
- + return err;
- + }
- +
- + return 0;
- +}
- +
- +static netdev_tx_t evb_dropframe(struct sk_buff *skb, struct net_device *dev)
- +{
- + /* we don't support I/O for now, drop the frame */
- + dev_kfree_skb_any(skb);
- + return NETDEV_TX_OK;
- +}
- +
- +static int evb_links_state_update(struct evb_priv *priv)
- +{
- + struct evb_port_priv *port_priv;
- + struct list_head *pos;
- + int err;
- +
- + list_for_each(pos, &priv->port_list) {
- + port_priv = list_entry(pos, struct evb_port_priv, list);
- +
- + err = _evb_port_carrier_state_sync(port_priv->netdev);
- + if (err)
- + netdev_err(port_priv->netdev,
- + "_evb_port_carrier_state_sync err %d\n",
- + err);
- + }
- +
- + return 0;
- +}
- +
- +static irqreturn_t evb_irq0_handler(int irq_num, void *arg)
- +{
- + return IRQ_WAKE_THREAD;
- +}
- +
- +static irqreturn_t _evb_irq0_handler_thread(int irq_num, void *arg)
- +{
- + struct device *dev = (struct device *)arg;
- + struct fsl_mc_device *evb_dev = to_fsl_mc_device(dev);
- + struct net_device *netdev = dev_get_drvdata(dev);
- + struct evb_priv *priv = netdev_priv(netdev);
- + struct fsl_mc_io *io = priv->mc_io;
- + uint16_t token = priv->mux_handle;
- + int irq_index = DPDMUX_IRQ_INDEX_IF;
- + uint32_t status = 0, clear = 0;
- + int err;
- +
- + /* Sanity check */
- + if (WARN_ON(!evb_dev || !evb_dev->irqs || !evb_dev->irqs[irq_index]))
- + goto out;
- + if (WARN_ON(evb_dev->irqs[irq_index]->msi_desc->irq != irq_num))
- + goto out;
- +
- + err = dpdmux_get_irq_status(io, 0, token, irq_index, &status);
- + if (unlikely(err)) {
- + netdev_err(netdev, "Can't get irq status (err %d)", err);
- + clear = 0xffffffff;
- + goto out;
- + }
- +
- + /* FIXME clear irq status */
- +
- + if (status & DPDMUX_IRQ_EVENT_LINK_CHANGED) {
- + clear |= DPDMUX_IRQ_EVENT_LINK_CHANGED;
- +
- + err = evb_links_state_update(priv);
- + if (unlikely(err))
- + goto out;
- + }
- +out:
- + err = dpdmux_clear_irq_status(io, 0, token, irq_index, clear);
- + if (unlikely(err))
- + netdev_err(netdev, "Can't clear irq status (err %d)", err);
- + return IRQ_HANDLED;
- +}
- +
- +static int evb_setup_irqs(struct fsl_mc_device *evb_dev)
- +{
- + struct device *dev = &evb_dev->dev;
- + struct net_device *netdev = dev_get_drvdata(dev);
- + struct evb_priv *priv = netdev_priv(netdev);
- + int err = 0;
- + struct fsl_mc_device_irq *irq;
- + const int irq_index = DPDMUX_IRQ_INDEX_IF;
- + uint32_t mask = ~0x0u; /* FIXME: unmask handled irqs */
- +
- + err = fsl_mc_allocate_irqs(evb_dev);
- + if (unlikely(err)) {
- + dev_err(dev, "MC irqs allocation failed\n");
- + return err;
- + }
- +
- + if (WARN_ON(evb_dev->obj_desc.irq_count != DPDMUX_MAX_IRQ_NUM)) {
- + err = -EINVAL;
- + goto free_irq;
- + }
- +
- + err = dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
- + irq_index, 0);
- + if (unlikely(err)) {
- + dev_err(dev, "dpdmux_set_irq_enable err %d\n", err);
- + goto free_irq;
- + }
- +
- + irq = evb_dev->irqs[irq_index];
- +
- + err = devm_request_threaded_irq(dev, irq->msi_desc->irq,
- + evb_irq0_handler,
- + _evb_irq0_handler_thread,
- + IRQF_NO_SUSPEND | IRQF_ONESHOT,
- + dev_name(dev), dev);
- + if (unlikely(err)) {
- + dev_err(dev, "devm_request_threaded_irq(): %d", err);
- + goto free_irq;
- + }
- +
- + err = dpdmux_set_irq_mask(priv->mc_io, 0, priv->mux_handle,
- + irq_index, mask);
- + if (unlikely(err)) {
- + dev_err(dev, "dpdmux_set_irq_mask(): %d", err);
- + goto free_devm_irq;
- + }
- +
- + err = dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
- + irq_index, 1);
- + if (unlikely(err)) {
- + dev_err(dev, "dpdmux_set_irq_enable(): %d", err);
- + goto free_devm_irq;
- + }
- +
- + return 0;
- +
- +free_devm_irq:
- + devm_free_irq(dev, irq->msi_desc->irq, dev);
- +free_irq:
- + fsl_mc_free_irqs(evb_dev);
- + return err;
- +}
- +
- +static void evb_teardown_irqs(struct fsl_mc_device *evb_dev)
- +{
- + struct device *dev = &evb_dev->dev;
- + struct net_device *netdev = dev_get_drvdata(dev);
- + struct evb_priv *priv = netdev_priv(netdev);
- +
- + dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle,
- + DPDMUX_IRQ_INDEX_IF, 0);
- +
- + devm_free_irq(dev,
- + evb_dev->irqs[DPDMUX_IRQ_INDEX_IF]->msi_desc->irq,
- + dev);
- + fsl_mc_free_irqs(evb_dev);
- +}
- +
- +static int evb_port_add_rule(struct net_device *netdev,
- + const unsigned char *addr, u16 vid)
- +{
- + struct evb_port_priv *port_priv = netdev_priv(netdev);
- + struct dpdmux_l2_rule rule = { .vlan_id = vid };
- + int err;
- +
- + if (addr)
- + ether_addr_copy(rule.mac_addr, addr);
- +
- + err = dpdmux_if_add_l2_rule(port_priv->evb_priv->mc_io,
- + 0,
- + port_priv->evb_priv->mux_handle,
- + port_priv->port_index, &rule);
- + if (unlikely(err))
- + netdev_err(netdev, "dpdmux_if_add_l2_rule err %d\n", err);
- + return err;
- +}
- +
- +static int evb_port_del_rule(struct net_device *netdev,
- + const unsigned char *addr, u16 vid)
- +{
- + struct evb_port_priv *port_priv = netdev_priv(netdev);
- + struct dpdmux_l2_rule rule = { .vlan_id = vid };
- + int err;
- +
- + if (addr)
- + ether_addr_copy(rule.mac_addr, addr);
- +
- + err = dpdmux_if_remove_l2_rule(port_priv->evb_priv->mc_io,
- + 0,
- + port_priv->evb_priv->mux_handle,
- + port_priv->port_index, &rule);
- + if (unlikely(err))
- + netdev_err(netdev, "dpdmux_if_remove_l2_rule err %d\n", err);
- + return err;
- +}
- +
- +static bool _lookup_address(struct net_device *netdev,
- + const unsigned char *addr)
- +{
- + struct netdev_hw_addr *ha;
- + struct netdev_hw_addr_list *list = (is_unicast_ether_addr(addr)) ?
- + &netdev->uc : &netdev->mc;
- +
- + netif_addr_lock_bh(netdev);
- + list_for_each_entry(ha, &list->list, list) {
- + if (ether_addr_equal(ha->addr, addr)) {
- + netif_addr_unlock_bh(netdev);
- + return true;
- + }
- + }
- + netif_addr_unlock_bh(netdev);
- + return false;
- +}
- +
- +static inline int evb_port_fdb_prep(struct nlattr *tb[],
- + struct net_device *netdev,
- + const unsigned char *addr, u16 *vid,
- + bool del)
- +{
- + struct evb_port_priv *port_priv = netdev_priv(netdev);
- + struct evb_priv *evb_priv = port_priv->evb_priv;
- +
- + *vid = 0;
- +
- + if (evb_priv->attr.method != DPDMUX_METHOD_MAC &&
- + evb_priv->attr.method != DPDMUX_METHOD_C_VLAN_MAC) {
- + netdev_err(netdev,
- + "EVB mode does not support MAC classification\n");
- + return -EOPNOTSUPP;
- + }
- +
- + /* check if the address is configured on this port */
- + if (_lookup_address(netdev, addr)) {
- + if (!del)
- + return -EEXIST;
- + } else {
- + if (del)
- + return -ENOENT;
- + }
- +
- + if (tb[NDA_VLAN] && evb_priv->attr.method == DPDMUX_METHOD_C_VLAN_MAC) {
- + if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) {
- + netdev_err(netdev, "invalid vlan size %d\n",
- + nla_len(tb[NDA_VLAN]));
- + return -EINVAL;
- + }
- +
- + *vid = nla_get_u16(tb[NDA_VLAN]);
- +
- + if (!*vid || *vid >= VLAN_VID_MASK) {
- + netdev_err(netdev, "invalid vid value 0x%04x\n", *vid);
- + return -EINVAL;
- + }
- + } else if (evb_priv->attr.method == DPDMUX_METHOD_C_VLAN_MAC) {
- + netdev_err(netdev,
- + "EVB mode requires explicit VLAN configuration\n");
- + return -EINVAL;
- + } else if (tb[NDA_VLAN]) {
- + netdev_warn(netdev, "VLAN not supported, argument ignored\n");
- + }
- +
- + return 0;
- +}
- +
- +static int evb_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
- + struct net_device *netdev,
- + const unsigned char *addr, u16 vid, u16 flags)
- +{
- + u16 _vid;
- + int err;
- +
- + /* TODO: add replace support when added to iproute bridge */
- + if (!(flags & NLM_F_REQUEST)) {
- + netdev_err(netdev,
- + "evb_port_fdb_add unexpected flags value %08x\n",
- + flags);
- + return -EINVAL;
- + }
- +
- + err = evb_port_fdb_prep(tb, netdev, addr, &_vid, 0);
- + if (unlikely(err))
- + return err;
- +
- +
- + err = evb_port_add_rule(netdev, addr, _vid);
- + if (unlikely(err))
- + return err;
- +
- + if (is_unicast_ether_addr(addr)) {
- + err = dev_uc_add(netdev, addr);
- + if (unlikely(err)) {
- + netdev_err(netdev, "dev_uc_add err %d\n", err);
- + return err;
- + }
- + } else {
- + err = dev_mc_add(netdev, addr);
- + if (unlikely(err)) {
- + netdev_err(netdev, "dev_mc_add err %d\n", err);
- + return err;
- + }
- + }
- +
- + return 0;
- +}
- +
- +static int evb_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
- + struct net_device *netdev,
- + const unsigned char *addr, u16 vid)
- +{
- + u16 _vid;
- + int err;
- +
- + err = evb_port_fdb_prep(tb, netdev, addr, &_vid, 1);
- + if (unlikely(err))
- + return err;
- +
- + err = evb_port_del_rule(netdev, addr, _vid);
- + if (unlikely(err))
- + return err;
- +
- + if (is_unicast_ether_addr(addr)) {
- + err = dev_uc_del(netdev, addr);
- + if (unlikely(err)) {
- + netdev_err(netdev, "dev_uc_del err %d\n", err);
- + return err;
- + }
- + } else {
- + err = dev_mc_del(netdev, addr);
- + if (unlikely(err)) {
- + netdev_err(netdev, "dev_mc_del err %d\n", err);
- + return err;
- + }
- + }
- +
- + return 0;
- +}
- +
- +static int evb_change_mtu(struct net_device *netdev,
- + int mtu)
- +{
- + struct evb_port_priv *port_priv = netdev_priv(netdev);
- + struct evb_priv *evb_priv = port_priv->evb_priv;
- + struct list_head *pos;
- + int err = 0;
- +
- + /* This operation is not permitted on downlinks */
- + if (port_priv->port_index > 0)
- + return -EPERM;
- +
- + if (mtu < EVB_MIN_FRAME_LENGTH || mtu > EVB_MAX_FRAME_LENGTH) {
- + netdev_err(netdev, "Invalid MTU %d. Valid range is: %d..%d\n",
- + mtu, EVB_MIN_FRAME_LENGTH, EVB_MAX_FRAME_LENGTH);
- + return -EINVAL;
- + }
- +
- + err = dpdmux_ul_set_max_frame_length(evb_priv->mc_io,
- + 0,
- + evb_priv->mux_handle,
- + (uint16_t)mtu);
- +
- + if (unlikely(err)) {
- + netdev_err(netdev, "dpdmux_ul_set_max_frame_length err %d\n",
- + err);
- + return err;
- + }
- +
- + /* Update the max frame length for downlinks */
- + list_for_each(pos, &evb_priv->port_list) {
- + port_priv = list_entry(pos, struct evb_port_priv, list);
- + port_priv->netdev->mtu = mtu;
- + }
- +
- + netdev->mtu = mtu;
- + return 0;
- +}
- +
- +static const struct nla_policy ifla_br_policy[IFLA_MAX+1] = {
- + [IFLA_BRIDGE_FLAGS] = { .type = NLA_U16 },
- + [IFLA_BRIDGE_MODE] = { .type = NLA_U16 },
- + [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY,
- + .len = sizeof(struct bridge_vlan_info), },
- +};
- +
- +static int evb_setlink_af_spec(struct net_device *netdev,
- + struct nlattr **tb)
- +{
- + struct bridge_vlan_info *vinfo;
- + struct evb_port_priv *port_priv = netdev_priv(netdev);
- + int err = 0;
- +
- + if (!tb[IFLA_BRIDGE_VLAN_INFO]) {
- + netdev_err(netdev, "no VLAN INFO in nlmsg\n");
- + return -EOPNOTSUPP;
- + }
- +
- + vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
- +
- + if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK)
- + return -EINVAL;
- +
- + err = evb_port_add_rule(netdev, NULL, vinfo->vid);
- + if (unlikely(err))
- + return err;
- +
- + port_priv->vlans[vinfo->vid] = 1;
- +
- + return 0;
- +}
- +
- +static int evb_setlink(struct net_device *netdev,
- + struct nlmsghdr *nlh,
- + u16 flags)
- +{
- + struct evb_port_priv *port_priv = netdev_priv(netdev);
- + struct evb_priv *evb_priv = port_priv->evb_priv;
- + struct nlattr *attr;
- + struct nlattr *tb[(IFLA_BRIDGE_MAX > IFLA_BRPORT_MAX) ?
- + IFLA_BRIDGE_MAX : IFLA_BRPORT_MAX+1];
- + int err = 0;
- +
- + if (evb_priv->attr.method != DPDMUX_METHOD_C_VLAN &&
- + evb_priv->attr.method != DPDMUX_METHOD_S_VLAN) {
- + netdev_err(netdev,
- + "EVB mode does not support VLAN only classification\n");
- + return -EOPNOTSUPP;
- + }
- +
- + attr = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
- + if (attr) {
- + err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, attr,
- + ifla_br_policy);
- + if (unlikely(err)) {
- + netdev_err(netdev,
- + "nla_parse_nested for br_policy err %d\n",
- + err);
- + return err;
- + }
- +
- + err = evb_setlink_af_spec(netdev, tb);
- + return err;
- + }
- +
- + netdev_err(netdev, "nlmsg_find_attr found no AF_SPEC\n");
- + return -EOPNOTSUPP;
- +}
- +
- +static int __nla_put_netdev(struct sk_buff *skb, struct net_device *netdev)
- +{
- + struct evb_port_priv *port_priv = netdev_priv(netdev);
- + struct evb_priv *evb_priv = port_priv->evb_priv;
- + u8 operstate = netif_running(netdev) ?
- + netdev->operstate : IF_OPER_DOWN;
- + int iflink;
- + int err;
- +
- + err = nla_put_string(skb, IFLA_IFNAME, netdev->name);
- + if (unlikely(err))
- + goto nla_put_err;
- + err = nla_put_u32(skb, IFLA_MASTER, evb_priv->uplink.netdev->ifindex);
- + if (unlikely(err))
- + goto nla_put_err;
- + err = nla_put_u32(skb, IFLA_MTU, netdev->mtu);
- + if (unlikely(err))
- + goto nla_put_err;
- + err = nla_put_u8(skb, IFLA_OPERSTATE, operstate);
- + if (unlikely(err))
- + goto nla_put_err;
- + if (netdev->addr_len) {
- + err = nla_put(skb, IFLA_ADDRESS, netdev->addr_len,
- + netdev->dev_addr);
- + if (unlikely(err))
- + goto nla_put_err;
- + }
- +
- + iflink = dev_get_iflink(netdev);
- + if (netdev->ifindex != iflink) {
- + err = nla_put_u32(skb, IFLA_LINK, iflink);
- + if (unlikely(err))
- + goto nla_put_err;
- + }
- +
- + return 0;
- +
- +nla_put_err:
- + netdev_err(netdev, "nla_put_ err %d\n", err);
- + return err;
- +}
- +
- +static int __nla_put_port(struct sk_buff *skb, struct net_device *netdev)
- +{
- + struct nlattr *nest;
- + int err;
- +
- + nest = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED);
- + if (!nest) {
- + netdev_err(netdev, "nla_nest_start failed\n");
- + return -ENOMEM;
- + }
- +
- + err = nla_put_u8(skb, IFLA_BRPORT_STATE, BR_STATE_FORWARDING);
- + if (unlikely(err))
- + goto nla_put_err;
- + err = nla_put_u16(skb, IFLA_BRPORT_PRIORITY, 0);
- + if (unlikely(err))
- + goto nla_put_err;
- + err = nla_put_u32(skb, IFLA_BRPORT_COST, 0);
- + if (unlikely(err))
- + goto nla_put_err;
- + err = nla_put_u8(skb, IFLA_BRPORT_MODE, 0);
- + if (unlikely(err))
- + goto nla_put_err;
- + err = nla_put_u8(skb, IFLA_BRPORT_GUARD, 0);
- + if (unlikely(err))
- + goto nla_put_err;
- + err = nla_put_u8(skb, IFLA_BRPORT_PROTECT, 0);
- + if (unlikely(err))
- + goto nla_put_err;
- + err = nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, 0);
- + if (unlikely(err))
- + goto nla_put_err;
- + err = nla_put_u8(skb, IFLA_BRPORT_LEARNING, 0);
- + if (unlikely(err))
- + goto nla_put_err;
- + err = nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, 1);
- + if (unlikely(err))
- + goto nla_put_err;
- + nla_nest_end(skb, nest);
- +
- + return 0;
- +
- +nla_put_err:
- + netdev_err(netdev, "nla_put_ err %d\n", err);
- + nla_nest_cancel(skb, nest);
- + return err;
- +}
- +
- +static int __nla_put_vlan(struct sk_buff *skb, struct net_device *netdev)
- +{
- + struct evb_port_priv *port_priv = netdev_priv(netdev);
- + struct nlattr *nest;
- + struct bridge_vlan_info vinfo;
- + const u8 *vlans = port_priv->vlans;
- + u16 i;
- + int err;
- +
- + nest = nla_nest_start(skb, IFLA_AF_SPEC);
- + if (!nest) {
- + netdev_err(netdev, "nla_nest_start failed");
- + return -ENOMEM;
- + }
- +
- + for (i = 0; i < VLAN_VID_MASK+1; i++) {
- + if (!vlans[i])
- + continue;
- +
- + vinfo.flags = 0;
- + vinfo.vid = i;
- +
- + err = nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
- + sizeof(vinfo), &vinfo);
- + if (unlikely(err))
- + goto nla_put_err;
- + }
- +
- + nla_nest_end(skb, nest);
- +
- + return 0;
- +
- +nla_put_err:
- + netdev_err(netdev, "nla_put_ err %d\n", err);
- + nla_nest_cancel(skb, nest);
- + return err;
- +}
- +
- +static int evb_getlink(struct sk_buff *skb, u32 pid, u32 seq,
- + struct net_device *netdev, u32 filter_mask, int nlflags)
- +{
- + struct evb_port_priv *port_priv = netdev_priv(netdev);
- + struct evb_priv *evb_priv = port_priv->evb_priv;
- + struct ifinfomsg *hdr;
- + struct nlmsghdr *nlh;
- + int err;
- +
- + if (evb_priv->attr.method != DPDMUX_METHOD_C_VLAN &&
- + evb_priv->attr.method != DPDMUX_METHOD_S_VLAN) {
- + return 0;
- + }
- +
- + nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*hdr), NLM_F_MULTI);
- + if (!nlh)
- + return -EMSGSIZE;
- +
- + hdr = nlmsg_data(nlh);
- + memset(hdr, 0, sizeof(*hdr));
- + hdr->ifi_family = AF_BRIDGE;
- + hdr->ifi_type = netdev->type;
- + hdr->ifi_index = netdev->ifindex;
- + hdr->ifi_flags = dev_get_flags(netdev);
- +
- + err = __nla_put_netdev(skb, netdev);
- + if (unlikely(err))
- + goto nla_put_err;
- +
- + err = __nla_put_port(skb, netdev);
- + if (unlikely(err))
- + goto nla_put_err;
- +
- + /* Check if the VID information is requested */
- + if (filter_mask & RTEXT_FILTER_BRVLAN) {
- + err = __nla_put_vlan(skb, netdev);
- + if (unlikely(err))
- + goto nla_put_err;
- + }
- +
- + nlmsg_end(skb, nlh);
- + return skb->len;
- +
- +nla_put_err:
- + nlmsg_cancel(skb, nlh);
- + return -EMSGSIZE;
- +}
- +
- +static int evb_dellink(struct net_device *netdev,
- + struct nlmsghdr *nlh,
- + u16 flags)
- +{
- + struct nlattr *tb[IFLA_BRIDGE_MAX+1];
- + struct nlattr *spec;
- + struct bridge_vlan_info *vinfo;
- + struct evb_port_priv *port_priv = netdev_priv(netdev);
- + int err = 0;
- +
- + spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
- + if (!spec)
- + return 0;
- +
- + err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, spec, ifla_br_policy);
- + if (unlikely(err))
- + return err;
- +
- + if (!tb[IFLA_BRIDGE_VLAN_INFO])
- + return -EOPNOTSUPP;
- +
- + vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]);
- +
- + if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK)
- + return -EINVAL;
- +
- + err = evb_port_del_rule(netdev, NULL, vinfo->vid);
- + if (unlikely(err)) {
- + netdev_err(netdev, "evb_port_del_rule err %d\n", err);
- + return err;
- + }
- + port_priv->vlans[vinfo->vid] = 0;
- +
- + return 0;
- +}
- +
- +static struct rtnl_link_stats64 *
- +evb_port_get_stats(struct net_device *netdev,
- + struct rtnl_link_stats64 *storage)
- +{
- + struct evb_port_priv *port_priv = netdev_priv(netdev);
- + u64 tmp;
- + int err;
- +
- + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
- + 0,
- + port_priv->evb_priv->mux_handle,
- + port_priv->port_index,
- + DPDMUX_CNT_ING_FRAME, &storage->rx_packets);
- + if (unlikely(err))
- + goto error;
- +
- + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
- + 0,
- + port_priv->evb_priv->mux_handle,
- + port_priv->port_index,
- + DPDMUX_CNT_ING_BYTE, &storage->rx_bytes);
- + if (unlikely(err))
- + goto error;
- +
- + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
- + 0,
- + port_priv->evb_priv->mux_handle,
- + port_priv->port_index,
- + DPDMUX_CNT_ING_FLTR_FRAME, &tmp);
- + if (unlikely(err))
- + goto error;
- +
- + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
- + 0,
- + port_priv->evb_priv->mux_handle,
- + port_priv->port_index,
- + DPDMUX_CNT_ING_FRAME_DISCARD,
- + &storage->rx_dropped);
- + if (unlikely(err)) {
- + storage->rx_dropped = tmp;
- + goto error;
- + }
- + storage->rx_dropped += tmp;
- +
- + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
- + 0,
- + port_priv->evb_priv->mux_handle,
- + port_priv->port_index,
- + DPDMUX_CNT_ING_MCAST_FRAME,
- + &storage->multicast);
- + if (unlikely(err))
- + goto error;
- +
- + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
- + 0,
- + port_priv->evb_priv->mux_handle,
- + port_priv->port_index,
- + DPDMUX_CNT_EGR_FRAME, &storage->tx_packets);
- + if (unlikely(err))
- + goto error;
- +
- + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
- + 0,
- + port_priv->evb_priv->mux_handle,
- + port_priv->port_index,
- + DPDMUX_CNT_EGR_BYTE, &storage->tx_bytes);
- + if (unlikely(err))
- + goto error;
- +
- + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
- + 0,
- + port_priv->evb_priv->mux_handle,
- + port_priv->port_index,
- + DPDMUX_CNT_EGR_FRAME_DISCARD,
- + &storage->tx_dropped);
- + if (unlikely(err))
- + goto error;
- +
- + return storage;
- +
- +error:
- + netdev_err(netdev, "dpdmux_if_get_counter err %d\n", err);
- + return storage;
- +}
- +
- +static const struct net_device_ops evb_port_ops = {
- + .ndo_open = &evb_port_open,
- +
- + .ndo_start_xmit = &evb_dropframe,
- +
- + .ndo_fdb_add = &evb_port_fdb_add,
- + .ndo_fdb_del = &evb_port_fdb_del,
- +
- + .ndo_get_stats64 = &evb_port_get_stats,
- + .ndo_change_mtu = &evb_change_mtu,
- +};
- +
- +static struct {
- + enum dpdmux_counter_type id;
- + char name[ETH_GSTRING_LEN];
- +} evb_ethtool_counters[] = {
- + {DPDMUX_CNT_ING_FRAME, "rx frames"},
- + {DPDMUX_CNT_ING_BYTE, "rx bytes"},
- + {DPDMUX_CNT_ING_FLTR_FRAME, "rx filtered frames"},
- + {DPDMUX_CNT_ING_FRAME_DISCARD, "rx discarded frames"},
- + {DPDMUX_CNT_ING_BCAST_FRAME, "rx b-cast frames"},
- + {DPDMUX_CNT_ING_BCAST_BYTES, "rx b-cast bytes"},
- + {DPDMUX_CNT_ING_MCAST_FRAME, "rx m-cast frames"},
- + {DPDMUX_CNT_ING_MCAST_BYTE, "rx m-cast bytes"},
- + {DPDMUX_CNT_EGR_FRAME, "tx frames"},
- + {DPDMUX_CNT_EGR_BYTE, "tx bytes"},
- + {DPDMUX_CNT_EGR_FRAME_DISCARD, "tx discarded frames"},
- +};
- +
- +static int evb_ethtool_get_sset_count(struct net_device *dev, int sset)
- +{
- + switch (sset) {
- + case ETH_SS_STATS:
- + return ARRAY_SIZE(evb_ethtool_counters);
- + default:
- + return -EOPNOTSUPP;
- + }
- +}
- +
- +static void evb_ethtool_get_strings(struct net_device *netdev,
- + u32 stringset, u8 *data)
- +{
- + int i;
- +
- + switch (stringset) {
- + case ETH_SS_STATS:
- + for (i = 0; i < ARRAY_SIZE(evb_ethtool_counters); i++)
- + memcpy(data + i * ETH_GSTRING_LEN,
- + evb_ethtool_counters[i].name, ETH_GSTRING_LEN);
- + break;
- + }
- +}
- +
- +static void evb_ethtool_get_stats(struct net_device *netdev,
- + struct ethtool_stats *stats,
- + u64 *data)
- +{
- + struct evb_port_priv *port_priv = netdev_priv(netdev);
- + int i;
- + int err;
- +
- + for (i = 0; i < ARRAY_SIZE(evb_ethtool_counters); i++) {
- + err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io,
- + 0,
- + port_priv->evb_priv->mux_handle,
- + port_priv->port_index,
- + evb_ethtool_counters[i].id,
- + &data[i]);
- + if (err)
- + netdev_err(netdev, "dpdmux_if_get_counter[%s] err %d\n",
- + evb_ethtool_counters[i].name, err);
- + }
- +}
- +
- +static const struct ethtool_ops evb_port_ethtool_ops = {
- + .get_strings = &evb_ethtool_get_strings,
- + .get_ethtool_stats = &evb_ethtool_get_stats,
- + .get_sset_count = &evb_ethtool_get_sset_count,
- +};
- +
- +static int evb_open(struct net_device *netdev)
- +{
- + struct evb_priv *priv = netdev_priv(netdev);
- + int err = 0;
- +
- + err = dpdmux_enable(priv->mc_io, 0, priv->mux_handle);
- + if (unlikely(err))
- + netdev_err(netdev, "dpdmux_enable err %d\n", err);
- +
- + return err;
- +}
- +
- +static int evb_close(struct net_device *netdev)
- +{
- + struct evb_priv *priv = netdev_priv(netdev);
- + int err = 0;
- +
- + err = dpdmux_disable(priv->mc_io, 0, priv->mux_handle);
- + if (unlikely(err))
- + netdev_err(netdev, "dpdmux_disable err %d\n", err);
- +
- + return err;
- +}
- +
- +static const struct net_device_ops evb_ops = {
- + .ndo_start_xmit = &evb_dropframe,
- + .ndo_open = &evb_open,
- + .ndo_stop = &evb_close,
- +
- + .ndo_bridge_setlink = &evb_setlink,
- + .ndo_bridge_getlink = &evb_getlink,
- + .ndo_bridge_dellink = &evb_dellink,
- +
- + .ndo_get_stats64 = &evb_port_get_stats,
- + .ndo_change_mtu = &evb_change_mtu,
- +};
- +
- +static int evb_takedown(struct fsl_mc_device *evb_dev)
- +{
- + struct device *dev = &evb_dev->dev;
- + struct net_device *netdev = dev_get_drvdata(dev);
- + struct evb_priv *priv = netdev_priv(netdev);
- + int err;
- +
- + err = dpdmux_close(priv->mc_io, 0, priv->mux_handle);
- + if (unlikely(err))
- + dev_warn(dev, "dpdmux_close err %d\n", err);
- +
- + return 0;
- +}
- +
- +static int evb_init(struct fsl_mc_device *evb_dev)
- +{
- + struct device *dev = &evb_dev->dev;
- + struct net_device *netdev = dev_get_drvdata(dev);
- + struct evb_priv *priv = netdev_priv(netdev);
- + int err = 0;
- +
- + priv->dev_id = evb_dev->obj_desc.id;
- +
- + err = dpdmux_open(priv->mc_io, 0, priv->dev_id, &priv->mux_handle);
- + if (unlikely(err)) {
- + dev_err(dev, "dpdmux_open err %d\n", err);
- + goto err_exit;
- + }
- + if (!priv->mux_handle) {
- + dev_err(dev, "dpdmux_open returned null handle but no error\n");
- + err = -EFAULT;
- + goto err_exit;
- + }
- +
- + err = dpdmux_get_attributes(priv->mc_io, 0, priv->mux_handle,
- + &priv->attr);
- + if (unlikely(err)) {
- + dev_err(dev, "dpdmux_get_attributes err %d\n", err);
- + goto err_close;
- + }
- +
- + err = dpdmux_reset(priv->mc_io, 0, priv->mux_handle);
- + if (unlikely(err)) {
- + dev_err(dev, "dpdmux_reset err %d\n", err);
- + goto err_close;
- + }
- +
- + return 0;
- +
- +err_close:
- + dpdmux_close(priv->mc_io, 0, priv->mux_handle);
- +err_exit:
- + return err;
- +}
- +
- +static int evb_remove(struct fsl_mc_device *evb_dev)
- +{
- + struct device *dev = &evb_dev->dev;
- + struct net_device *netdev = dev_get_drvdata(dev);
- + struct evb_priv *priv = netdev_priv(netdev);
- + struct evb_port_priv *port_priv;
- + struct list_head *pos;
- +
- + list_for_each(pos, &priv->port_list) {
- + port_priv = list_entry(pos, struct evb_port_priv, list);
- +
- + rtnl_lock();
- + netdev_upper_dev_unlink(port_priv->netdev, netdev);
- + rtnl_unlock();
- +
- + unregister_netdev(port_priv->netdev);
- + free_netdev(port_priv->netdev);
- + }
- +
- + evb_teardown_irqs(evb_dev);
- +
- + unregister_netdev(netdev);
- +
- + evb_takedown(evb_dev);
- + fsl_mc_portal_free(priv->mc_io);
- +
- + dev_set_drvdata(dev, NULL);
- + free_netdev(netdev);
- +
- + return 0;
- +}
- +
- +static int evb_probe(struct fsl_mc_device *evb_dev)
- +{
- + struct device *dev;
- + struct evb_priv *priv = NULL;
- + struct net_device *netdev = NULL;
- + char port_name[IFNAMSIZ];
- + int i;
- + int err = 0;
- +
- + dev = &evb_dev->dev;
- +
- + /* register switch device, it's for management only - no I/O */
- + netdev = alloc_etherdev(sizeof(*priv));
- + if (!netdev) {
- + dev_err(dev, "alloc_etherdev error\n");
- + return -ENOMEM;
- + }
- + netdev->netdev_ops = &evb_ops;
- +
- + dev_set_drvdata(dev, netdev);
- +
- + priv = netdev_priv(netdev);
- +
- + err = fsl_mc_portal_allocate(evb_dev, 0, &priv->mc_io);
- + if (unlikely(err)) {
- + dev_err(dev, "fsl_mc_portal_allocate err %d\n", err);
- + goto err_free_netdev;
- + }
- + if (!priv->mc_io) {
- + dev_err(dev, "fsl_mc_portal_allocate returned null handle but no error\n");
- + err = -EFAULT;
- + goto err_free_netdev;
- + }
- +
- + err = evb_init(evb_dev);
- + if (unlikely(err)) {
- + dev_err(dev, "evb init err %d\n", err);
- + goto err_free_cmdport;
- + }
- +
- + INIT_LIST_HEAD(&priv->port_list);
- + netdev->flags |= IFF_PROMISC | IFF_MASTER;
- +
- + dev_alloc_name(netdev, "evb%d");
- +
- + /* register switch ports */
- + snprintf(port_name, IFNAMSIZ, "%sp%%d", netdev->name);
- +
- + /* only register downlinks? */
- + for (i = 0; i < priv->attr.num_ifs + 1; i++) {
- + struct net_device *port_netdev;
- + struct evb_port_priv *port_priv;
- +
- + if (i) {
- + port_netdev =
- + alloc_etherdev(sizeof(struct evb_port_priv));
- + if (!port_netdev) {
- + dev_err(dev, "alloc_etherdev error\n");
- + goto err_takedown;
- + }
- +
- + port_priv = netdev_priv(port_netdev);
- +
- + port_netdev->flags |= IFF_PROMISC | IFF_SLAVE;
- +
- + dev_alloc_name(port_netdev, port_name);
- + } else {
- + port_netdev = netdev;
- + port_priv = &priv->uplink;
- + }
- +
- + port_priv->netdev = port_netdev;
- + port_priv->evb_priv = priv;
- + port_priv->port_index = i;
- +
- + SET_NETDEV_DEV(port_netdev, dev);
- +
- + if (i) {
- + port_netdev->netdev_ops = &evb_port_ops;
- +
- + err = register_netdev(port_netdev);
- + if (err < 0) {
- + dev_err(dev, "register_netdev err %d\n", err);
- + free_netdev(port_netdev);
- + goto err_takedown;
- + }
- +
- + rtnl_lock();
- + err = netdev_master_upper_dev_link(port_netdev, netdev, NULL, NULL);
- + if (unlikely(err)) {
- + dev_err(dev, "netdev_master_upper_dev_link err %d\n",
- + err);
- + unregister_netdev(port_netdev);
- + free_netdev(port_netdev);
- + rtnl_unlock();
- + goto err_takedown;
- + }
- + rtmsg_ifinfo(RTM_NEWLINK, port_netdev,
- + IFF_SLAVE, GFP_KERNEL);
- + rtnl_unlock();
- +
- + list_add(&(port_priv->list), &(priv->port_list));
- + } else {
- + err = register_netdev(netdev);
- +
- + if (err < 0) {
- + dev_err(dev, "register_netdev error %d\n", err);
- + goto err_takedown;
- + }
- + }
- +
- + port_netdev->ethtool_ops = &evb_port_ethtool_ops;
- +
- + /* ports are up from init */
- + rtnl_lock();
- + err = dev_open(port_netdev);
- + rtnl_unlock();
- + if (unlikely(err))
- + dev_warn(dev, "dev_open err %d\n", err);
- + }
- +
- + /* setup irqs */
- + err = evb_setup_irqs(evb_dev);
- + if (unlikely(err)) {
- + dev_warn(dev, "evb_setup_irqs err %d\n", err);
- + goto err_takedown;
- + }
- +
- + dev_info(dev, "probed evb device with %d ports\n",
- + priv->attr.num_ifs);
- + return 0;
- +
- +err_takedown:
- + evb_remove(evb_dev);
- +err_free_cmdport:
- + fsl_mc_portal_free(priv->mc_io);
- +err_free_netdev:
- + return err;
- +}
- +
- +static const struct fsl_mc_device_match_id evb_match_id_table[] = {
- + {
- + .vendor = FSL_MC_VENDOR_FREESCALE,
- + .obj_type = "dpdmux",
- + .ver_major = DPDMUX_VER_MAJOR,
- + .ver_minor = DPDMUX_VER_MINOR,
- + },
- + {}
- +};
- +
- +static struct fsl_mc_driver evb_drv = {
- + .driver = {
- + .name = KBUILD_MODNAME,
- + .owner = THIS_MODULE,
- + },
- + .probe = evb_probe,
- + .remove = evb_remove,
- + .match_id_table = evb_match_id_table,
- +};
- +
- +module_fsl_mc_driver(evb_drv);
- +
- +MODULE_LICENSE("GPL");
- +MODULE_DESCRIPTION("Layerscape DPAA Edge Virtual Bridge driver (prototype)");
|