1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467 |
- /*
- * Header Parser helpers for Marvell PPv2 Network Controller
- *
- * Copyright (C) 2014 Marvell
- *
- * Marcin Wojtas <mw@semihalf.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
- #include <linux/kernel.h>
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/platform_device.h>
- #include <uapi/linux/ppp_defs.h>
- #include <net/ip.h>
- #include <net/ipv6.h>
- #include "mvpp2.h"
- #include "mvpp2_prs.h"
- /* Update parser tcam and sram hw entries */
- static int mvpp2_prs_hw_write(struct mvpp2 *priv, struct mvpp2_prs_entry *pe)
- {
- int i;
- if (pe->index > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
- return -EINVAL;
- /* Clear entry invalidation bit */
- pe->tcam.word[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK;
- /* Write tcam index - indirect access */
- mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
- for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
- mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam.word[i]);
- /* Write sram index - indirect access */
- mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index);
- for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
- mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), pe->sram.word[i]);
- return 0;
- }
- /* Initialize tcam entry from hw */
- static int mvpp2_prs_init_from_hw(struct mvpp2 *priv,
- struct mvpp2_prs_entry *pe, int tid)
- {
- int i;
- if (tid > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
- return -EINVAL;
- memset(pe, 0, sizeof(*pe));
- pe->index = tid;
- /* Write tcam index - indirect access */
- mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
- pe->tcam.word[MVPP2_PRS_TCAM_INV_WORD] = mvpp2_read(priv,
- MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD));
- if (pe->tcam.word[MVPP2_PRS_TCAM_INV_WORD] & MVPP2_PRS_TCAM_INV_MASK)
- return MVPP2_PRS_TCAM_ENTRY_INVALID;
- for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
- pe->tcam.word[i] = mvpp2_read(priv, MVPP2_PRS_TCAM_DATA_REG(i));
- /* Write sram index - indirect access */
- mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index);
- for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
- pe->sram.word[i] = mvpp2_read(priv, MVPP2_PRS_SRAM_DATA_REG(i));
- return 0;
- }
- /* Invalidate tcam hw entry */
- static void mvpp2_prs_hw_inv(struct mvpp2 *priv, int index)
- {
- /* Write index - indirect access */
- mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, index);
- mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD),
- MVPP2_PRS_TCAM_INV_MASK);
- }
- /* Enable shadow table entry and set its lookup ID */
- static void mvpp2_prs_shadow_set(struct mvpp2 *priv, int index, int lu)
- {
- priv->prs_shadow[index].valid = true;
- priv->prs_shadow[index].lu = lu;
- }
- /* Update ri fields in shadow table entry */
- static void mvpp2_prs_shadow_ri_set(struct mvpp2 *priv, int index,
- unsigned int ri, unsigned int ri_mask)
- {
- priv->prs_shadow[index].ri_mask = ri_mask;
- priv->prs_shadow[index].ri = ri;
- }
- /* Update lookup field in tcam sw entry */
- static void mvpp2_prs_tcam_lu_set(struct mvpp2_prs_entry *pe, unsigned int lu)
- {
- int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_LU_BYTE);
- pe->tcam.byte[MVPP2_PRS_TCAM_LU_BYTE] = lu;
- pe->tcam.byte[enable_off] = MVPP2_PRS_LU_MASK;
- }
- /* Update mask for single port in tcam sw entry */
- static void mvpp2_prs_tcam_port_set(struct mvpp2_prs_entry *pe,
- unsigned int port, bool add)
- {
- int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_PORT_BYTE);
- if (add)
- pe->tcam.byte[enable_off] &= ~(1 << port);
- else
- pe->tcam.byte[enable_off] |= 1 << port;
- }
- /* Update port map in tcam sw entry */
- static void mvpp2_prs_tcam_port_map_set(struct mvpp2_prs_entry *pe,
- unsigned int ports)
- {
- unsigned char port_mask = MVPP2_PRS_PORT_MASK;
- int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_PORT_BYTE);
- pe->tcam.byte[MVPP2_PRS_TCAM_PORT_BYTE] = 0;
- pe->tcam.byte[enable_off] &= ~port_mask;
- pe->tcam.byte[enable_off] |= ~ports & MVPP2_PRS_PORT_MASK;
- }
- /* Obtain port map from tcam sw entry */
- static unsigned int mvpp2_prs_tcam_port_map_get(struct mvpp2_prs_entry *pe)
- {
- int enable_off = MVPP2_PRS_TCAM_EN_OFFS(MVPP2_PRS_TCAM_PORT_BYTE);
- return ~(pe->tcam.byte[enable_off]) & MVPP2_PRS_PORT_MASK;
- }
- /* Set byte of data and its enable bits in tcam sw entry */
- static void mvpp2_prs_tcam_data_byte_set(struct mvpp2_prs_entry *pe,
- unsigned int offs, unsigned char byte,
- unsigned char enable)
- {
- pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE(offs)] = byte;
- pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(offs)] = enable;
- }
- /* Get byte of data and its enable bits from tcam sw entry */
- static void mvpp2_prs_tcam_data_byte_get(struct mvpp2_prs_entry *pe,
- unsigned int offs, unsigned char *byte,
- unsigned char *enable)
- {
- *byte = pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE(offs)];
- *enable = pe->tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(offs)];
- }
- /* Compare tcam data bytes with a pattern */
- static bool mvpp2_prs_tcam_data_cmp(struct mvpp2_prs_entry *pe, int offs,
- u16 data)
- {
- int off = MVPP2_PRS_TCAM_DATA_BYTE(offs);
- u16 tcam_data;
- tcam_data = (pe->tcam.byte[off + 1] << 8) | pe->tcam.byte[off];
- if (tcam_data != data)
- return false;
- return true;
- }
- /* Update ai bits in tcam sw entry */
- static void mvpp2_prs_tcam_ai_update(struct mvpp2_prs_entry *pe,
- unsigned int bits, unsigned int enable)
- {
- int i, ai_idx = MVPP2_PRS_TCAM_AI_BYTE;
- for (i = 0; i < MVPP2_PRS_AI_BITS; i++) {
- if (!(enable & BIT(i)))
- continue;
- if (bits & BIT(i))
- pe->tcam.byte[ai_idx] |= 1 << i;
- else
- pe->tcam.byte[ai_idx] &= ~(1 << i);
- }
- pe->tcam.byte[MVPP2_PRS_TCAM_EN_OFFS(ai_idx)] |= enable;
- }
- /* Get ai bits from tcam sw entry */
- static int mvpp2_prs_tcam_ai_get(struct mvpp2_prs_entry *pe)
- {
- return pe->tcam.byte[MVPP2_PRS_TCAM_AI_BYTE];
- }
- /* Set ethertype in tcam sw entry */
- static void mvpp2_prs_match_etype(struct mvpp2_prs_entry *pe, int offset,
- unsigned short ethertype)
- {
- mvpp2_prs_tcam_data_byte_set(pe, offset + 0, ethertype >> 8, 0xff);
- mvpp2_prs_tcam_data_byte_set(pe, offset + 1, ethertype & 0xff, 0xff);
- }
- /* Set vid in tcam sw entry */
- static void mvpp2_prs_match_vid(struct mvpp2_prs_entry *pe, int offset,
- unsigned short vid)
- {
- mvpp2_prs_tcam_data_byte_set(pe, offset + 0, (vid & 0xf00) >> 8, 0xf);
- mvpp2_prs_tcam_data_byte_set(pe, offset + 1, vid & 0xff, 0xff);
- }
- /* Set bits in sram sw entry */
- static void mvpp2_prs_sram_bits_set(struct mvpp2_prs_entry *pe, int bit_num,
- int val)
- {
- pe->sram.byte[MVPP2_BIT_TO_BYTE(bit_num)] |= (val << (bit_num % 8));
- }
- /* Clear bits in sram sw entry */
- static void mvpp2_prs_sram_bits_clear(struct mvpp2_prs_entry *pe, int bit_num,
- int val)
- {
- pe->sram.byte[MVPP2_BIT_TO_BYTE(bit_num)] &= ~(val << (bit_num % 8));
- }
- /* Update ri bits in sram sw entry */
- static void mvpp2_prs_sram_ri_update(struct mvpp2_prs_entry *pe,
- unsigned int bits, unsigned int mask)
- {
- unsigned int i;
- for (i = 0; i < MVPP2_PRS_SRAM_RI_CTRL_BITS; i++) {
- int ri_off = MVPP2_PRS_SRAM_RI_OFFS;
- if (!(mask & BIT(i)))
- continue;
- if (bits & BIT(i))
- mvpp2_prs_sram_bits_set(pe, ri_off + i, 1);
- else
- mvpp2_prs_sram_bits_clear(pe, ri_off + i, 1);
- mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_RI_CTRL_OFFS + i, 1);
- }
- }
- /* Obtain ri bits from sram sw entry */
- static int mvpp2_prs_sram_ri_get(struct mvpp2_prs_entry *pe)
- {
- return pe->sram.word[MVPP2_PRS_SRAM_RI_WORD];
- }
- /* Update ai bits in sram sw entry */
- static void mvpp2_prs_sram_ai_update(struct mvpp2_prs_entry *pe,
- unsigned int bits, unsigned int mask)
- {
- unsigned int i;
- int ai_off = MVPP2_PRS_SRAM_AI_OFFS;
- for (i = 0; i < MVPP2_PRS_SRAM_AI_CTRL_BITS; i++) {
- if (!(mask & BIT(i)))
- continue;
- if (bits & BIT(i))
- mvpp2_prs_sram_bits_set(pe, ai_off + i, 1);
- else
- mvpp2_prs_sram_bits_clear(pe, ai_off + i, 1);
- mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_AI_CTRL_OFFS + i, 1);
- }
- }
- /* Read ai bits from sram sw entry */
- static int mvpp2_prs_sram_ai_get(struct mvpp2_prs_entry *pe)
- {
- u8 bits;
- int ai_off = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_AI_OFFS);
- int ai_en_off = ai_off + 1;
- int ai_shift = MVPP2_PRS_SRAM_AI_OFFS % 8;
- bits = (pe->sram.byte[ai_off] >> ai_shift) |
- (pe->sram.byte[ai_en_off] << (8 - ai_shift));
- return bits;
- }
- /* In sram sw entry set lookup ID field of the tcam key to be used in the next
- * lookup interation
- */
- static void mvpp2_prs_sram_next_lu_set(struct mvpp2_prs_entry *pe,
- unsigned int lu)
- {
- int sram_next_off = MVPP2_PRS_SRAM_NEXT_LU_OFFS;
- mvpp2_prs_sram_bits_clear(pe, sram_next_off,
- MVPP2_PRS_SRAM_NEXT_LU_MASK);
- mvpp2_prs_sram_bits_set(pe, sram_next_off, lu);
- }
- /* In the sram sw entry set sign and value of the next lookup offset
- * and the offset value generated to the classifier
- */
- static void mvpp2_prs_sram_shift_set(struct mvpp2_prs_entry *pe, int shift,
- unsigned int op)
- {
- /* Set sign */
- if (shift < 0) {
- mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
- shift = 0 - shift;
- } else {
- mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
- }
- /* Set value */
- pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_SHIFT_OFFS)] =
- (unsigned char)shift;
- /* Reset and set operation */
- mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_MASK);
- mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, op);
- /* Set base offset as current */
- mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
- }
- /* In the sram sw entry set sign and value of the user defined offset
- * generated to the classifier
- */
- static void mvpp2_prs_sram_offset_set(struct mvpp2_prs_entry *pe,
- unsigned int type, int offset,
- unsigned int op)
- {
- /* Set sign */
- if (offset < 0) {
- mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
- offset = 0 - offset;
- } else {
- mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
- }
- /* Set value */
- mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_OFFS,
- MVPP2_PRS_SRAM_UDF_MASK);
- mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_OFFS, offset);
- pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_UDF_OFFS +
- MVPP2_PRS_SRAM_UDF_BITS)] &=
- ~(MVPP2_PRS_SRAM_UDF_MASK >> (8 - (MVPP2_PRS_SRAM_UDF_OFFS % 8)));
- pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_UDF_OFFS +
- MVPP2_PRS_SRAM_UDF_BITS)] |=
- (offset >> (8 - (MVPP2_PRS_SRAM_UDF_OFFS % 8)));
- /* Set offset type */
- mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS,
- MVPP2_PRS_SRAM_UDF_TYPE_MASK);
- mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, type);
- /* Set offset operation */
- mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS,
- MVPP2_PRS_SRAM_OP_SEL_UDF_MASK);
- mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS, op);
- pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS +
- MVPP2_PRS_SRAM_OP_SEL_UDF_BITS)] &=
- ~(MVPP2_PRS_SRAM_OP_SEL_UDF_MASK >>
- (8 - (MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS % 8)));
- pe->sram.byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS +
- MVPP2_PRS_SRAM_OP_SEL_UDF_BITS)] |=
- (op >> (8 - (MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS % 8)));
- /* Set base offset as current */
- mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
- }
- /* Find parser flow entry */
- static int mvpp2_prs_flow_find(struct mvpp2 *priv, int flow)
- {
- struct mvpp2_prs_entry pe;
- int tid;
- /* Go through the all entires with MVPP2_PRS_LU_FLOWS */
- for (tid = MVPP2_PRS_TCAM_SRAM_SIZE - 1; tid >= 0; tid--) {
- u8 bits;
- if (!priv->prs_shadow[tid].valid ||
- priv->prs_shadow[tid].lu != MVPP2_PRS_LU_FLOWS)
- continue;
- mvpp2_prs_init_from_hw(priv, &pe, tid);
- bits = mvpp2_prs_sram_ai_get(&pe);
- /* Sram store classification lookup ID in AI bits [5:0] */
- if ((bits & MVPP2_PRS_FLOW_ID_MASK) == flow)
- return tid;
- }
- return -ENOENT;
- }
- /* Return first free tcam index, seeking from start to end */
- static int mvpp2_prs_tcam_first_free(struct mvpp2 *priv, unsigned char start,
- unsigned char end)
- {
- int tid;
- if (start > end)
- swap(start, end);
- if (end >= MVPP2_PRS_TCAM_SRAM_SIZE)
- end = MVPP2_PRS_TCAM_SRAM_SIZE - 1;
- for (tid = start; tid <= end; tid++) {
- if (!priv->prs_shadow[tid].valid)
- return tid;
- }
- return -EINVAL;
- }
- /* Enable/disable dropping all mac da's */
- static void mvpp2_prs_mac_drop_all_set(struct mvpp2 *priv, int port, bool add)
- {
- struct mvpp2_prs_entry pe;
- if (priv->prs_shadow[MVPP2_PE_DROP_ALL].valid) {
- /* Entry exist - update port only */
- mvpp2_prs_init_from_hw(priv, &pe, MVPP2_PE_DROP_ALL);
- } else {
- /* Entry doesn't exist - create new */
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
- pe.index = MVPP2_PE_DROP_ALL;
- /* Non-promiscuous mode for all ports - DROP unknown packets */
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
- MVPP2_PRS_RI_DROP_MASK);
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- /* Update shadow table */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
- /* Mask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, 0);
- }
- /* Update port mask */
- mvpp2_prs_tcam_port_set(&pe, port, add);
- mvpp2_prs_hw_write(priv, &pe);
- }
- /* Set port to unicast or multicast promiscuous mode */
- void mvpp2_prs_mac_promisc_set(struct mvpp2 *priv, int port,
- enum mvpp2_prs_l2_cast l2_cast, bool add)
- {
- struct mvpp2_prs_entry pe;
- unsigned char cast_match;
- unsigned int ri;
- int tid;
- if (l2_cast == MVPP2_PRS_L2_UNI_CAST) {
- cast_match = MVPP2_PRS_UCAST_VAL;
- tid = MVPP2_PE_MAC_UC_PROMISCUOUS;
- ri = MVPP2_PRS_RI_L2_UCAST;
- } else {
- cast_match = MVPP2_PRS_MCAST_VAL;
- tid = MVPP2_PE_MAC_MC_PROMISCUOUS;
- ri = MVPP2_PRS_RI_L2_MCAST;
- }
- /* promiscuous mode - Accept unknown unicast or multicast packets */
- if (priv->prs_shadow[tid].valid) {
- mvpp2_prs_init_from_hw(priv, &pe, tid);
- } else {
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
- pe.index = tid;
- /* Continue - set next lookup */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA);
- /* Set result info bits */
- mvpp2_prs_sram_ri_update(&pe, ri, MVPP2_PRS_RI_L2_CAST_MASK);
- /* Match UC or MC addresses */
- mvpp2_prs_tcam_data_byte_set(&pe, 0, cast_match,
- MVPP2_PRS_CAST_MASK);
- /* Shift to ethertype */
- mvpp2_prs_sram_shift_set(&pe, 2 * ETH_ALEN,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- /* Mask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, 0);
- /* Update shadow table */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
- }
- /* Update port mask */
- mvpp2_prs_tcam_port_set(&pe, port, add);
- mvpp2_prs_hw_write(priv, &pe);
- }
- /* Set entry for dsa packets */
- static void mvpp2_prs_dsa_tag_set(struct mvpp2 *priv, int port, bool add,
- bool tagged, bool extend)
- {
- struct mvpp2_prs_entry pe;
- int tid, shift;
- if (extend) {
- tid = tagged ? MVPP2_PE_EDSA_TAGGED : MVPP2_PE_EDSA_UNTAGGED;
- shift = 8;
- } else {
- tid = tagged ? MVPP2_PE_DSA_TAGGED : MVPP2_PE_DSA_UNTAGGED;
- shift = 4;
- }
- if (priv->prs_shadow[tid].valid) {
- /* Entry exist - update port only */
- mvpp2_prs_init_from_hw(priv, &pe, tid);
- } else {
- /* Entry doesn't exist - create new */
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
- pe.index = tid;
- /* Update shadow table */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_DSA);
- if (tagged) {
- /* Set tagged bit in DSA tag */
- mvpp2_prs_tcam_data_byte_set(&pe, 0,
- MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
- MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
- /* Set ai bits for next iteration */
- if (extend)
- mvpp2_prs_sram_ai_update(&pe, 1,
- MVPP2_PRS_SRAM_AI_MASK);
- else
- mvpp2_prs_sram_ai_update(&pe, 0,
- MVPP2_PRS_SRAM_AI_MASK);
- /* Set result info bits to 'single vlan' */
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_SINGLE,
- MVPP2_PRS_RI_VLAN_MASK);
- /* If packet is tagged continue check vid filtering */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
- } else {
- /* Shift 4 bytes for DSA tag or 8 bytes for EDSA tag*/
- mvpp2_prs_sram_shift_set(&pe, shift,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- /* Set result info bits to 'no vlans' */
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
- MVPP2_PRS_RI_VLAN_MASK);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
- }
- /* Mask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, 0);
- }
- /* Update port mask */
- mvpp2_prs_tcam_port_set(&pe, port, add);
- mvpp2_prs_hw_write(priv, &pe);
- }
- /* Set entry for dsa ethertype */
- static void mvpp2_prs_dsa_tag_ethertype_set(struct mvpp2 *priv, int port,
- bool add, bool tagged, bool extend)
- {
- struct mvpp2_prs_entry pe;
- int tid, shift, port_mask;
- if (extend) {
- tid = tagged ? MVPP2_PE_ETYPE_EDSA_TAGGED :
- MVPP2_PE_ETYPE_EDSA_UNTAGGED;
- port_mask = 0;
- shift = 8;
- } else {
- tid = tagged ? MVPP2_PE_ETYPE_DSA_TAGGED :
- MVPP2_PE_ETYPE_DSA_UNTAGGED;
- port_mask = MVPP2_PRS_PORT_MASK;
- shift = 4;
- }
- if (priv->prs_shadow[tid].valid) {
- /* Entry exist - update port only */
- mvpp2_prs_init_from_hw(priv, &pe, tid);
- } else {
- /* Entry doesn't exist - create new */
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
- pe.index = tid;
- /* Set ethertype */
- mvpp2_prs_match_etype(&pe, 0, ETH_P_EDSA);
- mvpp2_prs_match_etype(&pe, 2, 0);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DSA_MASK,
- MVPP2_PRS_RI_DSA_MASK);
- /* Shift ethertype + 2 byte reserved + tag*/
- mvpp2_prs_sram_shift_set(&pe, 2 + MVPP2_ETH_TYPE_LEN + shift,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- /* Update shadow table */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_DSA);
- if (tagged) {
- /* Set tagged bit in DSA tag */
- mvpp2_prs_tcam_data_byte_set(&pe,
- MVPP2_ETH_TYPE_LEN + 2 + 3,
- MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
- MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
- /* Clear all ai bits for next iteration */
- mvpp2_prs_sram_ai_update(&pe, 0,
- MVPP2_PRS_SRAM_AI_MASK);
- /* If packet is tagged continue check vlans */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
- } else {
- /* Set result info bits to 'no vlans' */
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
- MVPP2_PRS_RI_VLAN_MASK);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
- }
- /* Mask/unmask all ports, depending on dsa type */
- mvpp2_prs_tcam_port_map_set(&pe, port_mask);
- }
- /* Update port mask */
- mvpp2_prs_tcam_port_set(&pe, port, add);
- mvpp2_prs_hw_write(priv, &pe);
- }
- /* Search for existing single/triple vlan entry */
- static int mvpp2_prs_vlan_find(struct mvpp2 *priv, unsigned short tpid, int ai)
- {
- struct mvpp2_prs_entry pe;
- int tid;
- /* Go through the all entries with MVPP2_PRS_LU_VLAN */
- for (tid = MVPP2_PE_FIRST_FREE_TID;
- tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
- unsigned int ri_bits, ai_bits;
- bool match;
- if (!priv->prs_shadow[tid].valid ||
- priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
- continue;
- mvpp2_prs_init_from_hw(priv, &pe, tid);
- match = mvpp2_prs_tcam_data_cmp(&pe, 0, swab16(tpid));
- if (!match)
- continue;
- /* Get vlan type */
- ri_bits = mvpp2_prs_sram_ri_get(&pe);
- ri_bits &= MVPP2_PRS_RI_VLAN_MASK;
- /* Get current ai value from tcam */
- ai_bits = mvpp2_prs_tcam_ai_get(&pe);
- /* Clear double vlan bit */
- ai_bits &= ~MVPP2_PRS_DBL_VLAN_AI_BIT;
- if (ai != ai_bits)
- continue;
- if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE ||
- ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE)
- return tid;
- }
- return -ENOENT;
- }
- /* Add/update single/triple vlan entry */
- static int mvpp2_prs_vlan_add(struct mvpp2 *priv, unsigned short tpid, int ai,
- unsigned int port_map)
- {
- struct mvpp2_prs_entry pe;
- int tid_aux, tid;
- int ret = 0;
- memset(&pe, 0, sizeof(pe));
- tid = mvpp2_prs_vlan_find(priv, tpid, ai);
- if (tid < 0) {
- /* Create new tcam entry */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_LAST_FREE_TID,
- MVPP2_PE_FIRST_FREE_TID);
- if (tid < 0)
- return tid;
- /* Get last double vlan tid */
- for (tid_aux = MVPP2_PE_LAST_FREE_TID;
- tid_aux >= MVPP2_PE_FIRST_FREE_TID; tid_aux--) {
- unsigned int ri_bits;
- if (!priv->prs_shadow[tid_aux].valid ||
- priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
- continue;
- mvpp2_prs_init_from_hw(priv, &pe, tid_aux);
- ri_bits = mvpp2_prs_sram_ri_get(&pe);
- if ((ri_bits & MVPP2_PRS_RI_VLAN_MASK) ==
- MVPP2_PRS_RI_VLAN_DOUBLE)
- break;
- }
- if (tid <= tid_aux)
- return -EINVAL;
- memset(&pe, 0, sizeof(pe));
- pe.index = tid;
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
- mvpp2_prs_match_etype(&pe, 0, tpid);
- /* VLAN tag detected, proceed with VID filtering */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
- /* Clear all ai bits for next iteration */
- mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
- if (ai == MVPP2_PRS_SINGLE_VLAN_AI) {
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_SINGLE,
- MVPP2_PRS_RI_VLAN_MASK);
- } else {
- ai |= MVPP2_PRS_DBL_VLAN_AI_BIT;
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_TRIPLE,
- MVPP2_PRS_RI_VLAN_MASK);
- }
- mvpp2_prs_tcam_ai_update(&pe, ai, MVPP2_PRS_SRAM_AI_MASK);
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
- } else {
- mvpp2_prs_init_from_hw(priv, &pe, tid);
- }
- /* Update ports' mask */
- mvpp2_prs_tcam_port_map_set(&pe, port_map);
- mvpp2_prs_hw_write(priv, &pe);
- return ret;
- }
- /* Get first free double vlan ai number */
- static int mvpp2_prs_double_vlan_ai_free_get(struct mvpp2 *priv)
- {
- int i;
- for (i = 1; i < MVPP2_PRS_DBL_VLANS_MAX; i++) {
- if (!priv->prs_double_vlans[i])
- return i;
- }
- return -EINVAL;
- }
- /* Search for existing double vlan entry */
- static int mvpp2_prs_double_vlan_find(struct mvpp2 *priv, unsigned short tpid1,
- unsigned short tpid2)
- {
- struct mvpp2_prs_entry pe;
- int tid;
- /* Go through the all entries with MVPP2_PRS_LU_VLAN */
- for (tid = MVPP2_PE_FIRST_FREE_TID;
- tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
- unsigned int ri_mask;
- bool match;
- if (!priv->prs_shadow[tid].valid ||
- priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
- continue;
- mvpp2_prs_init_from_hw(priv, &pe, tid);
- match = mvpp2_prs_tcam_data_cmp(&pe, 0, swab16(tpid1)) &&
- mvpp2_prs_tcam_data_cmp(&pe, 4, swab16(tpid2));
- if (!match)
- continue;
- ri_mask = mvpp2_prs_sram_ri_get(&pe) & MVPP2_PRS_RI_VLAN_MASK;
- if (ri_mask == MVPP2_PRS_RI_VLAN_DOUBLE)
- return tid;
- }
- return -ENOENT;
- }
- /* Add or update double vlan entry */
- static int mvpp2_prs_double_vlan_add(struct mvpp2 *priv, unsigned short tpid1,
- unsigned short tpid2,
- unsigned int port_map)
- {
- int tid_aux, tid, ai, ret = 0;
- struct mvpp2_prs_entry pe;
- memset(&pe, 0, sizeof(pe));
- tid = mvpp2_prs_double_vlan_find(priv, tpid1, tpid2);
- if (tid < 0) {
- /* Create new tcam entry */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- /* Set ai value for new double vlan entry */
- ai = mvpp2_prs_double_vlan_ai_free_get(priv);
- if (ai < 0)
- return ai;
- /* Get first single/triple vlan tid */
- for (tid_aux = MVPP2_PE_FIRST_FREE_TID;
- tid_aux <= MVPP2_PE_LAST_FREE_TID; tid_aux++) {
- unsigned int ri_bits;
- if (!priv->prs_shadow[tid_aux].valid ||
- priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
- continue;
- mvpp2_prs_init_from_hw(priv, &pe, tid_aux);
- ri_bits = mvpp2_prs_sram_ri_get(&pe);
- ri_bits &= MVPP2_PRS_RI_VLAN_MASK;
- if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE ||
- ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE)
- break;
- }
- if (tid >= tid_aux)
- return -ERANGE;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
- pe.index = tid;
- priv->prs_double_vlans[ai] = true;
- mvpp2_prs_match_etype(&pe, 0, tpid1);
- mvpp2_prs_match_etype(&pe, 4, tpid2);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
- /* Shift 4 bytes - skip outer vlan tag */
- mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_LEN,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_DOUBLE,
- MVPP2_PRS_RI_VLAN_MASK);
- mvpp2_prs_sram_ai_update(&pe, ai | MVPP2_PRS_DBL_VLAN_AI_BIT,
- MVPP2_PRS_SRAM_AI_MASK);
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
- } else {
- mvpp2_prs_init_from_hw(priv, &pe, tid);
- }
- /* Update ports' mask */
- mvpp2_prs_tcam_port_map_set(&pe, port_map);
- mvpp2_prs_hw_write(priv, &pe);
- return ret;
- }
- /* IPv4 header parsing for fragmentation and L4 offset */
- static int mvpp2_prs_ip4_proto(struct mvpp2 *priv, unsigned short proto,
- unsigned int ri, unsigned int ri_mask)
- {
- struct mvpp2_prs_entry pe;
- int tid;
- if ((proto != IPPROTO_TCP) && (proto != IPPROTO_UDP) &&
- (proto != IPPROTO_IGMP))
- return -EINVAL;
- /* Not fragmented packet */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
- pe.index = tid;
- /* Set next lu to IPv4 */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
- mvpp2_prs_sram_shift_set(&pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- /* Set L4 offset */
- mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
- sizeof(struct iphdr) - 4,
- MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
- mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
- MVPP2_PRS_IPV4_DIP_AI_BIT);
- mvpp2_prs_sram_ri_update(&pe, ri, ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK);
- mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00,
- MVPP2_PRS_TCAM_PROTO_MASK_L);
- mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00,
- MVPP2_PRS_TCAM_PROTO_MASK);
- mvpp2_prs_tcam_data_byte_set(&pe, 5, proto, MVPP2_PRS_TCAM_PROTO_MASK);
- mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
- mvpp2_prs_hw_write(priv, &pe);
- /* Fragmented packet */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- pe.index = tid;
- /* Clear ri before updating */
- pe.sram.word[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
- pe.sram.word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
- mvpp2_prs_sram_ri_update(&pe, ri, ri_mask);
- mvpp2_prs_sram_ri_update(&pe, ri | MVPP2_PRS_RI_IP_FRAG_TRUE,
- ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK);
- mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00, 0x0);
- mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00, 0x0);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
- mvpp2_prs_hw_write(priv, &pe);
- return 0;
- }
- /* IPv4 L3 multicast or broadcast */
- static int mvpp2_prs_ip4_cast(struct mvpp2 *priv, unsigned short l3_cast)
- {
- struct mvpp2_prs_entry pe;
- int mask, tid;
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
- pe.index = tid;
- switch (l3_cast) {
- case MVPP2_PRS_L3_MULTI_CAST:
- mvpp2_prs_tcam_data_byte_set(&pe, 0, MVPP2_PRS_IPV4_MC,
- MVPP2_PRS_IPV4_MC_MASK);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_MCAST,
- MVPP2_PRS_RI_L3_ADDR_MASK);
- break;
- case MVPP2_PRS_L3_BROAD_CAST:
- mask = MVPP2_PRS_IPV4_BC_MASK;
- mvpp2_prs_tcam_data_byte_set(&pe, 0, mask, mask);
- mvpp2_prs_tcam_data_byte_set(&pe, 1, mask, mask);
- mvpp2_prs_tcam_data_byte_set(&pe, 2, mask, mask);
- mvpp2_prs_tcam_data_byte_set(&pe, 3, mask, mask);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_BCAST,
- MVPP2_PRS_RI_L3_ADDR_MASK);
- break;
- default:
- return -EINVAL;
- }
- /* Finished: go to flowid generation */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
- mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
- MVPP2_PRS_IPV4_DIP_AI_BIT);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
- mvpp2_prs_hw_write(priv, &pe);
- return 0;
- }
- /* Set entries for protocols over IPv6 */
- static int mvpp2_prs_ip6_proto(struct mvpp2 *priv, unsigned short proto,
- unsigned int ri, unsigned int ri_mask)
- {
- struct mvpp2_prs_entry pe;
- int tid;
- if ((proto != IPPROTO_TCP) && (proto != IPPROTO_UDP) &&
- (proto != IPPROTO_ICMPV6) && (proto != IPPROTO_IPIP))
- return -EINVAL;
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
- pe.index = tid;
- /* Finished: go to flowid generation */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
- mvpp2_prs_sram_ri_update(&pe, ri, ri_mask);
- mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
- sizeof(struct ipv6hdr) - 6,
- MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
- mvpp2_prs_tcam_data_byte_set(&pe, 0, proto, MVPP2_PRS_TCAM_PROTO_MASK);
- mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
- MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Write HW */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6);
- mvpp2_prs_hw_write(priv, &pe);
- return 0;
- }
- /* IPv6 L3 multicast entry */
- static int mvpp2_prs_ip6_cast(struct mvpp2 *priv, unsigned short l3_cast)
- {
- struct mvpp2_prs_entry pe;
- int tid;
- if (l3_cast != MVPP2_PRS_L3_MULTI_CAST)
- return -EINVAL;
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
- pe.index = tid;
- /* Finished: go to flowid generation */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_MCAST,
- MVPP2_PRS_RI_L3_ADDR_MASK);
- mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
- MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
- /* Shift back to IPv6 NH */
- mvpp2_prs_sram_shift_set(&pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- mvpp2_prs_tcam_data_byte_set(&pe, 0, MVPP2_PRS_IPV6_MC,
- MVPP2_PRS_IPV6_MC_MASK);
- mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6);
- mvpp2_prs_hw_write(priv, &pe);
- return 0;
- }
- /* Parser per-port initialization */
- static void mvpp2_prs_hw_port_init(struct mvpp2 *priv, int port, int lu_first,
- int lu_max, int offset)
- {
- u32 val;
- /* Set lookup ID */
- val = mvpp2_read(priv, MVPP2_PRS_INIT_LOOKUP_REG);
- val &= ~MVPP2_PRS_PORT_LU_MASK(port);
- val |= MVPP2_PRS_PORT_LU_VAL(port, lu_first);
- mvpp2_write(priv, MVPP2_PRS_INIT_LOOKUP_REG, val);
- /* Set maximum number of loops for packet received from port */
- val = mvpp2_read(priv, MVPP2_PRS_MAX_LOOP_REG(port));
- val &= ~MVPP2_PRS_MAX_LOOP_MASK(port);
- val |= MVPP2_PRS_MAX_LOOP_VAL(port, lu_max);
- mvpp2_write(priv, MVPP2_PRS_MAX_LOOP_REG(port), val);
- /* Set initial offset for packet header extraction for the first
- * searching loop
- */
- val = mvpp2_read(priv, MVPP2_PRS_INIT_OFFS_REG(port));
- val &= ~MVPP2_PRS_INIT_OFF_MASK(port);
- val |= MVPP2_PRS_INIT_OFF_VAL(port, offset);
- mvpp2_write(priv, MVPP2_PRS_INIT_OFFS_REG(port), val);
- }
- /* Default flow entries initialization for all ports */
- static void mvpp2_prs_def_flow_init(struct mvpp2 *priv)
- {
- struct mvpp2_prs_entry pe;
- int port;
- for (port = 0; port < MVPP2_MAX_PORTS; port++) {
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- pe.index = MVPP2_PE_FIRST_DEFAULT_FLOW - port;
- /* Mask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, 0);
- /* Set flow ID*/
- mvpp2_prs_sram_ai_update(&pe, port, MVPP2_PRS_FLOW_ID_MASK);
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_FLOWS);
- mvpp2_prs_hw_write(priv, &pe);
- }
- }
- /* Set default entry for Marvell Header field */
- static void mvpp2_prs_mh_init(struct mvpp2 *priv)
- {
- struct mvpp2_prs_entry pe;
- memset(&pe, 0, sizeof(pe));
- pe.index = MVPP2_PE_MH_DEFAULT;
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MH);
- mvpp2_prs_sram_shift_set(&pe, MVPP2_MH_SIZE,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_MAC);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MH);
- mvpp2_prs_hw_write(priv, &pe);
- }
- /* Set default entires (place holder) for promiscuous, non-promiscuous and
- * multicast MAC addresses
- */
- static void mvpp2_prs_mac_init(struct mvpp2 *priv)
- {
- struct mvpp2_prs_entry pe;
- memset(&pe, 0, sizeof(pe));
- /* Non-promiscuous mode for all ports - DROP unknown packets */
- pe.index = MVPP2_PE_MAC_NON_PROMISCUOUS;
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
- MVPP2_PRS_RI_DROP_MASK);
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
- mvpp2_prs_hw_write(priv, &pe);
- /* Create dummy entries for drop all and promiscuous modes */
- mvpp2_prs_mac_drop_all_set(priv, 0, false);
- mvpp2_prs_mac_promisc_set(priv, 0, MVPP2_PRS_L2_UNI_CAST, false);
- mvpp2_prs_mac_promisc_set(priv, 0, MVPP2_PRS_L2_MULTI_CAST, false);
- }
- /* Set default entries for various types of dsa packets */
- static void mvpp2_prs_dsa_init(struct mvpp2 *priv)
- {
- struct mvpp2_prs_entry pe;
- /* None tagged EDSA entry - place holder */
- mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_UNTAGGED,
- MVPP2_PRS_EDSA);
- /* Tagged EDSA entry - place holder */
- mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
- /* None tagged DSA entry - place holder */
- mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_UNTAGGED,
- MVPP2_PRS_DSA);
- /* Tagged DSA entry - place holder */
- mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
- /* None tagged EDSA ethertype entry - place holder*/
- mvpp2_prs_dsa_tag_ethertype_set(priv, 0, false,
- MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
- /* Tagged EDSA ethertype entry - place holder*/
- mvpp2_prs_dsa_tag_ethertype_set(priv, 0, false,
- MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
- /* None tagged DSA ethertype entry */
- mvpp2_prs_dsa_tag_ethertype_set(priv, 0, true,
- MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
- /* Tagged DSA ethertype entry */
- mvpp2_prs_dsa_tag_ethertype_set(priv, 0, true,
- MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
- /* Set default entry, in case DSA or EDSA tag not found */
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
- pe.index = MVPP2_PE_DSA_DEFAULT;
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
- /* Shift 0 bytes */
- mvpp2_prs_sram_shift_set(&pe, 0, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
- /* Clear all sram ai bits for next iteration */
- mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- mvpp2_prs_hw_write(priv, &pe);
- }
- /* Initialize parser entries for VID filtering */
- static void mvpp2_prs_vid_init(struct mvpp2 *priv)
- {
- struct mvpp2_prs_entry pe;
- memset(&pe, 0, sizeof(pe));
- /* Set default vid entry */
- pe.index = MVPP2_PE_VID_FLTR_DEFAULT;
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
- mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_EDSA_VID_AI_BIT);
- /* Skip VLAN header - Set offset to 4 bytes */
- mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_LEN,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- /* Clear all ai bits for next iteration */
- mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
- mvpp2_prs_hw_write(priv, &pe);
- /* Set default vid entry for extended DSA*/
- memset(&pe, 0, sizeof(pe));
- /* Set default vid entry */
- pe.index = MVPP2_PE_VID_EDSA_FLTR_DEFAULT;
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
- mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_EDSA_VID_AI_BIT,
- MVPP2_PRS_EDSA_VID_AI_BIT);
- /* Skip VLAN header - Set offset to 8 bytes */
- mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_EDSA_LEN,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- /* Clear all ai bits for next iteration */
- mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
- mvpp2_prs_hw_write(priv, &pe);
- }
- /* Match basic ethertypes */
- static int mvpp2_prs_etype_init(struct mvpp2 *priv)
- {
- struct mvpp2_prs_entry pe;
- int tid;
- /* Ethertype: PPPoE */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
- pe.index = tid;
- mvpp2_prs_match_etype(&pe, 0, ETH_P_PPP_SES);
- mvpp2_prs_sram_shift_set(&pe, MVPP2_PPPOE_HDR_SIZE,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_PPPOE_MASK,
- MVPP2_PRS_RI_PPPOE_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
- priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
- priv->prs_shadow[pe.index].finish = false;
- mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_PPPOE_MASK,
- MVPP2_PRS_RI_PPPOE_MASK);
- mvpp2_prs_hw_write(priv, &pe);
- /* Ethertype: ARP */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
- pe.index = tid;
- mvpp2_prs_match_etype(&pe, 0, ETH_P_ARP);
- /* Generate flow in the next iteration*/
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_ARP,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- /* Set L3 offset */
- mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
- MVPP2_ETH_TYPE_LEN,
- MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
- priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
- priv->prs_shadow[pe.index].finish = true;
- mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_ARP,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- mvpp2_prs_hw_write(priv, &pe);
- /* Ethertype: LBTD */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
- pe.index = tid;
- mvpp2_prs_match_etype(&pe, 0, MVPP2_IP_LBDT_TYPE);
- /* Generate flow in the next iteration*/
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
- MVPP2_PRS_RI_UDF3_RX_SPECIAL,
- MVPP2_PRS_RI_CPU_CODE_MASK |
- MVPP2_PRS_RI_UDF3_MASK);
- /* Set L3 offset */
- mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
- MVPP2_ETH_TYPE_LEN,
- MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
- priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
- priv->prs_shadow[pe.index].finish = true;
- mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
- MVPP2_PRS_RI_UDF3_RX_SPECIAL,
- MVPP2_PRS_RI_CPU_CODE_MASK |
- MVPP2_PRS_RI_UDF3_MASK);
- mvpp2_prs_hw_write(priv, &pe);
- /* Ethertype: IPv4 without options */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
- pe.index = tid;
- mvpp2_prs_match_etype(&pe, 0, ETH_P_IP);
- mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
- MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL,
- MVPP2_PRS_IPV4_HEAD_MASK |
- MVPP2_PRS_IPV4_IHL_MASK);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- /* Skip eth_type + 4 bytes of IP header */
- mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 4,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- /* Set L3 offset */
- mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
- MVPP2_ETH_TYPE_LEN,
- MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
- priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
- priv->prs_shadow[pe.index].finish = false;
- mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_IP4,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- mvpp2_prs_hw_write(priv, &pe);
- /* Ethertype: IPv4 with options */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- pe.index = tid;
- /* Clear tcam data before updating */
- pe.tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE(MVPP2_ETH_TYPE_LEN)] = 0x0;
- pe.tcam.byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(MVPP2_ETH_TYPE_LEN)] = 0x0;
- mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
- MVPP2_PRS_IPV4_HEAD,
- MVPP2_PRS_IPV4_HEAD_MASK);
- /* Clear ri before updating */
- pe.sram.word[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
- pe.sram.word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4_OPT,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
- priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
- priv->prs_shadow[pe.index].finish = false;
- mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_IP4_OPT,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- mvpp2_prs_hw_write(priv, &pe);
- /* Ethertype: IPv6 without options */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
- pe.index = tid;
- mvpp2_prs_match_etype(&pe, 0, ETH_P_IPV6);
- /* Skip DIP of IPV6 header */
- mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 8 +
- MVPP2_MAX_L3_ADDR_SIZE,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP6,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- /* Set L3 offset */
- mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
- MVPP2_ETH_TYPE_LEN,
- MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
- priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
- priv->prs_shadow[pe.index].finish = false;
- mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_IP6,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- mvpp2_prs_hw_write(priv, &pe);
- /* Default entry for MVPP2_PRS_LU_L2 - Unknown ethtype */
- memset(&pe, 0, sizeof(struct mvpp2_prs_entry));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
- pe.index = MVPP2_PE_ETH_TYPE_UN;
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Generate flow in the next iteration*/
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- /* Set L3 offset even it's unknown L3 */
- mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
- MVPP2_ETH_TYPE_LEN,
- MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
- priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
- priv->prs_shadow[pe.index].finish = true;
- mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_UN,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- mvpp2_prs_hw_write(priv, &pe);
- return 0;
- }
- /* Configure vlan entries and detect up to 2 successive VLAN tags.
- * Possible options:
- * 0x8100, 0x88A8
- * 0x8100, 0x8100
- * 0x8100
- * 0x88A8
- */
- static int mvpp2_prs_vlan_init(struct platform_device *pdev, struct mvpp2 *priv)
- {
- struct mvpp2_prs_entry pe;
- int err;
- priv->prs_double_vlans = devm_kcalloc(&pdev->dev, sizeof(bool),
- MVPP2_PRS_DBL_VLANS_MAX,
- GFP_KERNEL);
- if (!priv->prs_double_vlans)
- return -ENOMEM;
- /* Double VLAN: 0x8100, 0x88A8 */
- err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021Q, ETH_P_8021AD,
- MVPP2_PRS_PORT_MASK);
- if (err)
- return err;
- /* Double VLAN: 0x8100, 0x8100 */
- err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021Q, ETH_P_8021Q,
- MVPP2_PRS_PORT_MASK);
- if (err)
- return err;
- /* Single VLAN: 0x88a8 */
- err = mvpp2_prs_vlan_add(priv, ETH_P_8021AD, MVPP2_PRS_SINGLE_VLAN_AI,
- MVPP2_PRS_PORT_MASK);
- if (err)
- return err;
- /* Single VLAN: 0x8100 */
- err = mvpp2_prs_vlan_add(priv, ETH_P_8021Q, MVPP2_PRS_SINGLE_VLAN_AI,
- MVPP2_PRS_PORT_MASK);
- if (err)
- return err;
- /* Set default double vlan entry */
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
- pe.index = MVPP2_PE_VLAN_DBL;
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
- /* Clear ai for next iterations */
- mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_DOUBLE,
- MVPP2_PRS_RI_VLAN_MASK);
- mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_DBL_VLAN_AI_BIT,
- MVPP2_PRS_DBL_VLAN_AI_BIT);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
- mvpp2_prs_hw_write(priv, &pe);
- /* Set default vlan none entry */
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
- pe.index = MVPP2_PE_VLAN_NONE;
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
- MVPP2_PRS_RI_VLAN_MASK);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
- mvpp2_prs_hw_write(priv, &pe);
- return 0;
- }
- /* Set entries for PPPoE ethertype */
- static int mvpp2_prs_pppoe_init(struct mvpp2 *priv)
- {
- struct mvpp2_prs_entry pe;
- int tid;
- /* IPv4 over PPPoE with options */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
- pe.index = tid;
- mvpp2_prs_match_etype(&pe, 0, PPP_IP);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4_OPT,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- /* Skip eth_type + 4 bytes of IP header */
- mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 4,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- /* Set L3 offset */
- mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
- MVPP2_ETH_TYPE_LEN,
- MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
- mvpp2_prs_hw_write(priv, &pe);
- /* IPv4 over PPPoE without options */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- pe.index = tid;
- mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
- MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL,
- MVPP2_PRS_IPV4_HEAD_MASK |
- MVPP2_PRS_IPV4_IHL_MASK);
- /* Clear ri before updating */
- pe.sram.word[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
- pe.sram.word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
- mvpp2_prs_hw_write(priv, &pe);
- /* IPv6 over PPPoE */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
- pe.index = tid;
- mvpp2_prs_match_etype(&pe, 0, PPP_IPV6);
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP6,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- /* Skip eth_type + 4 bytes of IPv6 header */
- mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 4,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- /* Set L3 offset */
- mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
- MVPP2_ETH_TYPE_LEN,
- MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
- mvpp2_prs_hw_write(priv, &pe);
- /* Non-IP over PPPoE */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
- pe.index = tid;
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN,
- MVPP2_PRS_RI_L3_PROTO_MASK);
- /* Finished: go to flowid generation */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
- /* Set L3 offset even if it's unknown L3 */
- mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
- MVPP2_ETH_TYPE_LEN,
- MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
- mvpp2_prs_hw_write(priv, &pe);
- return 0;
- }
- /* Initialize entries for IPv4 */
- static int mvpp2_prs_ip4_init(struct mvpp2 *priv)
- {
- struct mvpp2_prs_entry pe;
- int err;
- /* Set entries for TCP, UDP and IGMP over IPv4 */
- err = mvpp2_prs_ip4_proto(priv, IPPROTO_TCP, MVPP2_PRS_RI_L4_TCP,
- MVPP2_PRS_RI_L4_PROTO_MASK);
- if (err)
- return err;
- err = mvpp2_prs_ip4_proto(priv, IPPROTO_UDP, MVPP2_PRS_RI_L4_UDP,
- MVPP2_PRS_RI_L4_PROTO_MASK);
- if (err)
- return err;
- err = mvpp2_prs_ip4_proto(priv, IPPROTO_IGMP,
- MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
- MVPP2_PRS_RI_UDF3_RX_SPECIAL,
- MVPP2_PRS_RI_CPU_CODE_MASK |
- MVPP2_PRS_RI_UDF3_MASK);
- if (err)
- return err;
- /* IPv4 Broadcast */
- err = mvpp2_prs_ip4_cast(priv, MVPP2_PRS_L3_BROAD_CAST);
- if (err)
- return err;
- /* IPv4 Multicast */
- err = mvpp2_prs_ip4_cast(priv, MVPP2_PRS_L3_MULTI_CAST);
- if (err)
- return err;
- /* Default IPv4 entry for unknown protocols */
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
- pe.index = MVPP2_PE_IP4_PROTO_UN;
- /* Set next lu to IPv4 */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
- mvpp2_prs_sram_shift_set(&pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- /* Set L4 offset */
- mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
- sizeof(struct iphdr) - 4,
- MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
- mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
- MVPP2_PRS_IPV4_DIP_AI_BIT);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
- MVPP2_PRS_RI_L4_PROTO_MASK);
- mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
- mvpp2_prs_hw_write(priv, &pe);
- /* Default IPv4 entry for unicast address */
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
- pe.index = MVPP2_PE_IP4_ADDR_UN;
- /* Finished: go to flowid generation */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UCAST,
- MVPP2_PRS_RI_L3_ADDR_MASK);
- mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
- MVPP2_PRS_IPV4_DIP_AI_BIT);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
- mvpp2_prs_hw_write(priv, &pe);
- return 0;
- }
- /* Initialize entries for IPv6 */
- static int mvpp2_prs_ip6_init(struct mvpp2 *priv)
- {
- struct mvpp2_prs_entry pe;
- int tid, err;
- /* Set entries for TCP, UDP and ICMP over IPv6 */
- err = mvpp2_prs_ip6_proto(priv, IPPROTO_TCP,
- MVPP2_PRS_RI_L4_TCP,
- MVPP2_PRS_RI_L4_PROTO_MASK);
- if (err)
- return err;
- err = mvpp2_prs_ip6_proto(priv, IPPROTO_UDP,
- MVPP2_PRS_RI_L4_UDP,
- MVPP2_PRS_RI_L4_PROTO_MASK);
- if (err)
- return err;
- err = mvpp2_prs_ip6_proto(priv, IPPROTO_ICMPV6,
- MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
- MVPP2_PRS_RI_UDF3_RX_SPECIAL,
- MVPP2_PRS_RI_CPU_CODE_MASK |
- MVPP2_PRS_RI_UDF3_MASK);
- if (err)
- return err;
- /* IPv4 is the last header. This is similar case as 6-TCP or 17-UDP */
- /* Result Info: UDF7=1, DS lite */
- err = mvpp2_prs_ip6_proto(priv, IPPROTO_IPIP,
- MVPP2_PRS_RI_UDF7_IP6_LITE,
- MVPP2_PRS_RI_UDF7_MASK);
- if (err)
- return err;
- /* IPv6 multicast */
- err = mvpp2_prs_ip6_cast(priv, MVPP2_PRS_L3_MULTI_CAST);
- if (err)
- return err;
- /* Entry for checking hop limit */
- tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
- MVPP2_PE_LAST_FREE_TID);
- if (tid < 0)
- return tid;
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
- pe.index = tid;
- /* Finished: go to flowid generation */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN |
- MVPP2_PRS_RI_DROP_MASK,
- MVPP2_PRS_RI_L3_PROTO_MASK |
- MVPP2_PRS_RI_DROP_MASK);
- mvpp2_prs_tcam_data_byte_set(&pe, 1, 0x00, MVPP2_PRS_IPV6_HOP_MASK);
- mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
- MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
- mvpp2_prs_hw_write(priv, &pe);
- /* Default IPv6 entry for unknown protocols */
- memset(&pe, 0, sizeof(pe));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
- pe.index = MVPP2_PE_IP6_PROTO_UN;
- /* Finished: go to flowid generation */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
- MVPP2_PRS_RI_L4_PROTO_MASK);
- /* Set L4 offset relatively to our current place */
- mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
- sizeof(struct ipv6hdr) - 4,
- MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
- mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
- MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
- mvpp2_prs_hw_write(priv, &pe);
- /* Default IPv6 entry for unknown ext protocols */
- memset(&pe, 0, sizeof(struct mvpp2_prs_entry));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
- pe.index = MVPP2_PE_IP6_EXT_PROTO_UN;
- /* Finished: go to flowid generation */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
- MVPP2_PRS_RI_L4_PROTO_MASK);
- mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_EXT_AI_BIT,
- MVPP2_PRS_IPV6_EXT_AI_BIT);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
- mvpp2_prs_hw_write(priv, &pe);
- /* Default IPv6 entry for unicast address */
- memset(&pe, 0, sizeof(struct mvpp2_prs_entry));
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
- pe.index = MVPP2_PE_IP6_ADDR_UN;
- /* Finished: go to IPv6 again */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UCAST,
- MVPP2_PRS_RI_L3_ADDR_MASK);
- mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
- MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
- /* Shift back to IPV6 NH */
- mvpp2_prs_sram_shift_set(&pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
- /* Unmask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
- /* Update shadow table and hw entry */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6);
- mvpp2_prs_hw_write(priv, &pe);
- return 0;
- }
- /* Find tcam entry with matched pair <vid,port> */
- static int mvpp2_prs_vid_range_find(struct mvpp2 *priv, int pmap, u16 vid,
- u16 mask)
- {
- unsigned char byte[2], enable[2];
- struct mvpp2_prs_entry pe;
- u16 rvid, rmask;
- int tid;
- /* Go through the all entries with MVPP2_PRS_LU_VID */
- for (tid = MVPP2_PE_VID_FILT_RANGE_START;
- tid <= MVPP2_PE_VID_FILT_RANGE_END; tid++) {
- if (!priv->prs_shadow[tid].valid ||
- priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VID)
- continue;
- mvpp2_prs_init_from_hw(priv, &pe, tid);
- mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]);
- mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]);
- rvid = ((byte[0] & 0xf) << 8) + byte[1];
- rmask = ((enable[0] & 0xf) << 8) + enable[1];
- if (rvid != vid || rmask != mask)
- continue;
- return tid;
- }
- return -ENOENT;
- }
- /* Write parser entry for VID filtering */
- int mvpp2_prs_vid_entry_add(struct mvpp2_port *port, u16 vid)
- {
- unsigned int vid_start = MVPP2_PE_VID_FILT_RANGE_START +
- port->id * MVPP2_PRS_VLAN_FILT_MAX;
- unsigned int mask = 0xfff, reg_val, shift;
- struct mvpp2 *priv = port->priv;
- struct mvpp2_prs_entry pe;
- int tid;
- memset(&pe, 0, sizeof(pe));
- /* Scan TCAM and see if entry with this <vid,port> already exist */
- tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, mask);
- reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
- if (reg_val & MVPP2_DSA_EXTENDED)
- shift = MVPP2_VLAN_TAG_EDSA_LEN;
- else
- shift = MVPP2_VLAN_TAG_LEN;
- /* No such entry */
- if (tid < 0) {
- /* Go through all entries from first to last in vlan range */
- tid = mvpp2_prs_tcam_first_free(priv, vid_start,
- vid_start +
- MVPP2_PRS_VLAN_FILT_MAX_ENTRY);
- /* There isn't room for a new VID filter */
- if (tid < 0)
- return tid;
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
- pe.index = tid;
- /* Mask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, 0);
- } else {
- mvpp2_prs_init_from_hw(priv, &pe, tid);
- }
- /* Enable the current port */
- mvpp2_prs_tcam_port_set(&pe, port->id, true);
- /* Continue - set next lookup */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
- /* Skip VLAN header - Set offset to 4 or 8 bytes */
- mvpp2_prs_sram_shift_set(&pe, shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- /* Set match on VID */
- mvpp2_prs_match_vid(&pe, MVPP2_PRS_VID_TCAM_BYTE, vid);
- /* Clear all ai bits for next iteration */
- mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
- /* Update shadow table */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
- mvpp2_prs_hw_write(priv, &pe);
- return 0;
- }
- /* Write parser entry for VID filtering */
- void mvpp2_prs_vid_entry_remove(struct mvpp2_port *port, u16 vid)
- {
- struct mvpp2 *priv = port->priv;
- int tid;
- /* Scan TCAM and see if entry with this <vid,port> already exist */
- tid = mvpp2_prs_vid_range_find(priv, (1 << port->id), vid, 0xfff);
- /* No such entry */
- if (tid < 0)
- return;
- mvpp2_prs_hw_inv(priv, tid);
- priv->prs_shadow[tid].valid = false;
- }
- /* Remove all existing VID filters on this port */
- void mvpp2_prs_vid_remove_all(struct mvpp2_port *port)
- {
- struct mvpp2 *priv = port->priv;
- int tid;
- for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
- tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
- if (priv->prs_shadow[tid].valid)
- mvpp2_prs_vid_entry_remove(port, tid);
- }
- }
- /* Remove VID filering entry for this port */
- void mvpp2_prs_vid_disable_filtering(struct mvpp2_port *port)
- {
- unsigned int tid = MVPP2_PRS_VID_PORT_DFLT(port->id);
- struct mvpp2 *priv = port->priv;
- /* Invalidate the guard entry */
- mvpp2_prs_hw_inv(priv, tid);
- priv->prs_shadow[tid].valid = false;
- }
- /* Add guard entry that drops packets when no VID is matched on this port */
- void mvpp2_prs_vid_enable_filtering(struct mvpp2_port *port)
- {
- unsigned int tid = MVPP2_PRS_VID_PORT_DFLT(port->id);
- struct mvpp2 *priv = port->priv;
- unsigned int reg_val, shift;
- struct mvpp2_prs_entry pe;
- if (priv->prs_shadow[tid].valid)
- return;
- memset(&pe, 0, sizeof(pe));
- pe.index = tid;
- reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
- if (reg_val & MVPP2_DSA_EXTENDED)
- shift = MVPP2_VLAN_TAG_EDSA_LEN;
- else
- shift = MVPP2_VLAN_TAG_LEN;
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
- /* Mask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, 0);
- /* Update port mask */
- mvpp2_prs_tcam_port_set(&pe, port->id, true);
- /* Continue - set next lookup */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
- /* Skip VLAN header - Set offset to 4 or 8 bytes */
- mvpp2_prs_sram_shift_set(&pe, shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- /* Drop VLAN packets that don't belong to any VIDs on this port */
- mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
- MVPP2_PRS_RI_DROP_MASK);
- /* Clear all ai bits for next iteration */
- mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
- /* Update shadow table */
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
- mvpp2_prs_hw_write(priv, &pe);
- }
- /* Parser default initialization */
- int mvpp2_prs_default_init(struct platform_device *pdev, struct mvpp2 *priv)
- {
- int err, index, i;
- /* Enable tcam table */
- mvpp2_write(priv, MVPP2_PRS_TCAM_CTRL_REG, MVPP2_PRS_TCAM_EN_MASK);
- /* Clear all tcam and sram entries */
- for (index = 0; index < MVPP2_PRS_TCAM_SRAM_SIZE; index++) {
- mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, index);
- for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
- mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), 0);
- mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, index);
- for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
- mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), 0);
- }
- /* Invalidate all tcam entries */
- for (index = 0; index < MVPP2_PRS_TCAM_SRAM_SIZE; index++)
- mvpp2_prs_hw_inv(priv, index);
- priv->prs_shadow = devm_kcalloc(&pdev->dev, MVPP2_PRS_TCAM_SRAM_SIZE,
- sizeof(*priv->prs_shadow),
- GFP_KERNEL);
- if (!priv->prs_shadow)
- return -ENOMEM;
- /* Always start from lookup = 0 */
- for (index = 0; index < MVPP2_MAX_PORTS; index++)
- mvpp2_prs_hw_port_init(priv, index, MVPP2_PRS_LU_MH,
- MVPP2_PRS_PORT_LU_MAX, 0);
- mvpp2_prs_def_flow_init(priv);
- mvpp2_prs_mh_init(priv);
- mvpp2_prs_mac_init(priv);
- mvpp2_prs_dsa_init(priv);
- mvpp2_prs_vid_init(priv);
- err = mvpp2_prs_etype_init(priv);
- if (err)
- return err;
- err = mvpp2_prs_vlan_init(pdev, priv);
- if (err)
- return err;
- err = mvpp2_prs_pppoe_init(priv);
- if (err)
- return err;
- err = mvpp2_prs_ip6_init(priv);
- if (err)
- return err;
- err = mvpp2_prs_ip4_init(priv);
- if (err)
- return err;
- return 0;
- }
- /* Compare MAC DA with tcam entry data */
- static bool mvpp2_prs_mac_range_equals(struct mvpp2_prs_entry *pe,
- const u8 *da, unsigned char *mask)
- {
- unsigned char tcam_byte, tcam_mask;
- int index;
- for (index = 0; index < ETH_ALEN; index++) {
- mvpp2_prs_tcam_data_byte_get(pe, index, &tcam_byte, &tcam_mask);
- if (tcam_mask != mask[index])
- return false;
- if ((tcam_mask & tcam_byte) != (da[index] & mask[index]))
- return false;
- }
- return true;
- }
- /* Find tcam entry with matched pair <MAC DA, port> */
- static int
- mvpp2_prs_mac_da_range_find(struct mvpp2 *priv, int pmap, const u8 *da,
- unsigned char *mask, int udf_type)
- {
- struct mvpp2_prs_entry pe;
- int tid;
- /* Go through the all entires with MVPP2_PRS_LU_MAC */
- for (tid = MVPP2_PE_MAC_RANGE_START;
- tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
- unsigned int entry_pmap;
- if (!priv->prs_shadow[tid].valid ||
- (priv->prs_shadow[tid].lu != MVPP2_PRS_LU_MAC) ||
- (priv->prs_shadow[tid].udf != udf_type))
- continue;
- mvpp2_prs_init_from_hw(priv, &pe, tid);
- entry_pmap = mvpp2_prs_tcam_port_map_get(&pe);
- if (mvpp2_prs_mac_range_equals(&pe, da, mask) &&
- entry_pmap == pmap)
- return tid;
- }
- return -ENOENT;
- }
- /* Update parser's mac da entry */
- int mvpp2_prs_mac_da_accept(struct mvpp2_port *port, const u8 *da, bool add)
- {
- unsigned char mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- struct mvpp2 *priv = port->priv;
- unsigned int pmap, len, ri;
- struct mvpp2_prs_entry pe;
- int tid;
- memset(&pe, 0, sizeof(pe));
- /* Scan TCAM and see if entry with this <MAC DA, port> already exist */
- tid = mvpp2_prs_mac_da_range_find(priv, BIT(port->id), da, mask,
- MVPP2_PRS_UDF_MAC_DEF);
- /* No such entry */
- if (tid < 0) {
- if (!add)
- return 0;
- /* Create new TCAM entry */
- /* Go through the all entries from first to last */
- tid = mvpp2_prs_tcam_first_free(priv,
- MVPP2_PE_MAC_RANGE_START,
- MVPP2_PE_MAC_RANGE_END);
- if (tid < 0)
- return tid;
- pe.index = tid;
- /* Mask all ports */
- mvpp2_prs_tcam_port_map_set(&pe, 0);
- } else {
- mvpp2_prs_init_from_hw(priv, &pe, tid);
- }
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
- /* Update port mask */
- mvpp2_prs_tcam_port_set(&pe, port->id, add);
- /* Invalidate the entry if no ports are left enabled */
- pmap = mvpp2_prs_tcam_port_map_get(&pe);
- if (pmap == 0) {
- if (add)
- return -EINVAL;
- mvpp2_prs_hw_inv(priv, pe.index);
- priv->prs_shadow[pe.index].valid = false;
- return 0;
- }
- /* Continue - set next lookup */
- mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA);
- /* Set match on DA */
- len = ETH_ALEN;
- while (len--)
- mvpp2_prs_tcam_data_byte_set(&pe, len, da[len], 0xff);
- /* Set result info bits */
- if (is_broadcast_ether_addr(da)) {
- ri = MVPP2_PRS_RI_L2_BCAST;
- } else if (is_multicast_ether_addr(da)) {
- ri = MVPP2_PRS_RI_L2_MCAST;
- } else {
- ri = MVPP2_PRS_RI_L2_UCAST;
- if (ether_addr_equal(da, port->dev->dev_addr))
- ri |= MVPP2_PRS_RI_MAC_ME_MASK;
- }
- mvpp2_prs_sram_ri_update(&pe, ri, MVPP2_PRS_RI_L2_CAST_MASK |
- MVPP2_PRS_RI_MAC_ME_MASK);
- mvpp2_prs_shadow_ri_set(priv, pe.index, ri, MVPP2_PRS_RI_L2_CAST_MASK |
- MVPP2_PRS_RI_MAC_ME_MASK);
- /* Shift to ethertype */
- mvpp2_prs_sram_shift_set(&pe, 2 * ETH_ALEN,
- MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
- /* Update shadow table and hw entry */
- priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_MAC_DEF;
- mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
- mvpp2_prs_hw_write(priv, &pe);
- return 0;
- }
- int mvpp2_prs_update_mac_da(struct net_device *dev, const u8 *da)
- {
- struct mvpp2_port *port = netdev_priv(dev);
- int err;
- /* Remove old parser entry */
- err = mvpp2_prs_mac_da_accept(port, dev->dev_addr, false);
- if (err)
- return err;
- /* Add new parser entry */
- err = mvpp2_prs_mac_da_accept(port, da, true);
- if (err)
- return err;
- /* Set addr in the device */
- ether_addr_copy(dev->dev_addr, da);
- return 0;
- }
- void mvpp2_prs_mac_del_all(struct mvpp2_port *port)
- {
- struct mvpp2 *priv = port->priv;
- struct mvpp2_prs_entry pe;
- unsigned long pmap;
- int index, tid;
- for (tid = MVPP2_PE_MAC_RANGE_START;
- tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
- unsigned char da[ETH_ALEN], da_mask[ETH_ALEN];
- if (!priv->prs_shadow[tid].valid ||
- (priv->prs_shadow[tid].lu != MVPP2_PRS_LU_MAC) ||
- (priv->prs_shadow[tid].udf != MVPP2_PRS_UDF_MAC_DEF))
- continue;
- mvpp2_prs_init_from_hw(priv, &pe, tid);
- pmap = mvpp2_prs_tcam_port_map_get(&pe);
- /* We only want entries active on this port */
- if (!test_bit(port->id, &pmap))
- continue;
- /* Read mac addr from entry */
- for (index = 0; index < ETH_ALEN; index++)
- mvpp2_prs_tcam_data_byte_get(&pe, index, &da[index],
- &da_mask[index]);
- /* Special cases : Don't remove broadcast and port's own
- * address
- */
- if (is_broadcast_ether_addr(da) ||
- ether_addr_equal(da, port->dev->dev_addr))
- continue;
- /* Remove entry from TCAM */
- mvpp2_prs_mac_da_accept(port, da, false);
- }
- }
- int mvpp2_prs_tag_mode_set(struct mvpp2 *priv, int port, int type)
- {
- switch (type) {
- case MVPP2_TAG_TYPE_EDSA:
- /* Add port to EDSA entries */
- mvpp2_prs_dsa_tag_set(priv, port, true,
- MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
- mvpp2_prs_dsa_tag_set(priv, port, true,
- MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
- /* Remove port from DSA entries */
- mvpp2_prs_dsa_tag_set(priv, port, false,
- MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
- mvpp2_prs_dsa_tag_set(priv, port, false,
- MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
- break;
- case MVPP2_TAG_TYPE_DSA:
- /* Add port to DSA entries */
- mvpp2_prs_dsa_tag_set(priv, port, true,
- MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
- mvpp2_prs_dsa_tag_set(priv, port, true,
- MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
- /* Remove port from EDSA entries */
- mvpp2_prs_dsa_tag_set(priv, port, false,
- MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
- mvpp2_prs_dsa_tag_set(priv, port, false,
- MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
- break;
- case MVPP2_TAG_TYPE_MH:
- case MVPP2_TAG_TYPE_NONE:
- /* Remove port form EDSA and DSA entries */
- mvpp2_prs_dsa_tag_set(priv, port, false,
- MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
- mvpp2_prs_dsa_tag_set(priv, port, false,
- MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
- mvpp2_prs_dsa_tag_set(priv, port, false,
- MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
- mvpp2_prs_dsa_tag_set(priv, port, false,
- MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
- break;
- default:
- if ((type < 0) || (type > MVPP2_TAG_TYPE_EDSA))
- return -EINVAL;
- }
- return 0;
- }
- /* Set prs flow for the port */
- int mvpp2_prs_def_flow(struct mvpp2_port *port)
- {
- struct mvpp2_prs_entry pe;
- int tid;
- memset(&pe, 0, sizeof(pe));
- tid = mvpp2_prs_flow_find(port->priv, port->id);
- /* Such entry not exist */
- if (tid < 0) {
- /* Go through the all entires from last to first */
- tid = mvpp2_prs_tcam_first_free(port->priv,
- MVPP2_PE_LAST_FREE_TID,
- MVPP2_PE_FIRST_FREE_TID);
- if (tid < 0)
- return tid;
- pe.index = tid;
- /* Set flow ID*/
- mvpp2_prs_sram_ai_update(&pe, port->id, MVPP2_PRS_FLOW_ID_MASK);
- mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
- /* Update shadow table */
- mvpp2_prs_shadow_set(port->priv, pe.index, MVPP2_PRS_LU_FLOWS);
- } else {
- mvpp2_prs_init_from_hw(port->priv, &pe, tid);
- }
- mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
- mvpp2_prs_tcam_port_map_set(&pe, (1 << port->id));
- mvpp2_prs_hw_write(port->priv, &pe);
- return 0;
- }
|