| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496 |
- // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
- /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
- #include <linux/kernel.h>
- #include <linux/bitops.h>
- #include <linux/if_vlan.h>
- #include <linux/if_bridge.h>
- #include <linux/netdevice.h>
- #include <linux/rhashtable.h>
- #include <linux/rtnetlink.h>
- #include <linux/refcount.h>
- #include "spectrum.h"
- #include "spectrum_router.h"
- #include "reg.h"
- struct mlxsw_sp_fid_family;
- struct mlxsw_sp_fid_core {
- struct rhashtable fid_ht;
- struct rhashtable vni_ht;
- struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
- unsigned int *port_fid_mappings;
- };
- struct mlxsw_sp_fid_port_vid {
- struct list_head list;
- u16 local_port;
- u16 vid;
- };
- struct mlxsw_sp_fid {
- struct list_head list;
- struct mlxsw_sp_rif *rif;
- refcount_t ref_count;
- u16 fid_index;
- u16 fid_offset;
- struct mlxsw_sp_fid_family *fid_family;
- struct rhash_head ht_node;
- struct rhash_head vni_ht_node;
- enum mlxsw_sp_nve_type nve_type;
- __be32 vni;
- u32 nve_flood_index;
- int nve_ifindex;
- u8 vni_valid:1,
- nve_flood_index_valid:1;
- struct list_head port_vid_list; /* Ordered by local port. */
- };
- struct mlxsw_sp_fid_8021q {
- struct mlxsw_sp_fid common;
- u16 vid;
- };
- struct mlxsw_sp_fid_8021d {
- struct mlxsw_sp_fid common;
- int br_ifindex;
- };
- static const struct rhashtable_params mlxsw_sp_fid_ht_params = {
- .key_len = sizeof_field(struct mlxsw_sp_fid, fid_index),
- .key_offset = offsetof(struct mlxsw_sp_fid, fid_index),
- .head_offset = offsetof(struct mlxsw_sp_fid, ht_node),
- };
- static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = {
- .key_len = sizeof_field(struct mlxsw_sp_fid, vni),
- .key_offset = offsetof(struct mlxsw_sp_fid, vni),
- .head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node),
- };
- struct mlxsw_sp_flood_table {
- enum mlxsw_sp_flood_type packet_type;
- enum mlxsw_flood_table_type table_type; /* For flood_mode!=CFF. */
- int table_index;
- };
- struct mlxsw_sp_fid_ops {
- int (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
- int (*configure)(struct mlxsw_sp_fid *fid);
- void (*deconfigure)(struct mlxsw_sp_fid *fid);
- int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
- u16 *p_fid_index);
- bool (*compare)(const struct mlxsw_sp_fid *fid,
- const void *arg);
- int (*port_vid_map)(struct mlxsw_sp_fid *fid,
- struct mlxsw_sp_port *port, u16 vid);
- void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
- struct mlxsw_sp_port *port, u16 vid);
- int (*vni_set)(struct mlxsw_sp_fid *fid);
- void (*vni_clear)(struct mlxsw_sp_fid *fid);
- int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid);
- void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);
- void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid,
- const struct net_device *nve_dev);
- int (*vid_to_fid_rif_update)(const struct mlxsw_sp_fid *fid,
- const struct mlxsw_sp_rif *rif);
- int (*flood_table_init)(struct mlxsw_sp_fid_family *fid_family,
- const struct mlxsw_sp_flood_table *flood_table);
- int (*pgt_size)(const struct mlxsw_sp_fid_family *fid_family,
- u16 *p_pgt_size);
- u16 (*fid_mid)(const struct mlxsw_sp_fid *fid,
- const struct mlxsw_sp_flood_table *flood_table);
- void (*fid_pack)(char *sfmr_pl, const struct mlxsw_sp_fid *fid,
- enum mlxsw_reg_sfmr_op op);
- /* These are specific to RFID families and we assume are only
- * implemented by RFID families, if at all.
- */
- int (*fid_port_init)(const struct mlxsw_sp_fid_family *fid_family,
- const struct mlxsw_sp_port *mlxsw_sp_port);
- void (*fid_port_fini)(const struct mlxsw_sp_fid_family *fid_family,
- const struct mlxsw_sp_port *mlxsw_sp_port);
- };
- enum mlxsw_sp_fid_flood_profile_id {
- MLXSW_SP_FID_FLOOD_PROFILE_ID_BRIDGE = 1,
- MLXSW_SP_FID_FLOOD_PROFILE_ID_RSP,
- MLXSW_SP_FID_FLOOD_PROFILE_ID_NVE,
- };
- struct mlxsw_sp_fid_flood_profile {
- const struct mlxsw_sp_flood_table *flood_tables;
- int nr_flood_tables;
- const enum mlxsw_sp_fid_flood_profile_id profile_id; /* For CFF mode. */
- };
- struct mlxsw_sp_fid_family {
- enum mlxsw_sp_fid_type type;
- size_t fid_size;
- u16 start_index;
- u16 end_index;
- struct list_head fids_list;
- unsigned long *fids_bitmap;
- const struct mlxsw_sp_fid_flood_profile *flood_profile;
- enum mlxsw_sp_rif_type rif_type;
- const struct mlxsw_sp_fid_ops *ops;
- struct mlxsw_sp *mlxsw_sp;
- bool flood_rsp; /* For flood_mode!=CFF. */
- enum mlxsw_reg_bridge_type bridge_type;
- u16 pgt_base;
- bool smpe_index_valid;
- };
- static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
- [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1,
- };
- static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
- [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1,
- [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1,
- [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1,
- [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1,
- [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1,
- };
- static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
- [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
- };
- static const int mlxsw_sp_sfgc_not_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
- [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1,
- [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1,
- [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1,
- [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1,
- [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1,
- [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
- };
- static const int mlxsw_sp_sfgc_any_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
- [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1,
- [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1,
- [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1,
- [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1,
- [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1,
- [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1,
- [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
- };
- static const int *mlxsw_sp_packet_type_sfgc_types[] = {
- [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types,
- [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types,
- [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types,
- [MLXSW_SP_FLOOD_TYPE_NOT_UC] = mlxsw_sp_sfgc_not_uc_packet_types,
- [MLXSW_SP_FLOOD_TYPE_ANY] = mlxsw_sp_sfgc_any_packet_types,
- };
- struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
- u16 fid_index)
- {
- struct mlxsw_sp_fid *fid;
- fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index,
- mlxsw_sp_fid_ht_params);
- if (fid)
- refcount_inc(&fid->ref_count);
- return fid;
- }
- int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex)
- {
- if (!fid->vni_valid)
- return -EINVAL;
- *nve_ifindex = fid->nve_ifindex;
- return 0;
- }
- int mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid,
- enum mlxsw_sp_nve_type *p_type)
- {
- if (!fid->vni_valid)
- return -EINVAL;
- *p_type = fid->nve_type;
- return 0;
- }
- struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,
- __be32 vni)
- {
- struct mlxsw_sp_fid *fid;
- fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni,
- mlxsw_sp_fid_vni_ht_params);
- if (fid)
- refcount_inc(&fid->ref_count);
- return fid;
- }
- int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni)
- {
- if (!fid->vni_valid)
- return -EINVAL;
- *vni = fid->vni;
- return 0;
- }
- int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
- u32 nve_flood_index)
- {
- struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
- const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
- int err;
- if (WARN_ON(fid->nve_flood_index_valid))
- return -EINVAL;
- fid->nve_flood_index = nve_flood_index;
- fid->nve_flood_index_valid = true;
- err = ops->nve_flood_index_set(fid);
- if (err)
- goto err_nve_flood_index_set;
- return 0;
- err_nve_flood_index_set:
- fid->nve_flood_index_valid = false;
- return err;
- }
- void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
- {
- struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
- const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
- if (WARN_ON(!fid->nve_flood_index_valid))
- return;
- fid->nve_flood_index_valid = false;
- ops->nve_flood_index_clear(fid);
- }
- bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
- {
- return fid->nve_flood_index_valid;
- }
- int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type,
- __be32 vni, int nve_ifindex)
- {
- struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
- const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
- struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
- int err;
- if (WARN_ON(fid->vni_valid))
- return -EINVAL;
- fid->nve_type = type;
- fid->nve_ifindex = nve_ifindex;
- fid->vni = vni;
- err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht,
- &fid->vni_ht_node,
- mlxsw_sp_fid_vni_ht_params);
- if (err)
- return err;
- fid->vni_valid = true;
- err = ops->vni_set(fid);
- if (err)
- goto err_vni_set;
- return 0;
- err_vni_set:
- fid->vni_valid = false;
- rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
- mlxsw_sp_fid_vni_ht_params);
- return err;
- }
- void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid)
- {
- struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
- const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
- struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
- if (WARN_ON(!fid->vni_valid))
- return;
- fid->vni_valid = false;
- ops->vni_clear(fid);
- rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
- mlxsw_sp_fid_vni_ht_params);
- }
- bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
- {
- return fid->vni_valid;
- }
- void mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
- const struct net_device *nve_dev)
- {
- struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
- const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
- if (ops->fdb_clear_offload)
- ops->fdb_clear_offload(fid, nve_dev);
- }
- static const struct mlxsw_sp_flood_table *
- mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
- enum mlxsw_sp_flood_type packet_type)
- {
- struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
- int i;
- for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) {
- const struct mlxsw_sp_flood_table *flood_table;
- flood_table = &fid_family->flood_profile->flood_tables[i];
- if (flood_table->packet_type != packet_type)
- continue;
- return flood_table;
- }
- return NULL;
- }
- static u16
- mlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family *fid_family)
- {
- return fid_family->end_index - fid_family->start_index + 1;
- }
- static int
- mlxsw_sp_fid_8021d_pgt_size(const struct mlxsw_sp_fid_family *fid_family,
- u16 *p_pgt_size)
- {
- u16 num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
- *p_pgt_size = num_fids * fid_family->flood_profile->nr_flood_tables;
- return 0;
- }
- static unsigned int mlxsw_sp_fid_rfid_port_offset_cff(unsigned int local_port)
- {
- /* Port 0 is the CPU port. Since we never create RIFs based off that
- * port, we don't need to count it.
- */
- return WARN_ON_ONCE(!local_port) ? 0 : local_port - 1;
- }
- static int
- mlxsw_sp_fid_rfid_pgt_size_cff(const struct mlxsw_sp_fid_family *fid_family,
- u16 *p_pgt_size)
- {
- struct mlxsw_core *core = fid_family->mlxsw_sp->core;
- unsigned int max_ports;
- u16 pgt_size;
- u16 max_lags;
- int err;
- max_ports = mlxsw_core_max_ports(core);
- err = mlxsw_core_max_lag(core, &max_lags);
- if (err)
- return err;
- pgt_size = (mlxsw_sp_fid_rfid_port_offset_cff(max_ports) + max_lags) *
- fid_family->flood_profile->nr_flood_tables;
- *p_pgt_size = pgt_size;
- return 0;
- }
- static u16
- mlxsw_sp_fid_pgt_base_ctl(const struct mlxsw_sp_fid_family *fid_family,
- const struct mlxsw_sp_flood_table *flood_table)
- {
- u16 num_fids;
- num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
- return fid_family->pgt_base + num_fids * flood_table->table_index;
- }
- static u16
- mlxsw_sp_fid_fid_mid_ctl(const struct mlxsw_sp_fid *fid,
- const struct mlxsw_sp_flood_table *flood_table)
- {
- return mlxsw_sp_fid_pgt_base_ctl(fid->fid_family, flood_table) +
- fid->fid_offset;
- }
- int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
- enum mlxsw_sp_flood_type packet_type, u16 local_port,
- bool member)
- {
- struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
- const struct mlxsw_sp_flood_table *flood_table;
- u16 mid_index;
- if (WARN_ON(!fid_family->flood_profile))
- return -EINVAL;
- flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
- if (!flood_table)
- return -ESRCH;
- mid_index = fid_family->ops->fid_mid(fid, flood_table);
- return mlxsw_sp_pgt_entry_port_set(fid_family->mlxsw_sp, mid_index,
- fid->fid_index, local_port, member);
- }
- int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
- struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
- {
- if (WARN_ON(!fid->fid_family->ops->port_vid_map))
- return -EINVAL;
- return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);
- }
- void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
- struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
- {
- fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
- }
- u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
- {
- return fid->fid_index;
- }
- enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
- {
- return fid->fid_family->type;
- }
- struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
- {
- return fid->rif;
- }
- enum mlxsw_sp_rif_type
- mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
- enum mlxsw_sp_fid_type type)
- {
- struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
- return fid_core->fid_family_arr[type]->rif_type;
- }
- static struct mlxsw_sp_fid_8021q *
- mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
- {
- return container_of(fid, struct mlxsw_sp_fid_8021q, common);
- }
- u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
- {
- return mlxsw_sp_fid_8021q_fid(fid)->vid;
- }
- static int mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
- {
- u16 vid = *(u16 *) arg;
- mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
- fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
- return 0;
- }
- static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
- {
- return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
- MLXSW_REG_SFMR_OP_DESTROY_FID;
- }
- static void mlxsw_sp_fid_pack(char *sfmr_pl,
- const struct mlxsw_sp_fid *fid,
- enum mlxsw_reg_sfmr_op op)
- {
- u16 smpe;
- smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;
- mlxsw_reg_sfmr_pack(sfmr_pl, op, fid->fid_index,
- fid->fid_family->smpe_index_valid, smpe);
- }
- static void mlxsw_sp_fid_pack_ctl(char *sfmr_pl,
- const struct mlxsw_sp_fid *fid,
- enum mlxsw_reg_sfmr_op op)
- {
- mlxsw_sp_fid_pack(sfmr_pl, fid, op);
- mlxsw_reg_sfmr_fid_offset_set(sfmr_pl, fid->fid_offset);
- mlxsw_reg_sfmr_flood_rsp_set(sfmr_pl, fid->fid_family->flood_rsp);
- mlxsw_reg_sfmr_flood_bridge_type_set(sfmr_pl,
- fid->fid_family->bridge_type);
- }
- static u16
- mlxsw_sp_fid_off_pgt_base_cff(const struct mlxsw_sp_fid_family *fid_family,
- u16 fid_offset)
- {
- return fid_family->pgt_base +
- fid_offset * fid_family->flood_profile->nr_flood_tables;
- }
- static u16 mlxsw_sp_fid_pgt_base_cff(const struct mlxsw_sp_fid *fid)
- {
- return mlxsw_sp_fid_off_pgt_base_cff(fid->fid_family, fid->fid_offset);
- }
- static void mlxsw_sp_fid_fid_pack_cff(char *sfmr_pl,
- const struct mlxsw_sp_fid *fid,
- enum mlxsw_reg_sfmr_op op)
- {
- struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
- u16 pgt_base = mlxsw_sp_fid_pgt_base_cff(fid);
- mlxsw_sp_fid_pack(sfmr_pl, fid, op);
- mlxsw_reg_sfmr_cff_mid_base_set(sfmr_pl, pgt_base);
- mlxsw_reg_sfmr_cff_prf_id_set(sfmr_pl,
- fid_family->flood_profile->profile_id);
- mlxsw_reg_sfmr_nve_flood_prf_id_set(sfmr_pl,
- MLXSW_SP_FID_FLOOD_PROFILE_ID_NVE);
- }
- static u16 mlxsw_sp_fid_rfid_fid_offset_cff(struct mlxsw_sp *mlxsw_sp,
- u16 port_lag_id, bool is_lag)
- {
- u16 max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
- if (is_lag)
- return mlxsw_sp_fid_rfid_port_offset_cff(max_ports) +
- port_lag_id;
- else
- return mlxsw_sp_fid_rfid_port_offset_cff(port_lag_id);
- }
- static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid)
- {
- struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
- char sfmr_pl[MLXSW_REG_SFMR_LEN];
- fid->fid_family->ops->fid_pack(sfmr_pl, fid,
- mlxsw_sp_sfmr_op(valid));
- return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
- }
- static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid,
- const struct mlxsw_sp_rif *rif)
- {
- struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
- char sfmr_pl[MLXSW_REG_SFMR_LEN];
- fid->fid_family->ops->fid_pack(sfmr_pl, fid,
- MLXSW_REG_SFMR_OP_CREATE_FID);
- mlxsw_reg_sfmr_vv_set(sfmr_pl, fid->vni_valid);
- mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(fid->vni));
- mlxsw_reg_sfmr_vtfp_set(sfmr_pl, fid->nve_flood_index_valid);
- mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, fid->nve_flood_index);
- if (rif) {
- mlxsw_reg_sfmr_irif_v_set(sfmr_pl, true);
- mlxsw_reg_sfmr_irif_set(sfmr_pl, mlxsw_sp_rif_index(rif));
- }
- return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
- }
- static int mlxsw_sp_fid_vni_to_fid_map(const struct mlxsw_sp_fid *fid,
- const struct mlxsw_sp_rif *rif,
- bool valid)
- {
- struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
- char svfa_pl[MLXSW_REG_SVFA_LEN];
- bool irif_valid;
- u16 irif_index;
- irif_valid = !!rif;
- irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
- mlxsw_reg_svfa_vni_pack(svfa_pl, valid, fid->fid_index,
- be32_to_cpu(fid->vni), irif_valid, irif_index);
- return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
- }
- static int mlxsw_sp_fid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
- const struct mlxsw_sp_rif *rif)
- {
- return mlxsw_sp_fid_edit_op(fid, rif);
- }
- static int mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
- const struct mlxsw_sp_rif *rif)
- {
- if (!fid->vni_valid)
- return 0;
- return mlxsw_sp_fid_vni_to_fid_map(fid, rif, fid->vni_valid);
- }
- static int
- mlxsw_sp_fid_vid_to_fid_map(const struct mlxsw_sp_fid *fid, u16 vid, bool valid,
- const struct mlxsw_sp_rif *rif)
- {
- struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
- char svfa_pl[MLXSW_REG_SVFA_LEN];
- bool irif_valid;
- u16 irif_index;
- irif_valid = !!rif;
- irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
- mlxsw_reg_svfa_vid_pack(svfa_pl, valid, fid->fid_index, vid, irif_valid,
- irif_index);
- return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
- }
- static int
- mlxsw_sp_fid_8021q_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
- const struct mlxsw_sp_rif *rif)
- {
- struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
- /* Update the global VID => FID mapping we created when the FID was
- * configured.
- */
- return mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, rif);
- }
- static int
- mlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid *fid,
- struct mlxsw_sp_fid_port_vid *pv,
- bool irif_valid, u16 irif_index)
- {
- struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
- char svfa_pl[MLXSW_REG_SVFA_LEN];
- mlxsw_reg_svfa_port_vid_pack(svfa_pl, pv->local_port, true,
- fid->fid_index, pv->vid, irif_valid,
- irif_index);
- return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
- }
- static int mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid *fid,
- const struct mlxsw_sp_rif *rif)
- {
- struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
- struct mlxsw_sp_fid_port_vid *pv;
- u16 irif_index;
- int err;
- err = fid->fid_family->ops->vid_to_fid_rif_update(fid, rif);
- if (err)
- return err;
- irif_index = mlxsw_sp_rif_index(rif);
- list_for_each_entry(pv, &fid->port_vid_list, list) {
- /* If port is not in virtual mode, then it does not have any
- * {Port, VID}->FID mappings that need to be updated with the
- * ingress RIF.
- */
- if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
- continue;
- err = mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv,
- true,
- irif_index);
- if (err)
- goto err_port_vid_to_fid_rif_update_one;
- }
- return 0;
- err_port_vid_to_fid_rif_update_one:
- list_for_each_entry_continue_reverse(pv, &fid->port_vid_list, list) {
- if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
- continue;
- mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
- }
- fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
- return err;
- }
- static void mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid *fid)
- {
- struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
- struct mlxsw_sp_fid_port_vid *pv;
- list_for_each_entry(pv, &fid->port_vid_list, list) {
- /* If port is not in virtual mode, then it does not have any
- * {Port, VID}->FID mappings that need to be updated.
- */
- if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
- continue;
- mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
- }
- fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
- }
- static int mlxsw_sp_fid_reiv_handle(struct mlxsw_sp_fid *fid, u16 rif_index,
- bool valid, u8 port_page)
- {
- u16 local_port_end = (port_page + 1) * MLXSW_REG_REIV_REC_MAX_COUNT - 1;
- u16 local_port_start = port_page * MLXSW_REG_REIV_REC_MAX_COUNT;
- struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
- struct mlxsw_sp_fid_port_vid *port_vid;
- u8 rec_num, entries_num = 0;
- char *reiv_pl;
- int err;
- reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
- if (!reiv_pl)
- return -ENOMEM;
- mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);
- list_for_each_entry(port_vid, &fid->port_vid_list, list) {
- /* port_vid_list is sorted by local_port. */
- if (port_vid->local_port < local_port_start)
- continue;
- if (port_vid->local_port > local_port_end)
- break;
- rec_num = port_vid->local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
- mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);
- mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num,
- valid ? port_vid->vid : 0);
- entries_num++;
- }
- if (!entries_num) {
- kfree(reiv_pl);
- return 0;
- }
- err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);
- if (err)
- goto err_reg_write;
- kfree(reiv_pl);
- return 0;
- err_reg_write:
- kfree(reiv_pl);
- return err;
- }
- static int mlxsw_sp_fid_erif_eport_to_vid_map(struct mlxsw_sp_fid *fid,
- u16 rif_index, bool valid)
- {
- struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
- u8 num_port_pages;
- int err, i;
- num_port_pages = mlxsw_core_max_ports(mlxsw_sp->core) /
- MLXSW_REG_REIV_REC_MAX_COUNT + 1;
- for (i = 0; i < num_port_pages; i++) {
- err = mlxsw_sp_fid_reiv_handle(fid, rif_index, valid, i);
- if (err)
- goto err_reiv_handle;
- }
- return 0;
- err_reiv_handle:
- for (; i >= 0; i--)
- mlxsw_sp_fid_reiv_handle(fid, rif_index, !valid, i);
- return err;
- }
- int mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
- {
- u16 rif_index = mlxsw_sp_rif_index(rif);
- int err;
- err = mlxsw_sp_fid_to_fid_rif_update(fid, rif);
- if (err)
- return err;
- err = mlxsw_sp_fid_vni_to_fid_rif_update(fid, rif);
- if (err)
- goto err_vni_to_fid_rif_update;
- err = mlxsw_sp_fid_vid_to_fid_rif_set(fid, rif);
- if (err)
- goto err_vid_to_fid_rif_set;
- err = mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, true);
- if (err)
- goto err_erif_eport_to_vid_map;
- fid->rif = rif;
- return 0;
- err_erif_eport_to_vid_map:
- mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
- err_vid_to_fid_rif_set:
- mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
- err_vni_to_fid_rif_update:
- mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
- return err;
- }
- void mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid *fid)
- {
- u16 rif_index;
- if (!fid->rif)
- return;
- rif_index = mlxsw_sp_rif_index(fid->rif);
- fid->rif = NULL;
- mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, false);
- mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
- mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
- mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
- }
- static int mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid *fid)
- {
- int err;
- err = mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, fid->vni_valid);
- if (err)
- return err;
- err = mlxsw_sp_fid_edit_op(fid, fid->rif);
- if (err)
- goto err_fid_edit_op;
- return 0;
- err_fid_edit_op:
- mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, !fid->vni_valid);
- return err;
- }
- static int __mlxsw_sp_fid_port_vid_map(const struct mlxsw_sp_fid *fid,
- u16 local_port, u16 vid, bool valid)
- {
- struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
- char svfa_pl[MLXSW_REG_SVFA_LEN];
- bool irif_valid = false;
- u16 irif_index = 0;
- if (fid->rif) {
- irif_valid = true;
- irif_index = mlxsw_sp_rif_index(fid->rif);
- }
- mlxsw_reg_svfa_port_vid_pack(svfa_pl, local_port, valid, fid->fid_index,
- vid, irif_valid, irif_index);
- return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
- }
- static struct mlxsw_sp_fid_8021d *
- mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
- {
- return container_of(fid, struct mlxsw_sp_fid_8021d, common);
- }
- static int mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
- {
- int br_ifindex = *(int *) arg;
- mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
- fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
- return 0;
- }
- static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
- {
- return mlxsw_sp_fid_op(fid, true);
- }
- static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
- {
- if (fid->vni_valid)
- mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
- mlxsw_sp_fid_op(fid, false);
- }
- static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
- const void *arg, u16 *p_fid_index)
- {
- struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
- u16 nr_fids, fid_index;
- nr_fids = fid_family->end_index - fid_family->start_index + 1;
- fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);
- if (fid_index == nr_fids)
- return -ENOBUFS;
- *p_fid_index = fid_family->start_index + fid_index;
- return 0;
- }
- static bool
- mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
- {
- int br_ifindex = *(int *) arg;
- return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
- }
- static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
- {
- struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
- int err;
- list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
- list) {
- struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
- u16 vid = mlxsw_sp_port_vlan->vid;
- if (!fid)
- continue;
- err = __mlxsw_sp_fid_port_vid_map(fid,
- mlxsw_sp_port->local_port,
- vid, true);
- if (err)
- goto err_fid_port_vid_map;
- }
- err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
- if (err)
- goto err_port_vp_mode_set;
- return 0;
- err_port_vp_mode_set:
- err_fid_port_vid_map:
- list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
- &mlxsw_sp_port->vlans_list, list) {
- struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
- u16 vid = mlxsw_sp_port_vlan->vid;
- if (!fid)
- continue;
- __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
- false);
- }
- return err;
- }
- static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
- {
- struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
- mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
- list_for_each_entry_reverse(mlxsw_sp_port_vlan,
- &mlxsw_sp_port->vlans_list, list) {
- struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
- u16 vid = mlxsw_sp_port_vlan->vid;
- if (!fid)
- continue;
- __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
- false);
- }
- }
- static int
- mlxsw_sp_fid_port_vid_list_add(struct mlxsw_sp_fid *fid, u16 local_port,
- u16 vid)
- {
- struct mlxsw_sp_fid_port_vid *port_vid, *tmp_port_vid;
- port_vid = kzalloc(sizeof(*port_vid), GFP_KERNEL);
- if (!port_vid)
- return -ENOMEM;
- port_vid->local_port = local_port;
- port_vid->vid = vid;
- list_for_each_entry(tmp_port_vid, &fid->port_vid_list, list) {
- if (tmp_port_vid->local_port > local_port)
- break;
- }
- list_add_tail(&port_vid->list, &tmp_port_vid->list);
- return 0;
- }
- static void
- mlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid *fid, u16 local_port,
- u16 vid)
- {
- struct mlxsw_sp_fid_port_vid *port_vid, *tmp;
- list_for_each_entry_safe(port_vid, tmp, &fid->port_vid_list, list) {
- if (port_vid->local_port != local_port || port_vid->vid != vid)
- continue;
- list_del(&port_vid->list);
- kfree(port_vid);
- return;
- }
- }
- static int
- mlxsw_sp_fid_mpe_table_map(const struct mlxsw_sp_fid *fid, u16 local_port,
- u16 vid, bool valid)
- {
- struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
- char smpe_pl[MLXSW_REG_SMPE_LEN];
- mlxsw_reg_smpe_pack(smpe_pl, local_port, fid->fid_index,
- valid ? vid : 0);
- return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smpe), smpe_pl);
- }
- static int
- mlxsw_sp_fid_erif_eport_to_vid_map_one(const struct mlxsw_sp_fid *fid,
- u16 local_port, u16 vid, bool valid)
- {
- u8 port_page = local_port / MLXSW_REG_REIV_REC_MAX_COUNT;
- u8 rec_num = local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
- struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
- u16 rif_index = mlxsw_sp_rif_index(fid->rif);
- char *reiv_pl;
- int err;
- reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
- if (!reiv_pl)
- return -ENOMEM;
- mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);
- mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);
- mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num, valid ? vid : 0);
- err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);
- kfree(reiv_pl);
- return err;
- }
- static int mlxsw_sp_fid_evid_map(const struct mlxsw_sp_fid *fid, u16 local_port,
- u16 vid, bool valid)
- {
- int err;
- err = mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, valid);
- if (err)
- return err;
- if (!fid->rif)
- return 0;
- err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
- valid);
- if (err)
- goto err_erif_eport_to_vid_map_one;
- return 0;
- err_erif_eport_to_vid_map_one:
- mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, !valid);
- return err;
- }
- static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
- struct mlxsw_sp_port *mlxsw_sp_port,
- u16 vid)
- {
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- u16 local_port = mlxsw_sp_port->local_port;
- int err;
- err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
- true);
- if (err)
- return err;
- err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);
- if (err)
- goto err_fid_evid_map;
- err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
- vid);
- if (err)
- goto err_port_vid_list_add;
- if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
- err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
- if (err)
- goto err_port_vp_mode_trans;
- }
- return 0;
- err_port_vp_mode_trans:
- mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
- mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
- err_port_vid_list_add:
- mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
- err_fid_evid_map:
- __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
- return err;
- }
- static void
- mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
- struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
- {
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- u16 local_port = mlxsw_sp_port->local_port;
- if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
- mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
- mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
- mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
- mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
- __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
- }
- static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid)
- {
- return mlxsw_sp_fid_vni_op(fid);
- }
- static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
- {
- mlxsw_sp_fid_vni_op(fid);
- }
- static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid)
- {
- return mlxsw_sp_fid_edit_op(fid, fid->rif);
- }
- static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
- {
- mlxsw_sp_fid_edit_op(fid, fid->rif);
- }
- static void
- mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
- const struct net_device *nve_dev)
- {
- br_fdb_clear_offload(nve_dev, 0);
- }
- static int
- mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
- const struct mlxsw_sp_rif *rif)
- {
- return 0;
- }
- static int
- mlxsw_sp_fid_flood_table_init_ctl(struct mlxsw_sp_fid_family *fid_family,
- const struct mlxsw_sp_flood_table *flood_table)
- {
- enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
- struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
- const int *sfgc_packet_types;
- u16 mid_base;
- int err, i;
- mid_base = mlxsw_sp_fid_pgt_base_ctl(fid_family, flood_table);
- sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
- for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
- char sfgc_pl[MLXSW_REG_SFGC_LEN];
- if (!sfgc_packet_types[i])
- continue;
- mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type,
- flood_table->table_type, 0, mid_base);
- err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
- if (err)
- return err;
- }
- return 0;
- }
- static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_ctl = {
- .setup = mlxsw_sp_fid_8021d_setup,
- .configure = mlxsw_sp_fid_8021d_configure,
- .deconfigure = mlxsw_sp_fid_8021d_deconfigure,
- .index_alloc = mlxsw_sp_fid_8021d_index_alloc,
- .compare = mlxsw_sp_fid_8021d_compare,
- .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map,
- .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap,
- .vni_set = mlxsw_sp_fid_8021d_vni_set,
- .vni_clear = mlxsw_sp_fid_8021d_vni_clear,
- .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set,
- .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear,
- .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload,
- .vid_to_fid_rif_update = mlxsw_sp_fid_8021d_vid_to_fid_rif_update,
- .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl,
- .pgt_size = mlxsw_sp_fid_8021d_pgt_size,
- .fid_mid = mlxsw_sp_fid_fid_mid_ctl,
- .fid_pack = mlxsw_sp_fid_pack_ctl,
- };
- static u16
- mlxsw_sp_fid_fid_mid_cff(const struct mlxsw_sp_fid *fid,
- const struct mlxsw_sp_flood_table *flood_table)
- {
- return mlxsw_sp_fid_pgt_base_cff(fid) + flood_table->table_index;
- }
- static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_cff = {
- .setup = mlxsw_sp_fid_8021d_setup,
- .configure = mlxsw_sp_fid_8021d_configure,
- .deconfigure = mlxsw_sp_fid_8021d_deconfigure,
- .index_alloc = mlxsw_sp_fid_8021d_index_alloc,
- .compare = mlxsw_sp_fid_8021d_compare,
- .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map,
- .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap,
- .vni_set = mlxsw_sp_fid_8021d_vni_set,
- .vni_clear = mlxsw_sp_fid_8021d_vni_clear,
- .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set,
- .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear,
- .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload,
- .vid_to_fid_rif_update = mlxsw_sp_fid_8021d_vid_to_fid_rif_update,
- .pgt_size = mlxsw_sp_fid_8021d_pgt_size,
- .fid_mid = mlxsw_sp_fid_fid_mid_cff,
- .fid_pack = mlxsw_sp_fid_fid_pack_cff,
- };
- #define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2)
- #define MLXSW_SP_FID_RFID_MAX (11 * 1024)
- static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
- {
- .packet_type = MLXSW_SP_FLOOD_TYPE_UC,
- .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
- .table_index = 0,
- },
- {
- .packet_type = MLXSW_SP_FLOOD_TYPE_MC,
- .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
- .table_index = 1,
- },
- {
- .packet_type = MLXSW_SP_FLOOD_TYPE_BC,
- .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
- .table_index = 2,
- },
- };
- static const
- struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_8021d_flood_profile = {
- .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
- .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
- .profile_id = MLXSW_SP_FID_FLOOD_PROFILE_ID_BRIDGE,
- };
- static const struct mlxsw_sp_flood_table mlxsw_sp_fid_rsp_flood_tables_cff[] = {
- {
- .packet_type = MLXSW_SP_FLOOD_TYPE_UC,
- .table_index = 0,
- },
- {
- .packet_type = MLXSW_SP_FLOOD_TYPE_NOT_UC,
- .table_index = 1,
- },
- };
- static const
- struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_rsp_flood_profile_cff = {
- .flood_tables = mlxsw_sp_fid_rsp_flood_tables_cff,
- .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_rsp_flood_tables_cff),
- .profile_id = MLXSW_SP_FID_FLOOD_PROFILE_ID_RSP,
- };
- static const struct mlxsw_sp_flood_table mlxsw_sp_fid_nve_flood_tables_cff[] = {
- {
- .packet_type = MLXSW_SP_FLOOD_TYPE_ANY,
- .table_index = 0,
- },
- };
- static const
- struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_nve_flood_profile_cff = {
- .flood_tables = mlxsw_sp_fid_nve_flood_tables_cff,
- .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_nve_flood_tables_cff),
- .profile_id = MLXSW_SP_FID_FLOOD_PROFILE_ID_NVE,
- };
- static bool
- mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
- {
- u16 vid = *(u16 *) arg;
- return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
- }
- static void
- mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
- const struct net_device *nve_dev)
- {
- br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid));
- }
- static int mlxsw_sp_fid_rfid_setup_ctl(struct mlxsw_sp_fid *fid,
- const void *arg)
- {
- /* In controlled mode, the FW takes care of FID placement. */
- fid->fid_offset = 0;
- return 0;
- }
- static int mlxsw_sp_fid_rfid_setup_cff(struct mlxsw_sp_fid *fid,
- const void *arg)
- {
- struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
- u16 rif_index = *(const u16 *)arg;
- struct mlxsw_sp_rif *rif;
- bool is_lag;
- u16 port;
- int err;
- rif = mlxsw_sp_rif_by_index(mlxsw_sp, rif_index);
- if (!rif)
- return -ENOENT;
- err = mlxsw_sp_rif_subport_port(rif, &port, &is_lag);
- if (err)
- return err;
- fid->fid_offset = mlxsw_sp_fid_rfid_fid_offset_cff(mlxsw_sp, port,
- is_lag);
- return 0;
- }
- static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
- {
- return mlxsw_sp_fid_op(fid, true);
- }
- static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
- {
- mlxsw_sp_fid_op(fid, false);
- }
- static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
- const void *arg, u16 *p_fid_index)
- {
- u16 rif_index = *(u16 *) arg;
- *p_fid_index = fid->fid_family->start_index + rif_index;
- return 0;
- }
- static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
- const void *arg)
- {
- u16 rif_index = *(u16 *) arg;
- return fid->fid_index == rif_index + fid->fid_family->start_index;
- }
- static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
- struct mlxsw_sp_port *mlxsw_sp_port,
- u16 vid)
- {
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- u16 local_port = mlxsw_sp_port->local_port;
- int err;
- err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
- vid);
- if (err)
- return err;
- /* Using legacy bridge model, we only need to transition the port to
- * virtual mode since {Port, VID} => FID is done by the firmware upon
- * RIF creation. Using unified bridge model, we need to map
- * {Port, VID} => FID and map egress VID.
- */
- err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
- true);
- if (err)
- goto err_port_vid_map;
- if (fid->rif) {
- err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port,
- vid, true);
- if (err)
- goto err_erif_eport_to_vid_map_one;
- }
- if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
- err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
- if (err)
- goto err_port_vp_mode_trans;
- }
- return 0;
- err_port_vp_mode_trans:
- mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
- if (fid->rif)
- mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
- false);
- err_erif_eport_to_vid_map_one:
- __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
- err_port_vid_map:
- mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
- return err;
- }
- static void
- mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
- struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
- {
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- u16 local_port = mlxsw_sp_port->local_port;
- if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
- mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
- mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
- if (fid->rif)
- mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
- false);
- __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
- mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
- }
- static int mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid *fid)
- {
- return -EOPNOTSUPP;
- }
- static void mlxsw_sp_fid_rfid_vni_clear(struct mlxsw_sp_fid *fid)
- {
- WARN_ON_ONCE(1);
- }
- static int mlxsw_sp_fid_rfid_nve_flood_index_set(struct mlxsw_sp_fid *fid)
- {
- return -EOPNOTSUPP;
- }
- static void mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
- {
- WARN_ON_ONCE(1);
- }
- static int
- mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
- const struct mlxsw_sp_rif *rif)
- {
- return 0;
- }
- static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops_ctl = {
- .setup = mlxsw_sp_fid_rfid_setup_ctl,
- .configure = mlxsw_sp_fid_rfid_configure,
- .deconfigure = mlxsw_sp_fid_rfid_deconfigure,
- .index_alloc = mlxsw_sp_fid_rfid_index_alloc,
- .compare = mlxsw_sp_fid_rfid_compare,
- .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map,
- .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap,
- .vni_set = mlxsw_sp_fid_rfid_vni_set,
- .vni_clear = mlxsw_sp_fid_rfid_vni_clear,
- .nve_flood_index_set = mlxsw_sp_fid_rfid_nve_flood_index_set,
- .nve_flood_index_clear = mlxsw_sp_fid_rfid_nve_flood_index_clear,
- .vid_to_fid_rif_update = mlxsw_sp_fid_rfid_vid_to_fid_rif_update,
- .fid_pack = mlxsw_sp_fid_pack_ctl,
- };
- static int
- mlxsw_sp_fid_rfid_port_add_cff(struct mlxsw_sp *mlxsw_sp,
- const struct mlxsw_sp_flood_table *flood_table,
- u16 pgt_addr, u16 smpe, unsigned int local_port)
- {
- int err;
- err = mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe,
- local_port, true);
- if (err)
- return err;
- if (flood_table->packet_type == MLXSW_SP_FLOOD_TYPE_NOT_UC) {
- u16 router_port = mlxsw_sp_router_port(mlxsw_sp);
- err = mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe,
- router_port, true);
- if (err)
- goto err_entry_port_set;
- }
- return 0;
- err_entry_port_set:
- mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, local_port,
- false);
- return err;
- }
- static void
- mlxsw_sp_fid_rfid_port_del_cff(struct mlxsw_sp *mlxsw_sp,
- const struct mlxsw_sp_flood_table *flood_table,
- u16 pgt_addr, u16 smpe, u16 local_port)
- {
- if (flood_table->packet_type == MLXSW_SP_FLOOD_TYPE_NOT_UC) {
- u16 router_port = mlxsw_sp_router_port(mlxsw_sp);
- mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe,
- router_port, false);
- }
- mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, local_port,
- false);
- }
- static int
- mlxsw_sp_fid_rfid_port_memb_ft_cff(const struct mlxsw_sp_fid_family *fid_family,
- const struct mlxsw_sp_flood_table *flood_table,
- const struct mlxsw_sp_port *mlxsw_sp_port,
- bool member)
- {
- struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
- u16 local_port = mlxsw_sp_port->local_port;
- u16 fid_pgt_base;
- u16 fid_offset;
- u16 pgt_addr;
- u16 smpe;
- u16 port;
- /* In-PGT SMPE is only valid on Spectrum-1, CFF only on Spectrum>1. */
- smpe = 0;
- port = mlxsw_sp_port->lagged ? mlxsw_sp_port->lag_id : local_port;
- fid_offset = mlxsw_sp_fid_rfid_fid_offset_cff(mlxsw_sp, port,
- mlxsw_sp_port->lagged);
- fid_pgt_base = mlxsw_sp_fid_off_pgt_base_cff(fid_family, fid_offset);
- pgt_addr = fid_pgt_base + flood_table->table_index;
- if (member)
- return mlxsw_sp_fid_rfid_port_add_cff(mlxsw_sp, flood_table,
- pgt_addr, smpe,
- local_port);
- mlxsw_sp_fid_rfid_port_del_cff(mlxsw_sp, flood_table, pgt_addr, smpe,
- local_port);
- return 0;
- }
- static int
- mlxsw_sp_fid_rfid_port_memb_cff(const struct mlxsw_sp_fid_family *fid_family,
- const struct mlxsw_sp_port *mlxsw_sp_port,
- bool member)
- {
- int i;
- for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) {
- const struct mlxsw_sp_flood_table *flood_table =
- &fid_family->flood_profile->flood_tables[i];
- int err;
- err = mlxsw_sp_fid_rfid_port_memb_ft_cff(fid_family,
- flood_table,
- mlxsw_sp_port, member);
- if (err)
- return err;
- }
- return 0;
- }
- static int
- mlxsw_sp_fid_rfid_port_init_cff(const struct mlxsw_sp_fid_family *fid_family,
- const struct mlxsw_sp_port *mlxsw_sp_port)
- {
- return mlxsw_sp_fid_rfid_port_memb_cff(fid_family, mlxsw_sp_port, true);
- }
- static void
- mlxsw_sp_fid_rfid_port_fini_cff(const struct mlxsw_sp_fid_family *fid_family,
- const struct mlxsw_sp_port *mlxsw_sp_port)
- {
- mlxsw_sp_fid_rfid_port_memb_cff(fid_family, mlxsw_sp_port, false);
- }
- static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops_cff = {
- .setup = mlxsw_sp_fid_rfid_setup_cff,
- .configure = mlxsw_sp_fid_rfid_configure,
- .deconfigure = mlxsw_sp_fid_rfid_deconfigure,
- .index_alloc = mlxsw_sp_fid_rfid_index_alloc,
- .compare = mlxsw_sp_fid_rfid_compare,
- .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map,
- .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap,
- .vni_set = mlxsw_sp_fid_rfid_vni_set,
- .vni_clear = mlxsw_sp_fid_rfid_vni_clear,
- .nve_flood_index_set = mlxsw_sp_fid_rfid_nve_flood_index_set,
- .nve_flood_index_clear = mlxsw_sp_fid_rfid_nve_flood_index_clear,
- .vid_to_fid_rif_update = mlxsw_sp_fid_rfid_vid_to_fid_rif_update,
- .pgt_size = mlxsw_sp_fid_rfid_pgt_size_cff,
- .fid_port_init = mlxsw_sp_fid_rfid_port_init_cff,
- .fid_port_fini = mlxsw_sp_fid_rfid_port_fini_cff,
- .fid_mid = mlxsw_sp_fid_fid_mid_cff,
- .fid_pack = mlxsw_sp_fid_fid_pack_cff,
- };
- static int mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg)
- {
- fid->fid_offset = 0;
- return 0;
- }
- static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
- {
- return mlxsw_sp_fid_op(fid, true);
- }
- static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
- {
- mlxsw_sp_fid_op(fid, false);
- }
- static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
- const void *arg, u16 *p_fid_index)
- {
- *p_fid_index = fid->fid_family->start_index;
- return 0;
- }
- static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
- const void *arg)
- {
- return true;
- }
- static int mlxsw_sp_fid_dummy_vni_set(struct mlxsw_sp_fid *fid)
- {
- return -EOPNOTSUPP;
- }
- static void mlxsw_sp_fid_dummy_vni_clear(struct mlxsw_sp_fid *fid)
- {
- WARN_ON_ONCE(1);
- }
- static int mlxsw_sp_fid_dummy_nve_flood_index_set(struct mlxsw_sp_fid *fid)
- {
- return -EOPNOTSUPP;
- }
- static void mlxsw_sp_fid_dummy_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
- {
- WARN_ON_ONCE(1);
- }
- static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
- .setup = mlxsw_sp_fid_dummy_setup,
- .configure = mlxsw_sp_fid_dummy_configure,
- .deconfigure = mlxsw_sp_fid_dummy_deconfigure,
- .index_alloc = mlxsw_sp_fid_dummy_index_alloc,
- .compare = mlxsw_sp_fid_dummy_compare,
- .vni_set = mlxsw_sp_fid_dummy_vni_set,
- .vni_clear = mlxsw_sp_fid_dummy_vni_clear,
- .nve_flood_index_set = mlxsw_sp_fid_dummy_nve_flood_index_set,
- .nve_flood_index_clear = mlxsw_sp_fid_dummy_nve_flood_index_clear,
- .fid_pack = mlxsw_sp_fid_pack,
- };
- static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
- {
- struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
- int err;
- err = mlxsw_sp_fid_op(fid, true);
- if (err)
- return err;
- err = mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, fid->rif);
- if (err)
- goto err_vid_to_fid_map;
- return 0;
- err_vid_to_fid_map:
- mlxsw_sp_fid_op(fid, false);
- return err;
- }
- static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)
- {
- struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
- if (fid->vni_valid)
- mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
- mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, false, NULL);
- mlxsw_sp_fid_op(fid, false);
- }
- static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,
- struct mlxsw_sp_port *mlxsw_sp_port,
- u16 vid)
- {
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- u16 local_port = mlxsw_sp_port->local_port;
- int err;
- /* In case there are no {Port, VID} => FID mappings on the port,
- * we can use the global VID => FID mapping we created when the
- * FID was configured, otherwise, configure new mapping.
- */
- if (mlxsw_sp->fid_core->port_fid_mappings[local_port]) {
- err = __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, true);
- if (err)
- return err;
- }
- err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);
- if (err)
- goto err_fid_evid_map;
- err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
- vid);
- if (err)
- goto err_port_vid_list_add;
- return 0;
- err_port_vid_list_add:
- mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
- err_fid_evid_map:
- if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
- __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
- return err;
- }
- static void
- mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
- struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
- {
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- u16 local_port = mlxsw_sp_port->local_port;
- mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
- mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
- if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
- __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
- }
- static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_ctl = {
- .setup = mlxsw_sp_fid_8021q_setup,
- .configure = mlxsw_sp_fid_8021q_configure,
- .deconfigure = mlxsw_sp_fid_8021q_deconfigure,
- .index_alloc = mlxsw_sp_fid_8021d_index_alloc,
- .compare = mlxsw_sp_fid_8021q_compare,
- .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map,
- .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap,
- .vni_set = mlxsw_sp_fid_8021d_vni_set,
- .vni_clear = mlxsw_sp_fid_8021d_vni_clear,
- .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set,
- .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear,
- .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload,
- .vid_to_fid_rif_update = mlxsw_sp_fid_8021q_vid_to_fid_rif_update,
- .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl,
- .pgt_size = mlxsw_sp_fid_8021d_pgt_size,
- .fid_mid = mlxsw_sp_fid_fid_mid_ctl,
- .fid_pack = mlxsw_sp_fid_pack_ctl,
- };
- static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_cff = {
- .setup = mlxsw_sp_fid_8021q_setup,
- .configure = mlxsw_sp_fid_8021q_configure,
- .deconfigure = mlxsw_sp_fid_8021q_deconfigure,
- .index_alloc = mlxsw_sp_fid_8021d_index_alloc,
- .compare = mlxsw_sp_fid_8021q_compare,
- .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map,
- .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap,
- .vni_set = mlxsw_sp_fid_8021d_vni_set,
- .vni_clear = mlxsw_sp_fid_8021d_vni_clear,
- .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set,
- .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear,
- .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload,
- .vid_to_fid_rif_update = mlxsw_sp_fid_8021q_vid_to_fid_rif_update,
- .pgt_size = mlxsw_sp_fid_8021d_pgt_size,
- .fid_mid = mlxsw_sp_fid_fid_mid_cff,
- .fid_pack = mlxsw_sp_fid_fid_pack_cff,
- };
- /* There are 4K-2 802.1Q FIDs */
- #define MLXSW_SP_FID_8021Q_START 1 /* FID 0 is reserved. */
- #define MLXSW_SP_FID_8021Q_END (MLXSW_SP_FID_8021Q_START + \
- MLXSW_SP_FID_8021Q_MAX - 1)
- /* There are 1K 802.1D FIDs */
- #define MLXSW_SP_FID_8021D_START (MLXSW_SP_FID_8021Q_END + 1)
- #define MLXSW_SP_FID_8021D_END (MLXSW_SP_FID_8021D_START + \
- MLXSW_SP_FID_8021D_MAX - 1)
- /* There is one dummy FID */
- #define MLXSW_SP_FID_DUMMY (MLXSW_SP_FID_8021D_END + 1)
- /* There are 11K rFIDs */
- #define MLXSW_SP_RFID_START (MLXSW_SP_FID_DUMMY + 1)
- #define MLXSW_SP_RFID_END (MLXSW_SP_RFID_START + \
- MLXSW_SP_FID_RFID_MAX - 1)
- static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_family = {
- .type = MLXSW_SP_FID_TYPE_8021Q,
- .fid_size = sizeof(struct mlxsw_sp_fid_8021q),
- .start_index = MLXSW_SP_FID_8021Q_START,
- .end_index = MLXSW_SP_FID_8021Q_END,
- .flood_profile = &mlxsw_sp_fid_8021d_flood_profile,
- .rif_type = MLXSW_SP_RIF_TYPE_VLAN,
- .ops = &mlxsw_sp_fid_8021q_ops_ctl,
- .flood_rsp = false,
- .bridge_type = MLXSW_REG_BRIDGE_TYPE_0,
- .smpe_index_valid = false,
- };
- static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_family = {
- .type = MLXSW_SP_FID_TYPE_8021D,
- .fid_size = sizeof(struct mlxsw_sp_fid_8021d),
- .start_index = MLXSW_SP_FID_8021D_START,
- .end_index = MLXSW_SP_FID_8021D_END,
- .flood_profile = &mlxsw_sp_fid_8021d_flood_profile,
- .rif_type = MLXSW_SP_RIF_TYPE_FID,
- .ops = &mlxsw_sp_fid_8021d_ops_ctl,
- .bridge_type = MLXSW_REG_BRIDGE_TYPE_1,
- .smpe_index_valid = false,
- };
- static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_dummy_family = {
- .type = MLXSW_SP_FID_TYPE_DUMMY,
- .fid_size = sizeof(struct mlxsw_sp_fid),
- .start_index = MLXSW_SP_FID_DUMMY,
- .end_index = MLXSW_SP_FID_DUMMY,
- .ops = &mlxsw_sp_fid_dummy_ops,
- .smpe_index_valid = false,
- };
- static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family_ctl = {
- .type = MLXSW_SP_FID_TYPE_RFID,
- .fid_size = sizeof(struct mlxsw_sp_fid),
- .start_index = MLXSW_SP_RFID_START,
- .end_index = MLXSW_SP_RFID_END,
- .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT,
- .ops = &mlxsw_sp_fid_rfid_ops_ctl,
- .flood_rsp = true,
- .smpe_index_valid = false,
- };
- static const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = {
- [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp1_fid_8021q_family,
- [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp1_fid_8021d_family,
- [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp1_fid_dummy_family,
- [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_ctl,
- };
- static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family_ctl = {
- .type = MLXSW_SP_FID_TYPE_8021Q,
- .fid_size = sizeof(struct mlxsw_sp_fid_8021q),
- .start_index = MLXSW_SP_FID_8021Q_START,
- .end_index = MLXSW_SP_FID_8021Q_END,
- .flood_profile = &mlxsw_sp_fid_8021d_flood_profile,
- .rif_type = MLXSW_SP_RIF_TYPE_VLAN,
- .ops = &mlxsw_sp_fid_8021q_ops_ctl,
- .flood_rsp = false,
- .bridge_type = MLXSW_REG_BRIDGE_TYPE_0,
- .smpe_index_valid = true,
- };
- static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family_ctl = {
- .type = MLXSW_SP_FID_TYPE_8021D,
- .fid_size = sizeof(struct mlxsw_sp_fid_8021d),
- .start_index = MLXSW_SP_FID_8021D_START,
- .end_index = MLXSW_SP_FID_8021D_END,
- .flood_profile = &mlxsw_sp_fid_8021d_flood_profile,
- .rif_type = MLXSW_SP_RIF_TYPE_FID,
- .ops = &mlxsw_sp_fid_8021d_ops_ctl,
- .bridge_type = MLXSW_REG_BRIDGE_TYPE_1,
- .smpe_index_valid = true,
- };
- static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_dummy_family = {
- .type = MLXSW_SP_FID_TYPE_DUMMY,
- .fid_size = sizeof(struct mlxsw_sp_fid),
- .start_index = MLXSW_SP_FID_DUMMY,
- .end_index = MLXSW_SP_FID_DUMMY,
- .ops = &mlxsw_sp_fid_dummy_ops,
- .smpe_index_valid = false,
- };
- static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_ctl[] = {
- [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family_ctl,
- [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family_ctl,
- [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp2_fid_dummy_family,
- [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_ctl,
- };
- static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family_cff = {
- .type = MLXSW_SP_FID_TYPE_8021Q,
- .fid_size = sizeof(struct mlxsw_sp_fid_8021q),
- .start_index = MLXSW_SP_FID_8021Q_START,
- .end_index = MLXSW_SP_FID_8021Q_END,
- .flood_profile = &mlxsw_sp_fid_8021d_flood_profile,
- .rif_type = MLXSW_SP_RIF_TYPE_VLAN,
- .ops = &mlxsw_sp_fid_8021q_ops_cff,
- .smpe_index_valid = true,
- };
- static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family_cff = {
- .type = MLXSW_SP_FID_TYPE_8021D,
- .fid_size = sizeof(struct mlxsw_sp_fid_8021d),
- .start_index = MLXSW_SP_FID_8021D_START,
- .end_index = MLXSW_SP_FID_8021D_END,
- .flood_profile = &mlxsw_sp_fid_8021d_flood_profile,
- .rif_type = MLXSW_SP_RIF_TYPE_FID,
- .ops = &mlxsw_sp_fid_8021d_ops_cff,
- .smpe_index_valid = true,
- };
- static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family_cff = {
- .type = MLXSW_SP_FID_TYPE_RFID,
- .fid_size = sizeof(struct mlxsw_sp_fid),
- .start_index = MLXSW_SP_RFID_START,
- .end_index = MLXSW_SP_RFID_END,
- .flood_profile = &mlxsw_sp_fid_rsp_flood_profile_cff,
- .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT,
- .ops = &mlxsw_sp_fid_rfid_ops_cff,
- .smpe_index_valid = false,
- };
- static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_cff[] = {
- [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family_cff,
- [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family_cff,
- [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp2_fid_dummy_family,
- [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_cff,
- };
- static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,
- enum mlxsw_sp_fid_type type,
- const void *arg)
- {
- struct mlxsw_sp_fid_family *fid_family;
- struct mlxsw_sp_fid *fid;
- fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
- list_for_each_entry(fid, &fid_family->fids_list, list) {
- if (!fid->fid_family->ops->compare(fid, arg))
- continue;
- refcount_inc(&fid->ref_count);
- return fid;
- }
- return NULL;
- }
- static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
- enum mlxsw_sp_fid_type type,
- const void *arg)
- {
- struct mlxsw_sp_fid_family *fid_family;
- struct mlxsw_sp_fid *fid;
- u16 fid_index;
- int err;
- fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg);
- if (fid)
- return fid;
- fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
- fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
- if (!fid)
- return ERR_PTR(-ENOMEM);
- INIT_LIST_HEAD(&fid->port_vid_list);
- fid->fid_family = fid_family;
- err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
- if (err)
- goto err_index_alloc;
- fid->fid_index = fid_index;
- __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
- err = fid->fid_family->ops->setup(fid, arg);
- if (err)
- goto err_setup;
- err = fid->fid_family->ops->configure(fid);
- if (err)
- goto err_configure;
- err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node,
- mlxsw_sp_fid_ht_params);
- if (err)
- goto err_rhashtable_insert;
- list_add(&fid->list, &fid_family->fids_list);
- refcount_set(&fid->ref_count, 1);
- return fid;
- err_rhashtable_insert:
- fid->fid_family->ops->deconfigure(fid);
- err_configure:
- err_setup:
- __clear_bit(fid_index - fid_family->start_index,
- fid_family->fids_bitmap);
- err_index_alloc:
- kfree(fid);
- return ERR_PTR(err);
- }
- void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
- {
- struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
- struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
- if (!refcount_dec_and_test(&fid->ref_count))
- return;
- list_del(&fid->list);
- rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht,
- &fid->ht_node, mlxsw_sp_fid_ht_params);
- fid->fid_family->ops->deconfigure(fid);
- __clear_bit(fid->fid_index - fid_family->start_index,
- fid_family->fids_bitmap);
- WARN_ON_ONCE(!list_empty(&fid->port_vid_list));
- kfree(fid);
- }
- struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
- {
- return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
- }
- struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
- int br_ifindex)
- {
- return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
- }
- struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp,
- u16 vid)
- {
- return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
- }
- struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
- int br_ifindex)
- {
- return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D,
- &br_ifindex);
- }
- struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
- u16 rif_index)
- {
- return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);
- }
- struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
- {
- return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);
- }
- static int
- mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
- {
- struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
- u16 pgt_size;
- int err;
- int i;
- err = fid_family->ops->pgt_size(fid_family, &pgt_size);
- if (err)
- return err;
- err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, &fid_family->pgt_base,
- pgt_size);
- if (err)
- return err;
- if (!fid_family->flood_profile)
- return 0;
- for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) {
- const struct mlxsw_sp_flood_table *flood_table;
- flood_table = &fid_family->flood_profile->flood_tables[i];
- if (fid_family->ops->flood_table_init) {
- err = fid_family->ops->flood_table_init(fid_family,
- flood_table);
- if (err)
- goto err_flood_table_init;
- }
- }
- return 0;
- err_flood_table_init:
- mlxsw_sp_pgt_mid_free_range(mlxsw_sp, fid_family->pgt_base, pgt_size);
- return err;
- }
- static void
- mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family)
- {
- struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
- u16 pgt_size;
- int err;
- err = fid_family->ops->pgt_size(fid_family, &pgt_size);
- if (WARN_ON_ONCE(err))
- return;
- mlxsw_sp_pgt_mid_free_range(mlxsw_sp, fid_family->pgt_base, pgt_size);
- }
- static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
- const struct mlxsw_sp_fid_family *tmpl)
- {
- u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
- struct mlxsw_sp_fid_family *fid_family;
- int err;
- fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);
- if (!fid_family)
- return -ENOMEM;
- fid_family->mlxsw_sp = mlxsw_sp;
- INIT_LIST_HEAD(&fid_family->fids_list);
- fid_family->fids_bitmap = bitmap_zalloc(nr_fids, GFP_KERNEL);
- if (!fid_family->fids_bitmap) {
- err = -ENOMEM;
- goto err_alloc_fids_bitmap;
- }
- if (fid_family->flood_profile) {
- err = mlxsw_sp_fid_flood_tables_init(fid_family);
- if (err)
- goto err_fid_flood_tables_init;
- }
- mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
- return 0;
- err_fid_flood_tables_init:
- bitmap_free(fid_family->fids_bitmap);
- err_alloc_fids_bitmap:
- kfree(fid_family);
- return err;
- }
- static void
- mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_fid_family *fid_family)
- {
- mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
- if (fid_family->flood_profile)
- mlxsw_sp_fid_flood_tables_fini(fid_family);
- bitmap_free(fid_family->fids_bitmap);
- WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
- kfree(fid_family);
- }
- static int mlxsw_sp_fid_port_init(const struct mlxsw_sp_port *mlxsw_sp_port)
- {
- const enum mlxsw_sp_fid_type type_rfid = MLXSW_SP_FID_TYPE_RFID;
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- struct mlxsw_sp_fid_family *rfid_family;
- rfid_family = mlxsw_sp->fid_core->fid_family_arr[type_rfid];
- if (rfid_family->ops->fid_port_init)
- return rfid_family->ops->fid_port_init(rfid_family,
- mlxsw_sp_port);
- return 0;
- }
- static void mlxsw_sp_fid_port_fini(const struct mlxsw_sp_port *mlxsw_sp_port)
- {
- const enum mlxsw_sp_fid_type type_rfid = MLXSW_SP_FID_TYPE_RFID;
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- struct mlxsw_sp_fid_family *rfid_family;
- rfid_family = mlxsw_sp->fid_core->fid_family_arr[type_rfid];
- if (rfid_family->ops->fid_port_fini)
- rfid_family->ops->fid_port_fini(rfid_family, mlxsw_sp_port);
- }
- int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
- {
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- int err;
- /* Track number of FIDs configured on the port with mapping type
- * PORT_VID_TO_FID, so that we know when to transition the port
- * back to non-virtual (VLAN) mode.
- */
- mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
- err = mlxsw_sp_fid_port_init(mlxsw_sp_port);
- if (err)
- return err;
- err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
- if (err)
- goto err_vp_mode_set;
- return 0;
- err_vp_mode_set:
- mlxsw_sp_fid_port_fini(mlxsw_sp_port);
- return err;
- }
- void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
- {
- struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
- mlxsw_sp_fid_port_fini(mlxsw_sp_port);
- mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
- }
- int mlxsw_sp_fid_port_join_lag(const struct mlxsw_sp_port *mlxsw_sp_port)
- {
- return mlxsw_sp_fid_port_init(mlxsw_sp_port);
- }
- void mlxsw_sp_fid_port_leave_lag(const struct mlxsw_sp_port *mlxsw_sp_port)
- {
- mlxsw_sp_fid_port_fini(mlxsw_sp_port);
- }
- static int
- mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp,
- const struct mlxsw_sp_fid_family *fid_family_arr[])
- {
- unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
- struct mlxsw_sp_fid_core *fid_core;
- int err, i;
- fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
- if (!fid_core)
- return -ENOMEM;
- mlxsw_sp->fid_core = fid_core;
- err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params);
- if (err)
- goto err_rhashtable_fid_init;
- err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params);
- if (err)
- goto err_rhashtable_vni_init;
- fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
- GFP_KERNEL);
- if (!fid_core->port_fid_mappings) {
- err = -ENOMEM;
- goto err_alloc_port_fid_mappings;
- }
- for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
- err = mlxsw_sp_fid_family_register(mlxsw_sp, fid_family_arr[i]);
- if (err)
- goto err_fid_ops_register;
- }
- return 0;
- err_fid_ops_register:
- for (i--; i >= 0; i--) {
- struct mlxsw_sp_fid_family *fid_family;
- fid_family = fid_core->fid_family_arr[i];
- mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
- }
- kfree(fid_core->port_fid_mappings);
- err_alloc_port_fid_mappings:
- rhashtable_destroy(&fid_core->vni_ht);
- err_rhashtable_vni_init:
- rhashtable_destroy(&fid_core->fid_ht);
- err_rhashtable_fid_init:
- kfree(fid_core);
- return err;
- }
- static void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
- {
- struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
- int i;
- for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
- mlxsw_sp_fid_family_unregister(mlxsw_sp,
- fid_core->fid_family_arr[i]);
- kfree(fid_core->port_fid_mappings);
- rhashtable_destroy(&fid_core->vni_ht);
- rhashtable_destroy(&fid_core->fid_ht);
- kfree(fid_core);
- }
- static int mlxsw_sp1_fids_init(struct mlxsw_sp *mlxsw_sp)
- {
- return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp1_fid_family_arr);
- }
- const struct mlxsw_sp_fid_core_ops mlxsw_sp1_fid_core_ops = {
- .init = mlxsw_sp1_fids_init,
- .fini = mlxsw_sp_fids_fini,
- };
- static int mlxsw_sp_fid_check_flood_profile_id(struct mlxsw_sp *mlxsw_sp,
- int profile_id)
- {
- u32 max_profiles;
- if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_NVE_FLOOD_PRF))
- return -EIO;
- max_profiles = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_NVE_FLOOD_PRF);
- if (WARN_ON_ONCE(!profile_id) ||
- WARN_ON_ONCE(profile_id >= max_profiles))
- return -EINVAL;
- return 0;
- }
- static int
- mlxsw_sp2_fids_init_flood_table(struct mlxsw_sp *mlxsw_sp,
- enum mlxsw_sp_fid_flood_profile_id profile_id,
- const struct mlxsw_sp_flood_table *flood_table)
- {
- enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
- const int *sfgc_packet_types;
- int err;
- int i;
- sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
- for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
- char sffp_pl[MLXSW_REG_SFFP_LEN];
- if (!sfgc_packet_types[i])
- continue;
- mlxsw_reg_sffp_pack(sffp_pl, profile_id, i,
- flood_table->table_index);
- err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sffp), sffp_pl);
- if (err)
- return err;
- }
- return 0;
- }
- static int
- mlxsw_sp2_fids_init_flood_profile(struct mlxsw_sp *mlxsw_sp,
- const struct mlxsw_sp_fid_flood_profile *
- flood_profile)
- {
- int err;
- int i;
- err = mlxsw_sp_fid_check_flood_profile_id(mlxsw_sp,
- flood_profile->profile_id);
- if (err)
- return err;
- for (i = 0; i < flood_profile->nr_flood_tables; i++) {
- const struct mlxsw_sp_flood_table *flood_table;
- flood_table = &flood_profile->flood_tables[i];
- err = mlxsw_sp2_fids_init_flood_table(mlxsw_sp,
- flood_profile->profile_id,
- flood_table);
- if (err)
- return err;
- }
- return 0;
- }
- static const
- struct mlxsw_sp_fid_flood_profile *mlxsw_sp_fid_flood_profiles[] = {
- &mlxsw_sp_fid_8021d_flood_profile,
- &mlxsw_sp_fid_rsp_flood_profile_cff,
- &mlxsw_sp_fid_nve_flood_profile_cff,
- };
- static int
- mlxsw_sp2_fids_init_flood_profiles(struct mlxsw_sp *mlxsw_sp)
- {
- int err;
- int i;
- for (i = 0; i < ARRAY_SIZE(mlxsw_sp_fid_flood_profiles); i++) {
- const struct mlxsw_sp_fid_flood_profile *flood_profile;
- flood_profile = mlxsw_sp_fid_flood_profiles[i];
- err = mlxsw_sp2_fids_init_flood_profile(mlxsw_sp,
- flood_profile);
- if (err)
- return err;
- }
- return 0;
- }
- static int mlxsw_sp2_fids_init_ctl(struct mlxsw_sp *mlxsw_sp)
- {
- return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp2_fid_family_arr_ctl);
- }
- static int mlxsw_sp2_fids_init_cff(struct mlxsw_sp *mlxsw_sp)
- {
- int err;
- err = mlxsw_sp2_fids_init_flood_profiles(mlxsw_sp);
- if (err)
- return err;
- return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp2_fid_family_arr_cff);
- }
- static int mlxsw_sp2_fids_init(struct mlxsw_sp *mlxsw_sp)
- {
- switch (mlxsw_core_flood_mode(mlxsw_sp->core)) {
- case MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED:
- return mlxsw_sp2_fids_init_ctl(mlxsw_sp);
- case MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CFF:
- return mlxsw_sp2_fids_init_cff(mlxsw_sp);
- default:
- WARN_ON_ONCE(1);
- return -EINVAL;
- }
- }
- const struct mlxsw_sp_fid_core_ops mlxsw_sp2_fid_core_ops = {
- .init = mlxsw_sp2_fids_init,
- .fini = mlxsw_sp_fids_fini,
- };
|