12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398 |
- /*
- * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
- *
- * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
- *
- *
- * Permission to use, copy, modify, and/or distribute this software for
- * any purpose with or without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all
- * copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
- * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
- /*
- * This file was originally distributed by Qualcomm Atheros, Inc.
- * under proprietary terms before Copyright ownership was assigned
- * to the Linux Foundation.
- */
- /*=== includes ===*/
- /* header files for OS primitives */
- #include <osdep.h> /* uint32_t, etc. */
- #include <cdf_memory.h> /* cdf_mem_malloc,free */
- #include <cdf_types.h> /* cdf_device_t, cdf_print */
- #include <cdf_lock.h> /* cdf_spinlock */
- #include <cdf_atomic.h> /* cdf_atomic_read */
- /* Required for WLAN_FEATURE_FASTPATH */
- #include <ce_api.h>
- /* header files for utilities */
- #include <cds_queue.h> /* TAILQ */
- /* header files for configuration API */
- #include <ol_cfg.h> /* ol_cfg_is_high_latency */
- #include <ol_if_athvar.h>
- /* header files for HTT API */
- #include <ol_htt_api.h>
- #include <ol_htt_tx_api.h>
- /* header files for OS shim API */
- #include <ol_osif_api.h>
- /* header files for our own APIs */
- #include <ol_txrx_api.h>
- #include <ol_txrx_dbg.h>
- #include <ol_txrx_ctrl_api.h>
- #include <ol_txrx_osif_api.h>
- /* header files for our internal definitions */
- #include <ol_txrx_internal.h> /* TXRX_ASSERT, etc. */
- #include <wdi_event.h> /* WDI events */
- #include <ol_txrx_types.h> /* ol_txrx_pdev_t, etc. */
- #include <ol_ctrl_txrx_api.h>
- #include <ol_tx.h> /* ol_tx_ll */
- #include <ol_rx.h> /* ol_rx_deliver */
- #include <ol_txrx_peer_find.h> /* ol_txrx_peer_find_attach, etc. */
- #include <ol_rx_pn.h> /* ol_rx_pn_check, etc. */
- #include <ol_rx_fwd.h> /* ol_rx_fwd_check, etc. */
- #include <ol_rx_reorder_timeout.h> /* OL_RX_REORDER_TIMEOUT_INIT, etc. */
- #include <ol_rx_reorder.h>
- #include <ol_tx_send.h> /* ol_tx_discard_target_frms */
- #include <ol_tx_desc.h> /* ol_tx_desc_frame_free */
- #include <ol_tx_queue.h>
- #include <ol_txrx.h>
- #include "wma.h"
- /*=== function definitions ===*/
- /**
- * ol_tx_set_is_mgmt_over_wmi_enabled() - set flag to indicate that mgmt over
- * wmi is enabled or not.
- * @value: 1 for enabled/ 0 for disable
- *
- * Return: None
- */
- void ol_tx_set_is_mgmt_over_wmi_enabled(uint8_t value)
- {
- struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- if (!pdev) {
- cdf_print("%s: pdev is NULL\n", __func__);
- return;
- }
- pdev->is_mgmt_over_wmi_enabled = value;
- return;
- }
- /**
- * ol_tx_get_is_mgmt_over_wmi_enabled() - get value of is_mgmt_over_wmi_enabled
- *
- * Return: is_mgmt_over_wmi_enabled
- */
- uint8_t ol_tx_get_is_mgmt_over_wmi_enabled(void)
- {
- struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- if (!pdev) {
- cdf_print("%s: pdev is NULL\n", __func__);
- return 0;
- }
- return pdev->is_mgmt_over_wmi_enabled;
- }
- #ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID
- ol_txrx_peer_handle
- ol_txrx_find_peer_by_addr_and_vdev(ol_txrx_pdev_handle pdev,
- ol_txrx_vdev_handle vdev,
- uint8_t *peer_addr, uint8_t *peer_id)
- {
- struct ol_txrx_peer_t *peer;
- peer = ol_txrx_peer_vdev_find_hash(pdev, vdev, peer_addr, 0, 1);
- if (!peer)
- return NULL;
- *peer_id = peer->local_id;
- cdf_atomic_dec(&peer->ref_cnt);
- return peer;
- }
- CDF_STATUS ol_txrx_get_vdevid(struct ol_txrx_peer_t *peer, uint8_t *vdev_id)
- {
- if (!peer) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "peer argument is null!!");
- return CDF_STATUS_E_FAILURE;
- }
- *vdev_id = peer->vdev->vdev_id;
- return CDF_STATUS_SUCCESS;
- }
- void *ol_txrx_get_vdev_by_sta_id(uint8_t sta_id)
- {
- struct ol_txrx_peer_t *peer = NULL;
- ol_txrx_pdev_handle pdev = NULL;
- if (sta_id >= WLAN_MAX_STA_COUNT) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "Invalid sta id passed");
- return NULL;
- }
- pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- if (!pdev) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "PDEV not found for sta_id [%d]", sta_id);
- return NULL;
- }
- peer = ol_txrx_peer_find_by_local_id(pdev, sta_id);
- if (!peer) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "PEER [%d] not found", sta_id);
- return NULL;
- }
- return peer->vdev;
- }
- ol_txrx_peer_handle ol_txrx_find_peer_by_addr(ol_txrx_pdev_handle pdev,
- uint8_t *peer_addr,
- uint8_t *peer_id)
- {
- struct ol_txrx_peer_t *peer;
- peer = ol_txrx_peer_find_hash_find(pdev, peer_addr, 0, 1);
- if (!peer)
- return NULL;
- *peer_id = peer->local_id;
- cdf_atomic_dec(&peer->ref_cnt);
- return peer;
- }
- uint16_t ol_txrx_local_peer_id(ol_txrx_peer_handle peer)
- {
- return peer->local_id;
- }
- ol_txrx_peer_handle
- ol_txrx_peer_find_by_local_id(struct ol_txrx_pdev_t *pdev,
- uint8_t local_peer_id)
- {
- struct ol_txrx_peer_t *peer;
- if ((local_peer_id == OL_TXRX_INVALID_LOCAL_PEER_ID) ||
- (local_peer_id >= OL_TXRX_NUM_LOCAL_PEER_IDS)) {
- return NULL;
- }
- cdf_spin_lock_bh(&pdev->local_peer_ids.lock);
- peer = pdev->local_peer_ids.map[local_peer_id];
- cdf_spin_unlock_bh(&pdev->local_peer_ids.lock);
- return peer;
- }
- static void ol_txrx_local_peer_id_pool_init(struct ol_txrx_pdev_t *pdev)
- {
- int i;
- /* point the freelist to the first ID */
- pdev->local_peer_ids.freelist = 0;
- /* link each ID to the next one */
- for (i = 0; i < OL_TXRX_NUM_LOCAL_PEER_IDS; i++) {
- pdev->local_peer_ids.pool[i] = i + 1;
- pdev->local_peer_ids.map[i] = NULL;
- }
- /* link the last ID to itself, to mark the end of the list */
- i = OL_TXRX_NUM_LOCAL_PEER_IDS;
- pdev->local_peer_ids.pool[i] = i;
- cdf_spinlock_init(&pdev->local_peer_ids.lock);
- }
- static void
- ol_txrx_local_peer_id_alloc(struct ol_txrx_pdev_t *pdev,
- struct ol_txrx_peer_t *peer)
- {
- int i;
- cdf_spin_lock_bh(&pdev->local_peer_ids.lock);
- i = pdev->local_peer_ids.freelist;
- if (pdev->local_peer_ids.pool[i] == i) {
- /* the list is empty, except for the list-end marker */
- peer->local_id = OL_TXRX_INVALID_LOCAL_PEER_ID;
- } else {
- /* take the head ID and advance the freelist */
- peer->local_id = i;
- pdev->local_peer_ids.freelist = pdev->local_peer_ids.pool[i];
- pdev->local_peer_ids.map[i] = peer;
- }
- cdf_spin_unlock_bh(&pdev->local_peer_ids.lock);
- }
- static void
- ol_txrx_local_peer_id_free(struct ol_txrx_pdev_t *pdev,
- struct ol_txrx_peer_t *peer)
- {
- int i = peer->local_id;
- if ((i == OL_TXRX_INVALID_LOCAL_PEER_ID) ||
- (i >= OL_TXRX_NUM_LOCAL_PEER_IDS)) {
- return;
- }
- /* put this ID on the head of the freelist */
- cdf_spin_lock_bh(&pdev->local_peer_ids.lock);
- pdev->local_peer_ids.pool[i] = pdev->local_peer_ids.freelist;
- pdev->local_peer_ids.freelist = i;
- pdev->local_peer_ids.map[i] = NULL;
- cdf_spin_unlock_bh(&pdev->local_peer_ids.lock);
- }
- static void ol_txrx_local_peer_id_cleanup(struct ol_txrx_pdev_t *pdev)
- {
- cdf_spinlock_destroy(&pdev->local_peer_ids.lock);
- }
- #else
- #define ol_txrx_local_peer_id_pool_init(pdev) /* no-op */
- #define ol_txrx_local_peer_id_alloc(pdev, peer) /* no-op */
- #define ol_txrx_local_peer_id_free(pdev, peer) /* no-op */
- #define ol_txrx_local_peer_id_cleanup(pdev) /* no-op */
- #endif
- #ifdef WLAN_FEATURE_FASTPATH
- /**
- * setup_fastpath_ce_handles() Update pdev with ce_handle for fastpath use.
- *
- * @osc: pointer to HIF context
- * @pdev: pointer to ol pdev
- *
- * Return: void
- */
- static inline void
- setup_fastpath_ce_handles(struct ol_softc *osc, struct ol_txrx_pdev_t *pdev)
- {
- /*
- * Before the HTT attach, set up the CE handles
- * CE handles are (struct CE_state *)
- * This is only required in the fast path
- */
- pdev->ce_tx_hdl = (struct CE_handle *)
- osc->ce_id_to_state[CE_HTT_H2T_MSG];
- }
- #else /* not WLAN_FEATURE_FASTPATH */
- static inline void
- setup_fastpath_ce_handles(struct ol_softc *osc, struct ol_txrx_pdev_t *pdev)
- {
- }
- #endif /* WLAN_FEATURE_FASTPATH */
- #ifdef QCA_LL_TX_FLOW_CONTROL_V2
- /**
- * ol_tx_set_desc_global_pool_size() - set global pool size
- * @num_msdu_desc: total number of descriptors
- *
- * Return: none
- */
- void ol_tx_set_desc_global_pool_size(uint32_t num_msdu_desc)
- {
- struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- if (!pdev) {
- cdf_print("%s: pdev is NULL\n", __func__);
- return;
- }
- pdev->num_msdu_desc = num_msdu_desc;
- if (!ol_tx_get_is_mgmt_over_wmi_enabled())
- pdev->num_msdu_desc += TX_FLOW_MGMT_POOL_SIZE;
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Global pool size: %d\n",
- pdev->num_msdu_desc);
- return;
- }
- /**
- * ol_tx_get_desc_global_pool_size() - get global pool size
- * @pdev: pdev handle
- *
- * Return: global pool size
- */
- static inline
- uint32_t ol_tx_get_desc_global_pool_size(struct ol_txrx_pdev_t *pdev)
- {
- return pdev->num_msdu_desc;
- }
- /**
- * ol_tx_get_total_free_desc() - get total free descriptors
- * @pdev: pdev handle
- *
- * Return: total free descriptors
- */
- static inline
- uint32_t ol_tx_get_total_free_desc(struct ol_txrx_pdev_t *pdev)
- {
- struct ol_tx_flow_pool_t *pool = NULL;
- uint32_t free_desc;
- free_desc = pdev->tx_desc.num_free;
- cdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock);
- TAILQ_FOREACH(pool, &pdev->tx_desc.flow_pool_list,
- flow_pool_list_elem) {
- cdf_spin_lock_bh(&pool->flow_pool_lock);
- free_desc += pool->avail_desc;
- cdf_spin_unlock_bh(&pool->flow_pool_lock);
- }
- cdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock);
- return free_desc;
- }
- #else
- /**
- * ol_tx_get_desc_global_pool_size() - get global pool size
- * @pdev: pdev handle
- *
- * Return: global pool size
- */
- static inline
- uint32_t ol_tx_get_desc_global_pool_size(struct ol_txrx_pdev_t *pdev)
- {
- return ol_cfg_target_tx_credit(pdev->ctrl_pdev);
- }
- /**
- * ol_tx_get_total_free_desc() - get total free descriptors
- * @pdev: pdev handle
- *
- * Return: total free descriptors
- */
- static inline
- uint32_t ol_tx_get_total_free_desc(struct ol_txrx_pdev_t *pdev)
- {
- return pdev->tx_desc.num_free;
- }
- #endif
- /**
- * ol_txrx_pdev_alloc() - allocate txrx pdev
- * @ctrl_pdev: cfg pdev
- * @htc_pdev: HTC pdev
- * @osdev: os dev
- *
- * Return: txrx pdev handle
- * NULL for failure
- */
- ol_txrx_pdev_handle
- ol_txrx_pdev_alloc(ol_pdev_handle ctrl_pdev,
- HTC_HANDLE htc_pdev, cdf_device_t osdev)
- {
- struct ol_txrx_pdev_t *pdev;
- int i;
- pdev = cdf_mem_malloc(sizeof(*pdev));
- if (!pdev)
- goto fail0;
- cdf_mem_zero(pdev, sizeof(*pdev));
- pdev->cfg.default_tx_comp_req = !ol_cfg_tx_free_at_download(ctrl_pdev);
- /* store provided params */
- pdev->ctrl_pdev = ctrl_pdev;
- pdev->osdev = osdev;
- for (i = 0; i < htt_num_sec_types; i++)
- pdev->sec_types[i] = (enum ol_sec_type)i;
- TXRX_STATS_INIT(pdev);
- TAILQ_INIT(&pdev->vdev_list);
- /* do initial set up of the peer ID -> peer object lookup map */
- if (ol_txrx_peer_find_attach(pdev))
- goto fail1;
- pdev->htt_pdev =
- htt_pdev_alloc(pdev, ctrl_pdev, htc_pdev, osdev);
- if (!pdev->htt_pdev)
- goto fail2;
- return pdev;
- fail2:
- ol_txrx_peer_find_detach(pdev);
- fail1:
- cdf_mem_free(pdev);
- fail0:
- return NULL;
- }
- /**
- * ol_txrx_pdev_attach() - attach txrx pdev
- * @pdev: txrx pdev
- *
- * Return: 0 for success
- */
- int
- ol_txrx_pdev_attach(ol_txrx_pdev_handle pdev)
- {
- uint16_t i;
- uint16_t fail_idx = 0;
- int ret = 0;
- uint16_t desc_pool_size;
- struct ol_softc *osc = cds_get_context(CDF_MODULE_ID_HIF);
- uint16_t desc_element_size = sizeof(union ol_tx_desc_list_elem_t);
- union ol_tx_desc_list_elem_t *c_element;
- unsigned int sig_bit;
- uint16_t desc_per_page;
- if (!osc) {
- ret = -EINVAL;
- goto ol_attach_fail;
- }
- /*
- * For LL, limit the number of host's tx descriptors to match
- * the number of target FW tx descriptors.
- * This simplifies the FW, by ensuring the host will never
- * download more tx descriptors than the target has space for.
- * The FW will drop/free low-priority tx descriptors when it
- * starts to run low, so that in theory the host should never
- * run out of tx descriptors.
- */
- /* initialize the counter of the target's tx buffer availability */
- cdf_atomic_init(&pdev->target_tx_credit);
- cdf_atomic_init(&pdev->orig_target_tx_credit);
- /*
- * LL - initialize the target credit outselves.
- * HL - wait for a HTT target credit initialization during htt_attach.
- */
- cdf_atomic_add(ol_cfg_target_tx_credit(pdev->ctrl_pdev),
- &pdev->target_tx_credit);
- desc_pool_size = ol_tx_get_desc_global_pool_size(pdev);
- setup_fastpath_ce_handles(osc, pdev);
- ret = htt_attach(pdev->htt_pdev, desc_pool_size);
- if (ret)
- goto ol_attach_fail;
- /* Update CE's pkt download length */
- ce_pkt_dl_len_set((void *)osc, htt_pkt_dl_len_get(pdev->htt_pdev));
- /* Attach micro controller data path offload resource */
- if (ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev))
- if (htt_ipa_uc_attach(pdev->htt_pdev))
- goto uc_attach_fail;
- /* Calculate single element reserved size power of 2 */
- pdev->tx_desc.desc_reserved_size = cdf_get_pwr2(desc_element_size);
- cdf_mem_multi_pages_alloc(pdev->osdev, &pdev->tx_desc.desc_pages,
- pdev->tx_desc.desc_reserved_size, desc_pool_size, 0, true);
- if ((0 == pdev->tx_desc.desc_pages.num_pages) ||
- (NULL == pdev->tx_desc.desc_pages.cacheable_pages)) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "Page alloc fail");
- goto page_alloc_fail;
- }
- desc_per_page = pdev->tx_desc.desc_pages.num_element_per_page;
- pdev->tx_desc.offset_filter = desc_per_page - 1;
- /* Calculate page divider to find page number */
- sig_bit = 0;
- while (desc_per_page) {
- sig_bit++;
- desc_per_page = desc_per_page >> 1;
- }
- pdev->tx_desc.page_divider = (sig_bit - 1);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "page_divider 0x%x, offset_filter 0x%x num elem %d, ol desc num page %d, ol desc per page %d",
- pdev->tx_desc.page_divider, pdev->tx_desc.offset_filter,
- desc_pool_size, pdev->tx_desc.desc_pages.num_pages,
- pdev->tx_desc.desc_pages.num_element_per_page);
- /*
- * Each SW tx desc (used only within the tx datapath SW) has a
- * matching HTT tx desc (used for downloading tx meta-data to FW/HW).
- * Go ahead and allocate the HTT tx desc and link it with the SW tx
- * desc now, to avoid doing it during time-critical transmit.
- */
- pdev->tx_desc.pool_size = desc_pool_size;
- pdev->tx_desc.freelist =
- (union ol_tx_desc_list_elem_t *)
- (*pdev->tx_desc.desc_pages.cacheable_pages);
- c_element = pdev->tx_desc.freelist;
- for (i = 0; i < desc_pool_size; i++) {
- void *htt_tx_desc;
- void *htt_frag_desc = NULL;
- uint32_t frag_paddr_lo = 0;
- uint32_t paddr_lo;
- if (i == (desc_pool_size - 1))
- c_element->next = NULL;
- else
- c_element->next = (union ol_tx_desc_list_elem_t *)
- ol_tx_desc_find(pdev, i + 1);
- htt_tx_desc = htt_tx_desc_alloc(pdev->htt_pdev, &paddr_lo, i);
- if (!htt_tx_desc) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_FATAL,
- "%s: failed to alloc HTT tx desc (%d of %d)",
- __func__, i, desc_pool_size);
- fail_idx = i;
- goto desc_alloc_fail;
- }
- c_element->tx_desc.htt_tx_desc = htt_tx_desc;
- c_element->tx_desc.htt_tx_desc_paddr = paddr_lo;
- ret = htt_tx_frag_alloc(pdev->htt_pdev,
- i, &frag_paddr_lo, &htt_frag_desc);
- if (ret) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: failed to alloc HTT frag dsc (%d/%d)",
- __func__, i, desc_pool_size);
- /* Is there a leak here, is this handling correct? */
- fail_idx = i;
- goto desc_alloc_fail;
- }
- if (!ret && htt_frag_desc) {
- /* Initialize the first 6 words (TSO flags)
- of the frag descriptor */
- memset(htt_frag_desc, 0, 6 * sizeof(uint32_t));
- c_element->tx_desc.htt_frag_desc = htt_frag_desc;
- c_element->tx_desc.htt_frag_desc_paddr = frag_paddr_lo;
- }
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW,
- "%s:%d - %d FRAG VA 0x%p FRAG PA 0x%x",
- __func__, __LINE__, i,
- c_element->tx_desc.htt_frag_desc,
- c_element->tx_desc.htt_frag_desc_paddr);
- #ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS
- c_element->tx_desc.pkt_type = 0xff;
- #ifdef QCA_COMPUTE_TX_DELAY
- c_element->tx_desc.entry_timestamp_ticks =
- 0xffffffff;
- #endif
- #endif
- c_element->tx_desc.id = i;
- cdf_atomic_init(&c_element->tx_desc.ref_cnt);
- c_element = c_element->next;
- fail_idx = i;
- }
- /* link SW tx descs into a freelist */
- pdev->tx_desc.num_free = desc_pool_size;
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1,
- "%s first tx_desc:0x%p Last tx desc:0x%p\n", __func__,
- (uint32_t *) pdev->tx_desc.freelist,
- (uint32_t *) (pdev->tx_desc.freelist + desc_pool_size));
- /* check what format of frames are expected to be delivered by the OS */
- pdev->frame_format = ol_cfg_frame_type(pdev->ctrl_pdev);
- if (pdev->frame_format == wlan_frm_fmt_native_wifi)
- pdev->htt_pkt_type = htt_pkt_type_native_wifi;
- else if (pdev->frame_format == wlan_frm_fmt_802_3) {
- if (ol_cfg_is_ce_classify_enabled(pdev->ctrl_pdev))
- pdev->htt_pkt_type = htt_pkt_type_eth2;
- else
- pdev->htt_pkt_type = htt_pkt_type_ethernet;
- } else {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s Invalid standard frame type: %d",
- __func__, pdev->frame_format);
- goto control_init_fail;
- }
- /* setup the global rx defrag waitlist */
- TAILQ_INIT(&pdev->rx.defrag.waitlist);
- /* configure where defrag timeout and duplicate detection is handled */
- pdev->rx.flags.defrag_timeout_check =
- pdev->rx.flags.dup_check =
- ol_cfg_rx_host_defrag_timeout_duplicate_check(pdev->ctrl_pdev);
- #ifdef QCA_SUPPORT_SW_TXRX_ENCAP
- /* Need to revisit this part. Currently,hardcode to riva's caps */
- pdev->target_tx_tran_caps = wlan_frm_tran_cap_raw;
- pdev->target_rx_tran_caps = wlan_frm_tran_cap_raw;
- /*
- * The Riva HW de-aggregate doesn't have capability to generate 802.11
- * header for non-first subframe of A-MSDU.
- */
- pdev->sw_subfrm_hdr_recovery_enable = 1;
- /*
- * The Riva HW doesn't have the capability to set Protected Frame bit
- * in the MAC header for encrypted data frame.
- */
- pdev->sw_pf_proc_enable = 1;
- if (pdev->frame_format == wlan_frm_fmt_802_3) {
- /* sw llc process is only needed in
- 802.3 to 802.11 transform case */
- pdev->sw_tx_llc_proc_enable = 1;
- pdev->sw_rx_llc_proc_enable = 1;
- } else {
- pdev->sw_tx_llc_proc_enable = 0;
- pdev->sw_rx_llc_proc_enable = 0;
- }
- switch (pdev->frame_format) {
- case wlan_frm_fmt_raw:
- pdev->sw_tx_encap =
- pdev->target_tx_tran_caps & wlan_frm_tran_cap_raw
- ? 0 : 1;
- pdev->sw_rx_decap =
- pdev->target_rx_tran_caps & wlan_frm_tran_cap_raw
- ? 0 : 1;
- break;
- case wlan_frm_fmt_native_wifi:
- pdev->sw_tx_encap =
- pdev->
- target_tx_tran_caps & wlan_frm_tran_cap_native_wifi
- ? 0 : 1;
- pdev->sw_rx_decap =
- pdev->
- target_rx_tran_caps & wlan_frm_tran_cap_native_wifi
- ? 0 : 1;
- break;
- case wlan_frm_fmt_802_3:
- pdev->sw_tx_encap =
- pdev->target_tx_tran_caps & wlan_frm_tran_cap_8023
- ? 0 : 1;
- pdev->sw_rx_decap =
- pdev->target_rx_tran_caps & wlan_frm_tran_cap_8023
- ? 0 : 1;
- break;
- default:
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "Invalid std frame type; [en/de]cap: f:%x t:%x r:%x",
- pdev->frame_format,
- pdev->target_tx_tran_caps, pdev->target_rx_tran_caps);
- goto control_init_fail;
- }
- #endif
- /*
- * Determine what rx processing steps are done within the host.
- * Possibilities:
- * 1. Nothing - rx->tx forwarding and rx PN entirely within target.
- * (This is unlikely; even if the target is doing rx->tx forwarding,
- * the host should be doing rx->tx forwarding too, as a back up for
- * the target's rx->tx forwarding, in case the target runs short on
- * memory, and can't store rx->tx frames that are waiting for
- * missing prior rx frames to arrive.)
- * 2. Just rx -> tx forwarding.
- * This is the typical configuration for HL, and a likely
- * configuration for LL STA or small APs (e.g. retail APs).
- * 3. Both PN check and rx -> tx forwarding.
- * This is the typical configuration for large LL APs.
- * Host-side PN check without rx->tx forwarding is not a valid
- * configuration, since the PN check needs to be done prior to
- * the rx->tx forwarding.
- */
- if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) {
- /* PN check, rx-tx forwarding and rx reorder is done by
- the target */
- if (ol_cfg_rx_fwd_disabled(pdev->ctrl_pdev))
- pdev->rx_opt_proc = ol_rx_in_order_deliver;
- else
- pdev->rx_opt_proc = ol_rx_fwd_check;
- } else {
- if (ol_cfg_rx_pn_check(pdev->ctrl_pdev)) {
- if (ol_cfg_rx_fwd_disabled(pdev->ctrl_pdev)) {
- /*
- * PN check done on host,
- * rx->tx forwarding not done at all.
- */
- pdev->rx_opt_proc = ol_rx_pn_check_only;
- } else if (ol_cfg_rx_fwd_check(pdev->ctrl_pdev)) {
- /*
- * Both PN check and rx->tx forwarding done
- * on host.
- */
- pdev->rx_opt_proc = ol_rx_pn_check;
- } else {
- #define TRACESTR01 "invalid config: if rx PN check is on the host,"\
- "rx->tx forwarding check needs to also be on the host"
- CDF_TRACE(CDF_MODULE_ID_TXRX,
- CDF_TRACE_LEVEL_ERROR,
- "%s: %s", __func__, TRACESTR01);
- #undef TRACESTR01
- goto control_init_fail;
- }
- } else {
- /* PN check done on target */
- if ((!ol_cfg_rx_fwd_disabled(pdev->ctrl_pdev)) &&
- ol_cfg_rx_fwd_check(pdev->ctrl_pdev)) {
- /*
- * rx->tx forwarding done on host (possibly as
- * back-up for target-side primary rx->tx
- * forwarding)
- */
- pdev->rx_opt_proc = ol_rx_fwd_check;
- } else {
- /* rx->tx forwarding either done in target,
- * or not done at all */
- pdev->rx_opt_proc = ol_rx_deliver;
- }
- }
- }
- /* initialize mutexes for tx desc alloc and peer lookup */
- cdf_spinlock_init(&pdev->tx_mutex);
- cdf_spinlock_init(&pdev->peer_ref_mutex);
- cdf_spinlock_init(&pdev->rx.mutex);
- cdf_spinlock_init(&pdev->last_real_peer_mutex);
- OL_TXRX_PEER_STATS_MUTEX_INIT(pdev);
- if (OL_RX_REORDER_TRACE_ATTACH(pdev) != A_OK)
- goto reorder_trace_attach_fail;
- if (OL_RX_PN_TRACE_ATTACH(pdev) != A_OK)
- goto pn_trace_attach_fail;
- #ifdef PERE_IP_HDR_ALIGNMENT_WAR
- pdev->host_80211_enable = ol_scn_host_80211_enable_get(pdev->ctrl_pdev);
- #endif
- /*
- * WDI event attach
- */
- wdi_event_attach(pdev);
- /*
- * Initialize rx PN check characteristics for different security types.
- */
- cdf_mem_set(&pdev->rx_pn[0], sizeof(pdev->rx_pn), 0);
- /* TKIP: 48-bit TSC, CCMP: 48-bit PN */
- pdev->rx_pn[htt_sec_type_tkip].len =
- pdev->rx_pn[htt_sec_type_tkip_nomic].len =
- pdev->rx_pn[htt_sec_type_aes_ccmp].len = 48;
- pdev->rx_pn[htt_sec_type_tkip].cmp =
- pdev->rx_pn[htt_sec_type_tkip_nomic].cmp =
- pdev->rx_pn[htt_sec_type_aes_ccmp].cmp = ol_rx_pn_cmp48;
- /* WAPI: 128-bit PN */
- pdev->rx_pn[htt_sec_type_wapi].len = 128;
- pdev->rx_pn[htt_sec_type_wapi].cmp = ol_rx_pn_wapi_cmp;
- OL_RX_REORDER_TIMEOUT_INIT(pdev);
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, "Created pdev %p\n", pdev);
- pdev->cfg.host_addba = ol_cfg_host_addba(pdev->ctrl_pdev);
- #ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI
- #define OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT 3
- /* #if 1 -- TODO: clean this up */
- #define OL_TXRX_RSSI_NEW_WEIGHT_DEFAULT \
- /* avg = 100% * new + 0% * old */ \
- (1 << OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT)
- /*
- #else
- #define OL_TXRX_RSSI_NEW_WEIGHT_DEFAULT
- //avg = 25% * new + 25% * old
- (1 << (OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT-2))
- #endif
- */
- pdev->rssi_update_shift = OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT;
- pdev->rssi_new_weight = OL_TXRX_RSSI_NEW_WEIGHT_DEFAULT;
- #endif
- ol_txrx_local_peer_id_pool_init(pdev);
- pdev->cfg.ll_pause_txq_limit =
- ol_tx_cfg_max_tx_queue_depth_ll(pdev->ctrl_pdev);
- #ifdef QCA_COMPUTE_TX_DELAY
- cdf_mem_zero(&pdev->tx_delay, sizeof(pdev->tx_delay));
- cdf_spinlock_init(&pdev->tx_delay.mutex);
- /* initialize compute interval with 5 seconds (ESE default) */
- pdev->tx_delay.avg_period_ticks = cdf_system_msecs_to_ticks(5000);
- {
- uint32_t bin_width_1000ticks;
- bin_width_1000ticks =
- cdf_system_msecs_to_ticks
- (QCA_TX_DELAY_HIST_INTERNAL_BIN_WIDTH_MS
- * 1000);
- /*
- * Compute a factor and shift that together are equal to the
- * inverse of the bin_width time, so that rather than dividing
- * by the bin width time, approximately the same result can be
- * obtained much more efficiently by a multiply + shift.
- * multiply_factor >> shift = 1 / bin_width_time, so
- * multiply_factor = (1 << shift) / bin_width_time.
- *
- * Pick the shift semi-arbitrarily.
- * If we knew statically what the bin_width would be, we could
- * choose a shift that minimizes the error.
- * Since the bin_width is determined dynamically, simply use a
- * shift that is about half of the uint32_t size. This should
- * result in a relatively large multiplier value, which
- * minimizes error from rounding the multiplier to an integer.
- * The rounding error only becomes significant if the tick units
- * are on the order of 1 microsecond. In most systems, it is
- * expected that the tick units will be relatively low-res,
- * on the order of 1 millisecond. In such systems the rounding
- * error is negligible.
- * It would be more accurate to dynamically try out different
- * shifts and choose the one that results in the smallest
- * rounding error, but that extra level of fidelity is
- * not needed.
- */
- pdev->tx_delay.hist_internal_bin_width_shift = 16;
- pdev->tx_delay.hist_internal_bin_width_mult =
- ((1 << pdev->tx_delay.hist_internal_bin_width_shift) *
- 1000 + (bin_width_1000ticks >> 1)) /
- bin_width_1000ticks;
- }
- #endif /* QCA_COMPUTE_TX_DELAY */
- /* Thermal Mitigation */
- ol_tx_throttle_init(pdev);
- ol_tso_seg_list_init(pdev, desc_pool_size);
- ol_tx_register_flow_control(pdev);
- return 0; /* success */
- pn_trace_attach_fail:
- OL_RX_REORDER_TRACE_DETACH(pdev);
- reorder_trace_attach_fail:
- cdf_spinlock_destroy(&pdev->tx_mutex);
- cdf_spinlock_destroy(&pdev->peer_ref_mutex);
- cdf_spinlock_destroy(&pdev->rx.mutex);
- cdf_spinlock_destroy(&pdev->last_real_peer_mutex);
- OL_TXRX_PEER_STATS_MUTEX_DESTROY(pdev);
- control_init_fail:
- desc_alloc_fail:
- for (i = 0; i < fail_idx; i++)
- htt_tx_desc_free(pdev->htt_pdev,
- (ol_tx_desc_find(pdev, i))->htt_tx_desc);
- cdf_mem_multi_pages_free(pdev->osdev,
- &pdev->tx_desc.desc_pages, 0, true);
- page_alloc_fail:
- if (ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev))
- htt_ipa_uc_detach(pdev->htt_pdev);
- uc_attach_fail:
- htt_detach(pdev->htt_pdev);
- ol_attach_fail:
- return ret; /* fail */
- }
- A_STATUS ol_txrx_pdev_attach_target(ol_txrx_pdev_handle pdev)
- {
- return htt_attach_target(pdev->htt_pdev);
- }
- void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev, int force)
- {
- int i;
- /*checking to ensure txrx pdev structure is not NULL */
- if (!pdev) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "NULL pdev passed to %s\n", __func__);
- return;
- }
- /* preconditions */
- TXRX_ASSERT2(pdev);
- /* check that the pdev has no vdevs allocated */
- TXRX_ASSERT1(TAILQ_EMPTY(&pdev->vdev_list));
- OL_RX_REORDER_TIMEOUT_CLEANUP(pdev);
- #ifdef QCA_SUPPORT_TX_THROTTLE
- /* Thermal Mitigation */
- cdf_softirq_timer_cancel(&pdev->tx_throttle.phase_timer);
- cdf_softirq_timer_free(&pdev->tx_throttle.phase_timer);
- #ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
- cdf_softirq_timer_cancel(&pdev->tx_throttle.tx_timer);
- cdf_softirq_timer_free(&pdev->tx_throttle.tx_timer);
- #endif
- #endif
- ol_tso_seg_list_deinit(pdev);
- ol_tx_deregister_flow_control(pdev);
- if (force) {
- /*
- * The assertion above confirms that all vdevs within this pdev
- * were detached. However, they may not have actually been
- * deleted.
- * If the vdev had peers which never received a PEER_UNMAP msg
- * from the target, then there are still zombie peer objects,
- * and the vdev parents of the zombie peers are also zombies,
- * hanging around until their final peer gets deleted.
- * Go through the peer hash table and delete any peers left.
- * As a side effect, this will complete the deletion of any
- * vdevs that are waiting for their peers to finish deletion.
- */
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, "Force delete for pdev %p\n",
- pdev);
- ol_txrx_peer_find_hash_erase(pdev);
- }
- /* Stop the communication between HTT and target at first */
- htt_detach_target(pdev->htt_pdev);
- for (i = 0; i < pdev->tx_desc.pool_size; i++) {
- void *htt_tx_desc;
- struct ol_tx_desc_t *tx_desc;
- tx_desc = ol_tx_desc_find(pdev, i);
- /*
- * Confirm that each tx descriptor is "empty", i.e. it has
- * no tx frame attached.
- * In particular, check that there are no frames that have
- * been given to the target to transmit, for which the
- * target has never provided a response.
- */
- if (cdf_atomic_read(&tx_desc->ref_cnt)) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_WARN,
- "Warning: freeing tx frame (no compltn)\n");
- ol_tx_desc_frame_free_nonstd(pdev,
- tx_desc, 1);
- }
- htt_tx_desc = tx_desc->htt_tx_desc;
- htt_tx_desc_free(pdev->htt_pdev, htt_tx_desc);
- }
- cdf_mem_multi_pages_free(pdev->osdev,
- &pdev->tx_desc.desc_pages, 0, true);
- pdev->tx_desc.freelist = NULL;
- /* Detach micro controller data path offload resource */
- if (ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev))
- htt_ipa_uc_detach(pdev->htt_pdev);
- htt_detach(pdev->htt_pdev);
- htt_pdev_free(pdev->htt_pdev);
- ol_txrx_peer_find_detach(pdev);
- cdf_spinlock_destroy(&pdev->tx_mutex);
- cdf_spinlock_destroy(&pdev->peer_ref_mutex);
- cdf_spinlock_destroy(&pdev->last_real_peer_mutex);
- cdf_spinlock_destroy(&pdev->rx.mutex);
- #ifdef QCA_SUPPORT_TX_THROTTLE
- /* Thermal Mitigation */
- cdf_spinlock_destroy(&pdev->tx_throttle.mutex);
- #endif
- OL_TXRX_PEER_STATS_MUTEX_DESTROY(pdev);
- OL_RX_REORDER_TRACE_DETACH(pdev);
- OL_RX_PN_TRACE_DETACH(pdev);
- /*
- * WDI event detach
- */
- wdi_event_detach(pdev);
- ol_txrx_local_peer_id_cleanup(pdev);
- #ifdef QCA_COMPUTE_TX_DELAY
- cdf_spinlock_destroy(&pdev->tx_delay.mutex);
- #endif
- }
- ol_txrx_vdev_handle
- ol_txrx_vdev_attach(ol_txrx_pdev_handle pdev,
- uint8_t *vdev_mac_addr,
- uint8_t vdev_id, enum wlan_op_mode op_mode)
- {
- struct ol_txrx_vdev_t *vdev;
- /* preconditions */
- TXRX_ASSERT2(pdev);
- TXRX_ASSERT2(vdev_mac_addr);
- vdev = cdf_mem_malloc(sizeof(*vdev));
- if (!vdev)
- return NULL; /* failure */
- /* store provided params */
- vdev->pdev = pdev;
- vdev->vdev_id = vdev_id;
- vdev->opmode = op_mode;
- vdev->delete.pending = 0;
- vdev->safemode = 0;
- vdev->drop_unenc = 1;
- vdev->num_filters = 0;
- cdf_mem_copy(&vdev->mac_addr.raw[0], vdev_mac_addr,
- OL_TXRX_MAC_ADDR_LEN);
- TAILQ_INIT(&vdev->peer_list);
- vdev->last_real_peer = NULL;
- #ifdef QCA_IBSS_SUPPORT
- vdev->ibss_peer_num = 0;
- vdev->ibss_peer_heart_beat_timer = 0;
- #endif
- cdf_spinlock_init(&vdev->ll_pause.mutex);
- vdev->ll_pause.paused_reason = 0;
- vdev->ll_pause.txq.head = vdev->ll_pause.txq.tail = NULL;
- vdev->ll_pause.txq.depth = 0;
- cdf_softirq_timer_init(pdev->osdev,
- &vdev->ll_pause.timer,
- ol_tx_vdev_ll_pause_queue_send, vdev,
- CDF_TIMER_TYPE_SW);
- cdf_atomic_init(&vdev->os_q_paused);
- cdf_atomic_set(&vdev->os_q_paused, 0);
- vdev->tx_fl_lwm = 0;
- vdev->tx_fl_hwm = 0;
- vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID;
- cdf_spinlock_init(&vdev->flow_control_lock);
- vdev->osif_flow_control_cb = NULL;
- vdev->osif_fc_ctx = NULL;
- /* Default MAX Q depth for every VDEV */
- vdev->ll_pause.max_q_depth =
- ol_tx_cfg_max_tx_queue_depth_ll(vdev->pdev->ctrl_pdev);
- /* add this vdev into the pdev's list */
- TAILQ_INSERT_TAIL(&pdev->vdev_list, vdev, vdev_list_elem);
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1,
- "Created vdev %p (%02x:%02x:%02x:%02x:%02x:%02x)\n",
- vdev,
- vdev->mac_addr.raw[0], vdev->mac_addr.raw[1],
- vdev->mac_addr.raw[2], vdev->mac_addr.raw[3],
- vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]);
- /*
- * We've verified that htt_op_mode == wlan_op_mode,
- * so no translation is needed.
- */
- htt_vdev_attach(pdev->htt_pdev, vdev_id, op_mode);
- return vdev;
- }
- void ol_txrx_osif_vdev_register(ol_txrx_vdev_handle vdev,
- void *osif_vdev,
- struct ol_txrx_osif_ops *txrx_ops)
- {
- vdev->osif_dev = osif_vdev;
- txrx_ops->tx.std = vdev->tx = OL_TX_LL;
- txrx_ops->tx.non_std = ol_tx_non_std_ll;
- }
- void ol_txrx_set_curchan(ol_txrx_pdev_handle pdev, uint32_t chan_mhz)
- {
- return;
- }
- void ol_txrx_set_safemode(ol_txrx_vdev_handle vdev, uint32_t val)
- {
- vdev->safemode = val;
- }
- void
- ol_txrx_set_privacy_filters(ol_txrx_vdev_handle vdev,
- void *filters, uint32_t num)
- {
- cdf_mem_copy(vdev->privacy_filters, filters,
- num * sizeof(struct privacy_exemption));
- vdev->num_filters = num;
- }
- void ol_txrx_set_drop_unenc(ol_txrx_vdev_handle vdev, uint32_t val)
- {
- vdev->drop_unenc = val;
- }
- void
- ol_txrx_vdev_detach(ol_txrx_vdev_handle vdev,
- ol_txrx_vdev_delete_cb callback, void *context)
- {
- struct ol_txrx_pdev_t *pdev = vdev->pdev;
- /* preconditions */
- TXRX_ASSERT2(vdev);
- cdf_spin_lock_bh(&vdev->ll_pause.mutex);
- cdf_softirq_timer_cancel(&vdev->ll_pause.timer);
- cdf_softirq_timer_free(&vdev->ll_pause.timer);
- vdev->ll_pause.is_q_timer_on = false;
- while (vdev->ll_pause.txq.head) {
- cdf_nbuf_t next = cdf_nbuf_next(vdev->ll_pause.txq.head);
- cdf_nbuf_set_next(vdev->ll_pause.txq.head, NULL);
- cdf_nbuf_unmap(pdev->osdev, vdev->ll_pause.txq.head,
- CDF_DMA_TO_DEVICE);
- cdf_nbuf_tx_free(vdev->ll_pause.txq.head, NBUF_PKT_ERROR);
- vdev->ll_pause.txq.head = next;
- }
- cdf_spin_unlock_bh(&vdev->ll_pause.mutex);
- cdf_spinlock_destroy(&vdev->ll_pause.mutex);
- cdf_spin_lock_bh(&vdev->flow_control_lock);
- vdev->osif_flow_control_cb = NULL;
- vdev->osif_fc_ctx = NULL;
- cdf_spin_unlock_bh(&vdev->flow_control_lock);
- cdf_spinlock_destroy(&vdev->flow_control_lock);
- /* remove the vdev from its parent pdev's list */
- TAILQ_REMOVE(&pdev->vdev_list, vdev, vdev_list_elem);
- /*
- * Use peer_ref_mutex while accessing peer_list, in case
- * a peer is in the process of being removed from the list.
- */
- cdf_spin_lock_bh(&pdev->peer_ref_mutex);
- /* check that the vdev has no peers allocated */
- if (!TAILQ_EMPTY(&vdev->peer_list)) {
- /* debug print - will be removed later */
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1,
- "%s: not deleting vdev object %p (%02x:%02x:%02x:%02x:%02x:%02x)"
- "until deletion finishes for all its peers\n",
- __func__, vdev,
- vdev->mac_addr.raw[0], vdev->mac_addr.raw[1],
- vdev->mac_addr.raw[2], vdev->mac_addr.raw[3],
- vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]);
- /* indicate that the vdev needs to be deleted */
- vdev->delete.pending = 1;
- vdev->delete.callback = callback;
- vdev->delete.context = context;
- cdf_spin_unlock_bh(&pdev->peer_ref_mutex);
- return;
- }
- cdf_spin_unlock_bh(&pdev->peer_ref_mutex);
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1,
- "%s: deleting vdev obj %p (%02x:%02x:%02x:%02x:%02x:%02x)\n",
- __func__, vdev,
- vdev->mac_addr.raw[0], vdev->mac_addr.raw[1],
- vdev->mac_addr.raw[2], vdev->mac_addr.raw[3],
- vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]);
- htt_vdev_detach(pdev->htt_pdev, vdev->vdev_id);
- /*
- * Doesn't matter if there are outstanding tx frames -
- * they will be freed once the target sends a tx completion
- * message for them.
- */
- cdf_mem_free(vdev);
- if (callback)
- callback(context);
- }
- /**
- * ol_txrx_flush_rx_frames() - flush cached rx frames
- * @peer: peer
- * @drop: set flag to drop frames
- *
- * Return: None
- */
- void ol_txrx_flush_rx_frames(struct ol_txrx_peer_t *peer,
- bool drop)
- {
- struct ol_rx_cached_buf *cache_buf;
- CDF_STATUS ret;
- ol_rx_callback_fp data_rx = NULL;
- void *cds_ctx = cds_get_global_context();
- if (cdf_atomic_inc_return(&peer->flush_in_progress) > 1) {
- cdf_atomic_dec(&peer->flush_in_progress);
- return;
- }
- cdf_assert(cds_ctx);
- cdf_spin_lock_bh(&peer->peer_info_lock);
- if (peer->state >= ol_txrx_peer_state_conn)
- data_rx = peer->osif_rx;
- else
- drop = true;
- cdf_spin_unlock_bh(&peer->peer_info_lock);
- cdf_spin_lock_bh(&peer->bufq_lock);
- cache_buf = list_entry((&peer->cached_bufq)->next,
- typeof(*cache_buf), list);
- while (!list_empty(&peer->cached_bufq)) {
- list_del(&cache_buf->list);
- cdf_spin_unlock_bh(&peer->bufq_lock);
- if (drop) {
- cdf_nbuf_free(cache_buf->buf);
- } else {
- /* Flush the cached frames to HDD */
- ret = data_rx(cds_ctx, cache_buf->buf, peer->local_id);
- if (ret != CDF_STATUS_SUCCESS)
- cdf_nbuf_free(cache_buf->buf);
- }
- cdf_mem_free(cache_buf);
- cdf_spin_lock_bh(&peer->bufq_lock);
- cache_buf = list_entry((&peer->cached_bufq)->next,
- typeof(*cache_buf), list);
- }
- cdf_spin_unlock_bh(&peer->bufq_lock);
- cdf_atomic_dec(&peer->flush_in_progress);
- }
- ol_txrx_peer_handle
- ol_txrx_peer_attach(ol_txrx_pdev_handle pdev,
- ol_txrx_vdev_handle vdev, uint8_t *peer_mac_addr)
- {
- struct ol_txrx_peer_t *peer;
- struct ol_txrx_peer_t *temp_peer;
- uint8_t i;
- int differs;
- bool wait_on_deletion = false;
- unsigned long rc;
- /* preconditions */
- TXRX_ASSERT2(pdev);
- TXRX_ASSERT2(vdev);
- TXRX_ASSERT2(peer_mac_addr);
- cdf_spin_lock_bh(&pdev->peer_ref_mutex);
- /* check for duplicate exsisting peer */
- TAILQ_FOREACH(temp_peer, &vdev->peer_list, peer_list_elem) {
- if (!ol_txrx_peer_find_mac_addr_cmp(&temp_peer->mac_addr,
- (union ol_txrx_align_mac_addr_t *)peer_mac_addr)) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
- "vdev_id %d (%02x:%02x:%02x:%02x:%02x:%02x) already exsist.\n",
- vdev->vdev_id,
- peer_mac_addr[0], peer_mac_addr[1],
- peer_mac_addr[2], peer_mac_addr[3],
- peer_mac_addr[4], peer_mac_addr[5]);
- if (cdf_atomic_read(&temp_peer->delete_in_progress)) {
- vdev->wait_on_peer_id = temp_peer->local_id;
- cdf_event_init(&vdev->wait_delete_comp);
- wait_on_deletion = true;
- } else {
- cdf_spin_unlock_bh(&pdev->peer_ref_mutex);
- return NULL;
- }
- }
- }
- cdf_spin_unlock_bh(&pdev->peer_ref_mutex);
- if (wait_on_deletion) {
- /* wait for peer deletion */
- rc = cdf_wait_single_event(&vdev->wait_delete_comp,
- cdf_system_msecs_to_ticks(PEER_DELETION_TIMEOUT));
- if (!rc) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
- "timedout waiting for peer(%d) deletion\n",
- vdev->wait_on_peer_id);
- vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID;
- return NULL;
- }
- }
- peer = cdf_mem_malloc(sizeof(*peer));
- if (!peer)
- return NULL; /* failure */
- cdf_mem_zero(peer, sizeof(*peer));
- /* store provided params */
- peer->vdev = vdev;
- cdf_mem_copy(&peer->mac_addr.raw[0], peer_mac_addr,
- OL_TXRX_MAC_ADDR_LEN);
- INIT_LIST_HEAD(&peer->cached_bufq);
- cdf_spin_lock_bh(&pdev->peer_ref_mutex);
- /* add this peer into the vdev's list */
- TAILQ_INSERT_TAIL(&vdev->peer_list, peer, peer_list_elem);
- cdf_spin_unlock_bh(&pdev->peer_ref_mutex);
- /* check whether this is a real peer (peer mac addr != vdev mac addr) */
- if (ol_txrx_peer_find_mac_addr_cmp(&vdev->mac_addr, &peer->mac_addr))
- vdev->last_real_peer = peer;
- peer->rx_opt_proc = pdev->rx_opt_proc;
- ol_rx_peer_init(pdev, peer);
- /* initialize the peer_id */
- for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++)
- peer->peer_ids[i] = HTT_INVALID_PEER;
- peer->osif_rx = NULL;
- cdf_spinlock_init(&peer->peer_info_lock);
- cdf_spinlock_init(&peer->bufq_lock);
- cdf_atomic_init(&peer->delete_in_progress);
- cdf_atomic_init(&peer->flush_in_progress);
- cdf_atomic_init(&peer->ref_cnt);
- /* keep one reference for attach */
- cdf_atomic_inc(&peer->ref_cnt);
- /* keep one reference for ol_rx_peer_map_handler */
- cdf_atomic_inc(&peer->ref_cnt);
- peer->valid = 1;
- ol_txrx_peer_find_hash_add(pdev, peer);
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2,
- "vdev %p created peer %p (%02x:%02x:%02x:%02x:%02x:%02x)\n",
- vdev, peer,
- peer->mac_addr.raw[0], peer->mac_addr.raw[1],
- peer->mac_addr.raw[2], peer->mac_addr.raw[3],
- peer->mac_addr.raw[4], peer->mac_addr.raw[5]);
- /*
- * For every peer MAp message search and set if bss_peer
- */
- differs =
- cdf_mem_compare(peer->mac_addr.raw, vdev->mac_addr.raw,
- OL_TXRX_MAC_ADDR_LEN);
- if (!differs)
- peer->bss_peer = 1;
- /*
- * The peer starts in the "disc" state while association is in progress.
- * Once association completes, the peer will get updated to "auth" state
- * by a call to ol_txrx_peer_state_update if the peer is in open mode,
- * or else to the "conn" state. For non-open mode, the peer will
- * progress to "auth" state once the authentication completes.
- */
- peer->state = ol_txrx_peer_state_invalid;
- ol_txrx_peer_state_update(pdev, peer->mac_addr.raw,
- ol_txrx_peer_state_disc);
- #ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI
- peer->rssi_dbm = HTT_RSSI_INVALID;
- #endif
- ol_txrx_local_peer_id_alloc(pdev, peer);
- return peer;
- }
- /*
- * Discarding tx filter - removes all data frames (disconnected state)
- */
- static A_STATUS ol_tx_filter_discard(struct ol_txrx_msdu_info_t *tx_msdu_info)
- {
- return A_ERROR;
- }
- /*
- * Non-autentication tx filter - filters out data frames that are not
- * related to authentication, but allows EAPOL (PAE) or WAPI (WAI)
- * data frames (connected state)
- */
- static A_STATUS ol_tx_filter_non_auth(struct ol_txrx_msdu_info_t *tx_msdu_info)
- {
- return
- (tx_msdu_info->htt.info.ethertype == ETHERTYPE_PAE ||
- tx_msdu_info->htt.info.ethertype ==
- ETHERTYPE_WAI) ? A_OK : A_ERROR;
- }
- /*
- * Pass-through tx filter - lets all data frames through (authenticated state)
- */
- static A_STATUS ol_tx_filter_pass_thru(struct ol_txrx_msdu_info_t *tx_msdu_info)
- {
- return A_OK;
- }
- CDF_STATUS
- ol_txrx_peer_state_update(struct ol_txrx_pdev_t *pdev, uint8_t *peer_mac,
- enum ol_txrx_peer_state state)
- {
- struct ol_txrx_peer_t *peer;
- if (cdf_unlikely(!pdev)) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Pdev is NULL");
- cdf_assert(0);
- return CDF_STATUS_E_INVAL;
- }
- peer = ol_txrx_peer_find_hash_find(pdev, peer_mac, 0, 1);
- if (NULL == peer) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, "%s: peer is null for peer_mac"
- " 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", __FUNCTION__,
- peer_mac[0], peer_mac[1], peer_mac[2], peer_mac[3],
- peer_mac[4], peer_mac[5]);
- return CDF_STATUS_E_INVAL;
- }
- /* TODO: Should we send WMI command of the connection state? */
- /* avoid multiple auth state change. */
- if (peer->state == state) {
- #ifdef TXRX_PRINT_VERBOSE_ENABLE
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO3,
- "%s: no state change, returns directly\n",
- __func__);
- #endif
- cdf_atomic_dec(&peer->ref_cnt);
- return CDF_STATUS_SUCCESS;
- }
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, "%s: change from %d to %d\n",
- __func__, peer->state, state);
- peer->tx_filter = (state == ol_txrx_peer_state_auth)
- ? ol_tx_filter_pass_thru
- : ((state == ol_txrx_peer_state_conn)
- ? ol_tx_filter_non_auth
- : ol_tx_filter_discard);
- if (peer->vdev->pdev->cfg.host_addba) {
- if (state == ol_txrx_peer_state_auth) {
- int tid;
- /*
- * Pause all regular (non-extended) TID tx queues until
- * data arrives and ADDBA negotiation has completed.
- */
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2,
- "%s: pause peer and unpause mgmt/non-qos\n",
- __func__);
- ol_txrx_peer_pause(peer); /* pause all tx queues */
- /* unpause mgmt and non-QoS tx queues */
- for (tid = OL_TX_NUM_QOS_TIDS;
- tid < OL_TX_NUM_TIDS; tid++)
- ol_txrx_peer_tid_unpause(peer, tid);
- }
- }
- cdf_atomic_dec(&peer->ref_cnt);
- /* Set the state after the Pause to avoid the race condiction
- with ADDBA check in tx path */
- peer->state = state;
- return CDF_STATUS_SUCCESS;
- }
- void
- ol_txrx_peer_keyinstalled_state_update(struct ol_txrx_peer_t *peer, uint8_t val)
- {
- peer->keyinstalled = val;
- }
- void
- ol_txrx_peer_update(ol_txrx_vdev_handle vdev,
- uint8_t *peer_mac,
- union ol_txrx_peer_update_param_t *param,
- enum ol_txrx_peer_update_select_t select)
- {
- struct ol_txrx_peer_t *peer;
- peer = ol_txrx_peer_find_hash_find(vdev->pdev, peer_mac, 0, 1);
- if (!peer) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, "%s: peer is null",
- __func__);
- return;
- }
- switch (select) {
- case ol_txrx_peer_update_qos_capable:
- {
- /* save qos_capable here txrx peer,
- * when HTT_ISOC_T2H_MSG_TYPE_PEER_INFO comes then save.
- */
- peer->qos_capable = param->qos_capable;
- /*
- * The following function call assumes that the peer has a
- * single ID. This is currently true, and
- * is expected to remain true.
- */
- htt_peer_qos_update(peer->vdev->pdev->htt_pdev,
- peer->peer_ids[0],
- peer->qos_capable);
- break;
- }
- case ol_txrx_peer_update_uapsdMask:
- {
- peer->uapsd_mask = param->uapsd_mask;
- htt_peer_uapsdmask_update(peer->vdev->pdev->htt_pdev,
- peer->peer_ids[0],
- peer->uapsd_mask);
- break;
- }
- case ol_txrx_peer_update_peer_security:
- {
- enum ol_sec_type sec_type = param->sec_type;
- enum htt_sec_type peer_sec_type = htt_sec_type_none;
- switch (sec_type) {
- case ol_sec_type_none:
- peer_sec_type = htt_sec_type_none;
- break;
- case ol_sec_type_wep128:
- peer_sec_type = htt_sec_type_wep128;
- break;
- case ol_sec_type_wep104:
- peer_sec_type = htt_sec_type_wep104;
- break;
- case ol_sec_type_wep40:
- peer_sec_type = htt_sec_type_wep40;
- break;
- case ol_sec_type_tkip:
- peer_sec_type = htt_sec_type_tkip;
- break;
- case ol_sec_type_tkip_nomic:
- peer_sec_type = htt_sec_type_tkip_nomic;
- break;
- case ol_sec_type_aes_ccmp:
- peer_sec_type = htt_sec_type_aes_ccmp;
- break;
- case ol_sec_type_wapi:
- peer_sec_type = htt_sec_type_wapi;
- break;
- default:
- peer_sec_type = htt_sec_type_none;
- break;
- }
- peer->security[txrx_sec_ucast].sec_type =
- peer->security[txrx_sec_mcast].sec_type =
- peer_sec_type;
- break;
- }
- default:
- {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "ERROR: unknown param %d in %s", select,
- __func__);
- break;
- }
- }
- cdf_atomic_dec(&peer->ref_cnt);
- }
- uint8_t
- ol_txrx_peer_uapsdmask_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id)
- {
- struct ol_txrx_peer_t *peer;
- peer = ol_txrx_peer_find_by_id(txrx_pdev, peer_id);
- if (peer)
- return peer->uapsd_mask;
- return 0;
- }
- uint8_t
- ol_txrx_peer_qoscapable_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id)
- {
- struct ol_txrx_peer_t *peer_t =
- ol_txrx_peer_find_by_id(txrx_pdev, peer_id);
- if (peer_t != NULL)
- return peer_t->qos_capable;
- return 0;
- }
- void ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer)
- {
- struct ol_txrx_vdev_t *vdev;
- struct ol_txrx_pdev_t *pdev;
- int i;
- /* preconditions */
- TXRX_ASSERT2(peer);
- vdev = peer->vdev;
- if (NULL == vdev) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1,
- "The vdev is not present anymore\n");
- return;
- }
- pdev = vdev->pdev;
- if (NULL == pdev) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1,
- "The pdev is not present anymore\n");
- return;
- }
- /*
- * Check for the reference count before deleting the peer
- * as we noticed that sometimes we are re-entering this
- * function again which is leading to dead-lock.
- * (A double-free should never happen, so assert if it does.)
- */
- if (0 == cdf_atomic_read(&(peer->ref_cnt))) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
- "The Peer is not present anymore\n");
- cdf_assert(0);
- return;
- }
- /*
- * Hold the lock all the way from checking if the peer ref count
- * is zero until the peer references are removed from the hash
- * table and vdev list (if the peer ref count is zero).
- * This protects against a new HL tx operation starting to use the
- * peer object just after this function concludes it's done being used.
- * Furthermore, the lock needs to be held while checking whether the
- * vdev's list of peers is empty, to make sure that list is not modified
- * concurrently with the empty check.
- */
- cdf_spin_lock_bh(&pdev->peer_ref_mutex);
- if (cdf_atomic_dec_and_test(&peer->ref_cnt)) {
- u_int16_t peer_id;
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
- "Deleting peer %p (%02x:%02x:%02x:%02x:%02x:%02x)\n",
- peer,
- peer->mac_addr.raw[0], peer->mac_addr.raw[1],
- peer->mac_addr.raw[2], peer->mac_addr.raw[3],
- peer->mac_addr.raw[4], peer->mac_addr.raw[5]);
- peer_id = peer->local_id;
- /* remove the reference to the peer from the hash table */
- ol_txrx_peer_find_hash_remove(pdev, peer);
- /* remove the peer from its parent vdev's list */
- TAILQ_REMOVE(&peer->vdev->peer_list, peer, peer_list_elem);
- /* cleanup the Rx reorder queues for this peer */
- ol_rx_peer_cleanup(vdev, peer);
- /* peer is removed from peer_list */
- cdf_atomic_set(&peer->delete_in_progress, 0);
- /*
- * Set wait_delete_comp event if the current peer id matches
- * with registered peer id.
- */
- if (peer_id == vdev->wait_on_peer_id) {
- cdf_event_set(&vdev->wait_delete_comp);
- vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID;
- }
- /* check whether the parent vdev has no peers left */
- if (TAILQ_EMPTY(&vdev->peer_list)) {
- /*
- * Check if the parent vdev was waiting for its peers
- * to be deleted, in order for it to be deleted too.
- */
- if (vdev->delete.pending) {
- ol_txrx_vdev_delete_cb vdev_delete_cb =
- vdev->delete.callback;
- void *vdev_delete_context =
- vdev->delete.context;
- /*
- * Now that there are no references to the peer,
- * we can release the peer reference lock.
- */
- cdf_spin_unlock_bh(&pdev->peer_ref_mutex);
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1,
- "%s: deleting vdev object %p "
- "(%02x:%02x:%02x:%02x:%02x:%02x)"
- " - its last peer is done\n",
- __func__, vdev,
- vdev->mac_addr.raw[0],
- vdev->mac_addr.raw[1],
- vdev->mac_addr.raw[2],
- vdev->mac_addr.raw[3],
- vdev->mac_addr.raw[4],
- vdev->mac_addr.raw[5]);
- /* all peers are gone, go ahead and delete it */
- cdf_mem_free(vdev);
- if (vdev_delete_cb)
- vdev_delete_cb(vdev_delete_context);
- } else {
- cdf_spin_unlock_bh(&pdev->peer_ref_mutex);
- }
- } else {
- cdf_spin_unlock_bh(&pdev->peer_ref_mutex);
- }
- /*
- * 'array' is allocated in addba handler and is supposed to be
- * freed in delba handler. There is the case (for example, in
- * SSR) where delba handler is not called. Because array points
- * to address of 'base' by default and is reallocated in addba
- * handler later, only free the memory when the array does not
- * point to base.
- */
- for (i = 0; i < OL_TXRX_NUM_EXT_TIDS; i++) {
- if (peer->tids_rx_reorder[i].array !=
- &peer->tids_rx_reorder[i].base) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1,
- "%s, delete reorder arr, tid:%d\n",
- __func__, i);
- cdf_mem_free(peer->tids_rx_reorder[i].array);
- ol_rx_reorder_init(&peer->tids_rx_reorder[i],
- (uint8_t) i);
- }
- }
- cdf_mem_free(peer);
- } else {
- cdf_spin_unlock_bh(&pdev->peer_ref_mutex);
- }
- }
- void ol_txrx_peer_detach(ol_txrx_peer_handle peer)
- {
- struct ol_txrx_vdev_t *vdev = peer->vdev;
- /* redirect peer's rx delivery function to point to a discard func */
- peer->rx_opt_proc = ol_rx_discard;
- peer->valid = 0;
- ol_txrx_local_peer_id_free(peer->vdev->pdev, peer);
- /* debug print to dump rx reorder state */
- /* htt_rx_reorder_log_print(vdev->pdev->htt_pdev); */
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
- "%s:peer %p (%02x:%02x:%02x:%02x:%02x:%02x)\n",
- __func__, peer,
- peer->mac_addr.raw[0], peer->mac_addr.raw[1],
- peer->mac_addr.raw[2], peer->mac_addr.raw[3],
- peer->mac_addr.raw[4], peer->mac_addr.raw[5]);
- ol_txrx_flush_rx_frames(peer, 1);
- if (peer->vdev->last_real_peer == peer)
- peer->vdev->last_real_peer = NULL;
- cdf_spin_lock_bh(&vdev->pdev->last_real_peer_mutex);
- if (vdev->last_real_peer == peer)
- vdev->last_real_peer = NULL;
- cdf_spin_unlock_bh(&vdev->pdev->last_real_peer_mutex);
- htt_rx_reorder_log_print(peer->vdev->pdev->htt_pdev);
- cdf_spinlock_destroy(&peer->peer_info_lock);
- cdf_spinlock_destroy(&peer->bufq_lock);
- /* set delete_in_progress to identify that wma
- * is waiting for unmap massage for this peer */
- cdf_atomic_set(&peer->delete_in_progress, 1);
- /*
- * Remove the reference added during peer_attach.
- * The peer will still be left allocated until the
- * PEER_UNMAP message arrives to remove the other
- * reference, added by the PEER_MAP message.
- */
- ol_txrx_peer_unref_delete(peer);
- }
- ol_txrx_peer_handle
- ol_txrx_peer_find_by_addr(struct ol_txrx_pdev_t *pdev, uint8_t *peer_mac_addr)
- {
- struct ol_txrx_peer_t *peer;
- peer = ol_txrx_peer_find_hash_find(pdev, peer_mac_addr, 0, 0);
- if (peer) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
- "%s: Delete extra reference %p\n", __func__, peer);
- /* release the extra reference */
- ol_txrx_peer_unref_delete(peer);
- }
- return peer;
- }
- /**
- * ol_txrx_dump_tx_desc() - dump tx desc total and free count
- * @txrx_pdev: Pointer to txrx pdev
- *
- * Return: none
- */
- static void ol_txrx_dump_tx_desc(ol_txrx_pdev_handle pdev_handle)
- {
- struct ol_txrx_pdev_t *pdev = (ol_txrx_pdev_handle) pdev_handle;
- uint32_t total;
- total = ol_tx_get_desc_global_pool_size(pdev);
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
- "total tx credit %d num_free %d",
- total, pdev->tx_desc.num_free);
- return;
- }
- /**
- * ol_txrx_wait_for_pending_tx() - wait for tx queue to be empty
- * @timeout: timeout in ms
- *
- * Wait for tx queue to be empty, return timeout error if
- * queue doesn't empty before timeout occurs.
- *
- * Return:
- * CDF_STATUS_SUCCESS if the queue empties,
- * CDF_STATUS_E_TIMEOUT in case of timeout,
- * CDF_STATUS_E_FAULT in case of missing handle
- */
- CDF_STATUS ol_txrx_wait_for_pending_tx(int timeout)
- {
- ol_txrx_pdev_handle txrx_pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- if (txrx_pdev == NULL) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
- "%s: txrx context is null", __func__);
- return CDF_STATUS_E_FAULT;
- }
- while (ol_txrx_get_tx_pending(txrx_pdev)) {
- cdf_sleep(OL_ATH_TX_DRAIN_WAIT_DELAY);
- if (timeout <= 0) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
- "%s: tx frames are pending", __func__);
- ol_txrx_dump_tx_desc(txrx_pdev);
- return CDF_STATUS_E_TIMEOUT;
- }
- timeout = timeout - OL_ATH_TX_DRAIN_WAIT_DELAY;
- }
- return CDF_STATUS_SUCCESS;
- }
- #ifndef QCA_WIFI_3_0_EMU
- #define SUSPEND_DRAIN_WAIT 500
- #else
- #define SUSPEND_DRAIN_WAIT 3000
- #endif
- /**
- * ol_txrx_bus_suspend() - bus suspend
- *
- * Ensure that ol_txrx is ready for bus suspend
- *
- * Return: CDF_STATUS
- */
- CDF_STATUS ol_txrx_bus_suspend(void)
- {
- return ol_txrx_wait_for_pending_tx(SUSPEND_DRAIN_WAIT);
- }
- /**
- * ol_txrx_bus_resume() - bus resume
- *
- * Dummy function for symetry
- *
- * Return: CDF_STATUS_SUCCESS
- */
- CDF_STATUS ol_txrx_bus_resume(void)
- {
- return CDF_STATUS_SUCCESS;
- }
- int ol_txrx_get_tx_pending(ol_txrx_pdev_handle pdev_handle)
- {
- struct ol_txrx_pdev_t *pdev = (ol_txrx_pdev_handle) pdev_handle;
- uint32_t total;
- total = ol_tx_get_desc_global_pool_size(pdev);
- return total - ol_tx_get_total_free_desc(pdev);
- }
- void ol_txrx_discard_tx_pending(ol_txrx_pdev_handle pdev_handle)
- {
- ol_tx_desc_list tx_descs;
- /* First let hif do the cdf_atomic_dec_and_test(&tx_desc->ref_cnt)
- * then let htt do the cdf_atomic_dec_and_test(&tx_desc->ref_cnt)
- * which is tha same with normal data send complete path*/
- htt_tx_pending_discard(pdev_handle->htt_pdev);
- TAILQ_INIT(&tx_descs);
- ol_tx_queue_discard(pdev_handle, true, &tx_descs);
- /* Discard Frames in Discard List */
- ol_tx_desc_frame_list_free(pdev_handle, &tx_descs, 1 /* error */);
- ol_tx_discard_target_frms(pdev_handle);
- }
- /*--- debug features --------------------------------------------------------*/
- unsigned g_txrx_print_level = TXRX_PRINT_LEVEL_ERR; /* default */
- void ol_txrx_print_level_set(unsigned level)
- {
- #ifndef TXRX_PRINT_ENABLE
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_FATAL,
- "The driver is compiled without TXRX prints enabled.\n"
- "To enable them, recompile with TXRX_PRINT_ENABLE defined");
- #else
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO,
- "TXRX printout level changed from %d to %d",
- g_txrx_print_level, level);
- g_txrx_print_level = level;
- #endif
- }
- struct ol_txrx_stats_req_internal {
- struct ol_txrx_stats_req base;
- int serviced; /* state of this request */
- int offset;
- };
- static inline
- uint64_t ol_txrx_stats_ptr_to_u64(struct ol_txrx_stats_req_internal *req)
- {
- return (uint64_t) ((size_t) req);
- }
- static inline
- struct ol_txrx_stats_req_internal *ol_txrx_u64_to_stats_ptr(uint64_t cookie)
- {
- return (struct ol_txrx_stats_req_internal *)((size_t) cookie);
- }
- #ifdef ATH_PERF_PWR_OFFLOAD
- void
- ol_txrx_fw_stats_cfg(ol_txrx_vdev_handle vdev,
- uint8_t cfg_stats_type, uint32_t cfg_val)
- {
- uint64_t dummy_cookie = 0;
- htt_h2t_dbg_stats_get(vdev->pdev->htt_pdev, 0 /* upload mask */,
- 0 /* reset mask */,
- cfg_stats_type, cfg_val, dummy_cookie);
- }
- A_STATUS
- ol_txrx_fw_stats_get(ol_txrx_vdev_handle vdev, struct ol_txrx_stats_req *req,
- bool response_expected)
- {
- struct ol_txrx_pdev_t *pdev = vdev->pdev;
- uint64_t cookie;
- struct ol_txrx_stats_req_internal *non_volatile_req;
- if (!pdev ||
- req->stats_type_upload_mask >= 1 << HTT_DBG_NUM_STATS ||
- req->stats_type_reset_mask >= 1 << HTT_DBG_NUM_STATS) {
- return A_ERROR;
- }
- /*
- * Allocate a non-transient stats request object.
- * (The one provided as an argument is likely allocated on the stack.)
- */
- non_volatile_req = cdf_mem_malloc(sizeof(*non_volatile_req));
- if (!non_volatile_req)
- return A_NO_MEMORY;
- /* copy the caller's specifications */
- non_volatile_req->base = *req;
- non_volatile_req->serviced = 0;
- non_volatile_req->offset = 0;
- /* use the non-volatile request object's address as the cookie */
- cookie = ol_txrx_stats_ptr_to_u64(non_volatile_req);
- if (htt_h2t_dbg_stats_get(pdev->htt_pdev,
- req->stats_type_upload_mask,
- req->stats_type_reset_mask,
- HTT_H2T_STATS_REQ_CFG_STAT_TYPE_INVALID, 0,
- cookie)) {
- cdf_mem_free(non_volatile_req);
- return A_ERROR;
- }
- if (req->wait.blocking)
- while (cdf_semaphore_acquire(pdev->osdev, req->wait.sem_ptr))
- ;
- if (response_expected == false)
- cdf_mem_free(non_volatile_req);
- return A_OK;
- }
- #endif
- void
- ol_txrx_fw_stats_handler(ol_txrx_pdev_handle pdev,
- uint64_t cookie, uint8_t *stats_info_list)
- {
- enum htt_dbg_stats_type type;
- enum htt_dbg_stats_status status;
- int length;
- uint8_t *stats_data;
- struct ol_txrx_stats_req_internal *req;
- int more = 0;
- req = ol_txrx_u64_to_stats_ptr(cookie);
- do {
- htt_t2h_dbg_stats_hdr_parse(stats_info_list, &type, &status,
- &length, &stats_data);
- if (status == HTT_DBG_STATS_STATUS_SERIES_DONE)
- break;
- if (status == HTT_DBG_STATS_STATUS_PRESENT ||
- status == HTT_DBG_STATS_STATUS_PARTIAL) {
- uint8_t *buf;
- int bytes = 0;
- if (status == HTT_DBG_STATS_STATUS_PARTIAL)
- more = 1;
- if (req->base.print.verbose || req->base.print.concise)
- /* provide the header along with the data */
- htt_t2h_stats_print(stats_info_list,
- req->base.print.concise);
- switch (type) {
- case HTT_DBG_STATS_WAL_PDEV_TXRX:
- bytes = sizeof(struct wlan_dbg_stats);
- if (req->base.copy.buf) {
- int lmt;
- lmt = sizeof(struct wlan_dbg_stats);
- if (req->base.copy.byte_limit < lmt)
- lmt = req->base.copy.byte_limit;
- buf = req->base.copy.buf + req->offset;
- cdf_mem_copy(buf, stats_data, lmt);
- }
- break;
- case HTT_DBG_STATS_RX_REORDER:
- bytes = sizeof(struct rx_reorder_stats);
- if (req->base.copy.buf) {
- int lmt;
- lmt = sizeof(struct rx_reorder_stats);
- if (req->base.copy.byte_limit < lmt)
- lmt = req->base.copy.byte_limit;
- buf = req->base.copy.buf + req->offset;
- cdf_mem_copy(buf, stats_data, lmt);
- }
- break;
- case HTT_DBG_STATS_RX_RATE_INFO:
- bytes = sizeof(wlan_dbg_rx_rate_info_t);
- if (req->base.copy.buf) {
- int lmt;
- lmt = sizeof(wlan_dbg_rx_rate_info_t);
- if (req->base.copy.byte_limit < lmt)
- lmt = req->base.copy.byte_limit;
- buf = req->base.copy.buf + req->offset;
- cdf_mem_copy(buf, stats_data, lmt);
- }
- break;
- case HTT_DBG_STATS_TX_RATE_INFO:
- bytes = sizeof(wlan_dbg_tx_rate_info_t);
- if (req->base.copy.buf) {
- int lmt;
- lmt = sizeof(wlan_dbg_tx_rate_info_t);
- if (req->base.copy.byte_limit < lmt)
- lmt = req->base.copy.byte_limit;
- buf = req->base.copy.buf + req->offset;
- cdf_mem_copy(buf, stats_data, lmt);
- }
- break;
- case HTT_DBG_STATS_TX_PPDU_LOG:
- bytes = 0;
- /* TO DO: specify how many bytes are present */
- /* TO DO: add copying to the requestor's buf */
- case HTT_DBG_STATS_RX_REMOTE_RING_BUFFER_INFO:
- bytes = sizeof(struct rx_remote_buffer_mgmt_stats);
- if (req->base.copy.buf) {
- int limit;
- limit = sizeof(struct rx_remote_buffer_mgmt_stats);
- if (req->base.copy.byte_limit < limit) {
- limit = req->base.copy.byte_limit;
- }
- buf = req->base.copy.buf + req->offset;
- cdf_mem_copy(buf, stats_data, limit);
- }
- break;
- case HTT_DBG_STATS_TXBF_INFO:
- bytes = sizeof(struct wlan_dbg_txbf_data_stats);
- if (req->base.copy.buf) {
- int limit;
- limit = sizeof(struct wlan_dbg_txbf_data_stats);
- if (req->base.copy.byte_limit < limit)
- limit = req->base.copy.byte_limit;
- buf = req->base.copy.buf + req->offset;
- cdf_mem_copy(buf, stats_data, limit);
- }
- break;
- case HTT_DBG_STATS_SND_INFO:
- bytes = sizeof(struct wlan_dbg_txbf_snd_stats);
- if (req->base.copy.buf) {
- int limit;
- limit = sizeof(struct wlan_dbg_txbf_snd_stats);
- if (req->base.copy.byte_limit < limit)
- limit = req->base.copy.byte_limit;
- buf = req->base.copy.buf + req->offset;
- cdf_mem_copy(buf, stats_data, limit);
- }
- break;
- case HTT_DBG_STATS_TX_SELFGEN_INFO:
- bytes = sizeof(struct wlan_dbg_tx_selfgen_stats);
- if (req->base.copy.buf) {
- int limit;
- limit = sizeof(struct wlan_dbg_tx_selfgen_stats);
- if (req->base.copy.byte_limit < limit)
- limit = req->base.copy.byte_limit;
- buf = req->base.copy.buf + req->offset;
- cdf_mem_copy(buf, stats_data, limit);
- }
- break;
- case HTT_DBG_STATS_ERROR_INFO:
- bytes =
- sizeof(struct wlan_dbg_wifi2_error_stats);
- if (req->base.copy.buf) {
- int limit;
- limit =
- sizeof(struct wlan_dbg_wifi2_error_stats);
- if (req->base.copy.byte_limit < limit)
- limit = req->base.copy.byte_limit;
- buf = req->base.copy.buf + req->offset;
- cdf_mem_copy(buf, stats_data, limit);
- }
- break;
- case HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT:
- bytes =
- sizeof(struct rx_txbf_musu_ndpa_pkts_stats);
- if (req->base.copy.buf) {
- int limit;
- limit = sizeof(struct
- rx_txbf_musu_ndpa_pkts_stats);
- if (req->base.copy.byte_limit < limit)
- limit =
- req->base.copy.byte_limit;
- buf = req->base.copy.buf + req->offset;
- cdf_mem_copy(buf, stats_data, limit);
- }
- break;
- default:
- break;
- }
- buf = req->base.copy.buf
- ? req->base.copy.buf
- : stats_data;
- if (req->base.callback.fp)
- req->base.callback.fp(req->base.callback.ctxt,
- type, buf, bytes);
- }
- stats_info_list += length;
- } while (1);
- if (!more) {
- if (req->base.wait.blocking)
- cdf_semaphore_release(pdev->osdev,
- req->base.wait.sem_ptr);
- cdf_mem_free(req);
- }
- }
- #ifndef ATH_PERF_PWR_OFFLOAD /*---------------------------------------------*/
- int ol_txrx_debug(ol_txrx_vdev_handle vdev, int debug_specs)
- {
- if (debug_specs & TXRX_DBG_MASK_OBJS) {
- #if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5
- ol_txrx_pdev_display(vdev->pdev, 0);
- #else
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_FATAL,
- "The pdev,vdev,peer display functions are disabled.\n"
- "To enable them, recompile with TXRX_DEBUG_LEVEL > 5");
- #endif
- }
- if (debug_specs & TXRX_DBG_MASK_STATS) {
- ol_txrx_stats_display(vdev->pdev);
- }
- if (debug_specs & TXRX_DBG_MASK_PROT_ANALYZE) {
- #if defined(ENABLE_TXRX_PROT_ANALYZE)
- ol_txrx_prot_ans_display(vdev->pdev);
- #else
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_FATAL,
- "txrx protocol analysis is disabled.\n"
- "To enable it, recompile with "
- "ENABLE_TXRX_PROT_ANALYZE defined");
- #endif
- }
- if (debug_specs & TXRX_DBG_MASK_RX_REORDER_TRACE) {
- #if defined(ENABLE_RX_REORDER_TRACE)
- ol_rx_reorder_trace_display(vdev->pdev, 0, 0);
- #else
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_FATAL,
- "rx reorder seq num trace is disabled.\n"
- "To enable it, recompile with "
- "ENABLE_RX_REORDER_TRACE defined");
- #endif
- }
- return 0;
- }
- #endif
- int ol_txrx_aggr_cfg(ol_txrx_vdev_handle vdev,
- int max_subfrms_ampdu, int max_subfrms_amsdu)
- {
- return htt_h2t_aggr_cfg_msg(vdev->pdev->htt_pdev,
- max_subfrms_ampdu, max_subfrms_amsdu);
- }
- #if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5
- void ol_txrx_pdev_display(ol_txrx_pdev_handle pdev, int indent)
- {
- struct ol_txrx_vdev_t *vdev;
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW,
- "%*s%s:\n", indent, " ", "txrx pdev");
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW,
- "%*spdev object: %p", indent + 4, " ", pdev);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW,
- "%*svdev list:", indent + 4, " ");
- TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) {
- ol_txrx_vdev_display(vdev, indent + 8);
- }
- ol_txrx_peer_find_display(pdev, indent + 4);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW,
- "%*stx desc pool: %d elems @ %p", indent + 4, " ",
- pdev->tx_desc.pool_size, pdev->tx_desc.array);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW, " ");
- htt_display(pdev->htt_pdev, indent);
- }
- void ol_txrx_vdev_display(ol_txrx_vdev_handle vdev, int indent)
- {
- struct ol_txrx_peer_t *peer;
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW,
- "%*stxrx vdev: %p\n", indent, " ", vdev);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW,
- "%*sID: %d\n", indent + 4, " ", vdev->vdev_id);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW,
- "%*sMAC addr: %d:%d:%d:%d:%d:%d",
- indent + 4, " ",
- vdev->mac_addr.raw[0], vdev->mac_addr.raw[1],
- vdev->mac_addr.raw[2], vdev->mac_addr.raw[3],
- vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW,
- "%*speer list:", indent + 4, " ");
- TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) {
- ol_txrx_peer_display(peer, indent + 8);
- }
- }
- void ol_txrx_peer_display(ol_txrx_peer_handle peer, int indent)
- {
- int i;
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW,
- "%*stxrx peer: %p", indent, " ", peer);
- for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) {
- if (peer->peer_ids[i] != HTT_INVALID_PEER) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_INFO_LOW,
- "%*sID: %d", indent + 4, " ",
- peer->peer_ids[i]);
- }
- }
- }
- #endif /* TXRX_DEBUG_LEVEL */
- #if defined(FEATURE_TSO) && defined(FEATURE_TSO_DEBUG)
- void ol_txrx_stats_display_tso(ol_txrx_pdev_handle pdev)
- {
- int msdu_idx;
- int seg_idx;
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "TSO pkts %lld, bytes %lld\n",
- pdev->stats.pub.tx.tso.tso_pkts.pkts,
- pdev->stats.pub.tx.tso.tso_pkts.bytes);
- for (msdu_idx = 0; msdu_idx < NUM_MAX_TSO_MSDUS; msdu_idx++) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "curr msdu idx: %d curr seg idx: %d num segs %d\n",
- TXRX_STATS_TSO_MSDU_IDX(pdev),
- TXRX_STATS_TSO_SEG_IDX(pdev),
- TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, msdu_idx));
- for (seg_idx = 0;
- ((seg_idx < TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, msdu_idx)) &&
- (seg_idx < NUM_MAX_TSO_SEGS));
- seg_idx++) {
- struct cdf_tso_seg_t tso_seg =
- TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "msdu idx: %d seg idx: %d\n",
- msdu_idx, seg_idx);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "tso_enable: %d\n",
- tso_seg.tso_flags.tso_enable);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "fin %d syn %d rst %d psh %d ack %d\n"
- "urg %d ece %d cwr %d ns %d\n",
- tso_seg.tso_flags.fin, tso_seg.tso_flags.syn,
- tso_seg.tso_flags.rst, tso_seg.tso_flags.psh,
- tso_seg.tso_flags.ack, tso_seg.tso_flags.urg,
- tso_seg.tso_flags.ece, tso_seg.tso_flags.cwr,
- tso_seg.tso_flags.ns);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "tcp_seq_num: 0x%x ip_id: %d\n",
- tso_seg.tso_flags.tcp_seq_num,
- tso_seg.tso_flags.ip_id);
- }
- }
- }
- #endif
- /**
- * ol_txrx_stats() - update ol layer stats
- * @vdev_id: vdev_id
- * @buffer: pointer to buffer
- * @buf_len: length of the buffer
- *
- * Return: length of string
- */
- int
- ol_txrx_stats(uint8_t vdev_id, char *buffer, unsigned buf_len)
- {
- uint32_t len = 0;
- ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id);
- if (!vdev) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: vdev is NULL", __func__);
- snprintf(buffer, buf_len, "vdev not found");
- return len;
- }
- len = scnprintf(buffer, buf_len,
- "\nTXRX stats:\n"
- "\nllQueue State : %s"
- "\n pause %u unpause %u"
- "\n overflow %u"
- "\nllQueue timer state : %s\n",
- ((vdev->ll_pause.is_q_paused == false) ? "UNPAUSED" : "PAUSED"),
- vdev->ll_pause.q_pause_cnt,
- vdev->ll_pause.q_unpause_cnt,
- vdev->ll_pause.q_overflow_cnt,
- ((vdev->ll_pause.is_q_timer_on == false)
- ? "NOT-RUNNING" : "RUNNING"));
- return len;
- }
- void ol_txrx_stats_display(ol_txrx_pdev_handle pdev)
- {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR, "txrx stats:");
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- " tx: sent %lld msdus (%lld B), "
- " rejected %lld (%lld B), dropped %lld (%lld B)",
- pdev->stats.pub.tx.delivered.pkts,
- pdev->stats.pub.tx.delivered.bytes,
- pdev->stats.pub.tx.dropped.host_reject.pkts,
- pdev->stats.pub.tx.dropped.host_reject.bytes,
- pdev->stats.pub.tx.dropped.download_fail.pkts
- + pdev->stats.pub.tx.dropped.target_discard.pkts
- + pdev->stats.pub.tx.dropped.no_ack.pkts,
- pdev->stats.pub.tx.dropped.download_fail.bytes
- + pdev->stats.pub.tx.dropped.target_discard.bytes
- + pdev->stats.pub.tx.dropped.no_ack.bytes);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- " download fail: %lld (%lld B), "
- "target discard: %lld (%lld B), "
- "no ack: %lld (%lld B)",
- pdev->stats.pub.tx.dropped.download_fail.pkts,
- pdev->stats.pub.tx.dropped.download_fail.bytes,
- pdev->stats.pub.tx.dropped.target_discard.pkts,
- pdev->stats.pub.tx.dropped.target_discard.bytes,
- pdev->stats.pub.tx.dropped.no_ack.pkts,
- pdev->stats.pub.tx.dropped.no_ack.bytes);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "Tx completion per interrupt:\n"
- "Single Packet %d\n"
- " 2-10 Packets %d\n"
- "11-20 Packets %d\n"
- "21-30 Packets %d\n"
- "31-40 Packets %d\n"
- "41-50 Packets %d\n"
- "51-60 Packets %d\n"
- " 60+ Packets %d\n",
- pdev->stats.pub.tx.comp_histogram.pkts_1,
- pdev->stats.pub.tx.comp_histogram.pkts_2_10,
- pdev->stats.pub.tx.comp_histogram.pkts_11_20,
- pdev->stats.pub.tx.comp_histogram.pkts_21_30,
- pdev->stats.pub.tx.comp_histogram.pkts_31_40,
- pdev->stats.pub.tx.comp_histogram.pkts_41_50,
- pdev->stats.pub.tx.comp_histogram.pkts_51_60,
- pdev->stats.pub.tx.comp_histogram.pkts_61_plus);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- " rx: %lld ppdus, %lld mpdus, %lld msdus, %lld bytes, %lld errs",
- pdev->stats.priv.rx.normal.ppdus,
- pdev->stats.priv.rx.normal.mpdus,
- pdev->stats.pub.rx.delivered.pkts,
- pdev->stats.pub.rx.delivered.bytes,
- pdev->stats.priv.rx.err.mpdu_bad);
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- " fwd to stack %d, fwd to fw %d, fwd to stack & fw %d\n",
- pdev->stats.pub.rx.intra_bss_fwd.packets_stack,
- pdev->stats.pub.rx.intra_bss_fwd.packets_fwd,
- pdev->stats.pub.rx.intra_bss_fwd.packets_stack_n_fwd);
- }
- void ol_txrx_stats_clear(ol_txrx_pdev_handle pdev)
- {
- cdf_mem_zero(&pdev->stats, sizeof(pdev->stats));
- }
- #if defined(ENABLE_TXRX_PROT_ANALYZE)
- void ol_txrx_prot_ans_display(ol_txrx_pdev_handle pdev)
- {
- ol_txrx_prot_an_display(pdev->prot_an_tx_sent);
- ol_txrx_prot_an_display(pdev->prot_an_rx_sent);
- }
- #endif /* ENABLE_TXRX_PROT_ANALYZE */
- #ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI
- int16_t ol_txrx_peer_rssi(ol_txrx_peer_handle peer)
- {
- return (peer->rssi_dbm == HTT_RSSI_INVALID) ?
- OL_TXRX_RSSI_INVALID : peer->rssi_dbm;
- }
- #endif /* #ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI */
- #ifdef QCA_ENABLE_OL_TXRX_PEER_STATS
- A_STATUS
- ol_txrx_peer_stats_copy(ol_txrx_pdev_handle pdev,
- ol_txrx_peer_handle peer, ol_txrx_peer_stats_t *stats)
- {
- cdf_assert(pdev && peer && stats);
- cdf_spin_lock_bh(&pdev->peer_stat_mutex);
- cdf_mem_copy(stats, &peer->stats, sizeof(*stats));
- cdf_spin_unlock_bh(&pdev->peer_stat_mutex);
- return A_OK;
- }
- #endif /* QCA_ENABLE_OL_TXRX_PEER_STATS */
- void ol_vdev_rx_set_intrabss_fwd(ol_txrx_vdev_handle vdev, bool val)
- {
- if (NULL == vdev)
- return;
- vdev->disable_intrabss_fwd = val;
- }
- #ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL
- /**
- * ol_txrx_get_vdev_from_sta_id() - get vdev from sta_id
- * @sta_id: sta_id
- *
- * Return: vdev handle
- * NULL if not found.
- */
- static ol_txrx_vdev_handle ol_txrx_get_vdev_from_sta_id(uint8_t sta_id)
- {
- struct ol_txrx_peer_t *peer = NULL;
- ol_txrx_pdev_handle pdev = NULL;
- if (sta_id >= WLAN_MAX_STA_COUNT) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "Invalid sta id passed");
- return NULL;
- }
- pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- if (!pdev) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "PDEV not found for sta_id [%d]", sta_id);
- return NULL;
- }
- peer = ol_txrx_peer_find_by_local_id(pdev, sta_id);
- if (!peer) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "PEER [%d] not found", sta_id);
- return NULL;
- }
- return peer->vdev;
- }
- /**
- * ol_txrx_register_tx_flow_control() - register tx flow control callback
- * @vdev_id: vdev_id
- * @flowControl: flow control callback
- * @osif_fc_ctx: callback context
- *
- * Return: 0 for sucess or error code
- */
- int ol_txrx_register_tx_flow_control (uint8_t vdev_id,
- ol_txrx_tx_flow_control_fp flowControl,
- void *osif_fc_ctx)
- {
- ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id);
- if (NULL == vdev) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: Invalid vdev_id %d", __func__, vdev_id);
- return -EINVAL;
- }
- cdf_spin_lock_bh(&vdev->flow_control_lock);
- vdev->osif_flow_control_cb = flowControl;
- vdev->osif_fc_ctx = osif_fc_ctx;
- cdf_spin_unlock_bh(&vdev->flow_control_lock);
- return 0;
- }
- /**
- * ol_txrx_de_register_tx_flow_control_cb() - deregister tx flow control callback
- * @vdev_id: vdev_id
- *
- * Return: 0 for success or error code
- */
- int ol_txrx_deregister_tx_flow_control_cb(uint8_t vdev_id)
- {
- ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id);
- if (NULL == vdev) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: Invalid vdev_id", __func__);
- return -EINVAL;
- }
- cdf_spin_lock_bh(&vdev->flow_control_lock);
- vdev->osif_flow_control_cb = NULL;
- vdev->osif_fc_ctx = NULL;
- cdf_spin_unlock_bh(&vdev->flow_control_lock);
- return 0;
- }
- /**
- * ol_txrx_get_tx_resource() - if tx resource less than low_watermark
- * @sta_id: sta id
- * @low_watermark: low watermark
- * @high_watermark_offset: high watermark offset value
- *
- * Return: true/false
- */
- bool
- ol_txrx_get_tx_resource(uint8_t sta_id,
- unsigned int low_watermark,
- unsigned int high_watermark_offset)
- {
- ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_sta_id(sta_id);
- if (NULL == vdev) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: Invalid sta_id %d", __func__, sta_id);
- /* Return true so caller do not understand that resource
- * is less than low_watermark.
- * sta_id validation will be done in ol_tx_send_data_frame
- * and if sta_id is not registered then host will drop
- * packet.
- */
- return true;
- }
- cdf_spin_lock_bh(&vdev->pdev->tx_mutex);
- if (vdev->pdev->tx_desc.num_free < (uint16_t) low_watermark) {
- vdev->tx_fl_lwm = (uint16_t) low_watermark;
- vdev->tx_fl_hwm =
- (uint16_t) (low_watermark + high_watermark_offset);
- /* Not enough free resource, stop TX OS Q */
- cdf_atomic_set(&vdev->os_q_paused, 1);
- cdf_spin_unlock_bh(&vdev->pdev->tx_mutex);
- return false;
- }
- cdf_spin_unlock_bh(&vdev->pdev->tx_mutex);
- return true;
- }
- /**
- * ol_txrx_ll_set_tx_pause_q_depth() - set pause queue depth
- * @vdev_id: vdev id
- * @pause_q_depth: pause queue depth
- *
- * Return: 0 for success or error code
- */
- int
- ol_txrx_ll_set_tx_pause_q_depth(uint8_t vdev_id, int pause_q_depth)
- {
- ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id);
- if (NULL == vdev) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: Invalid vdev_id %d", __func__, vdev_id);
- return -EINVAL;
- }
- cdf_spin_lock_bh(&vdev->ll_pause.mutex);
- vdev->ll_pause.max_q_depth = pause_q_depth;
- cdf_spin_unlock_bh(&vdev->ll_pause.mutex);
- return 0;
- }
- /**
- * ol_txrx_flow_control_cb() - call osif flow control callback
- * @vdev: vdev handle
- * @tx_resume: tx resume flag
- *
- * Return: none
- */
- inline void ol_txrx_flow_control_cb(ol_txrx_vdev_handle vdev,
- bool tx_resume)
- {
- cdf_spin_lock_bh(&vdev->flow_control_lock);
- if ((vdev->osif_flow_control_cb) && (vdev->osif_fc_ctx))
- vdev->osif_flow_control_cb(vdev->osif_fc_ctx, tx_resume);
- cdf_spin_unlock_bh(&vdev->flow_control_lock);
- return;
- }
- #endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */
- #ifdef IPA_OFFLOAD
- /**
- * ol_txrx_ipa_uc_get_resource() - Client request resource information
- * @pdev: handle to the HTT instance
- * @ce_sr_base_paddr: copy engine source ring base physical address
- * @ce_sr_ring_size: copy engine source ring size
- * @ce_reg_paddr: copy engine register physical address
- * @tx_comp_ring_base_paddr: tx comp ring base physical address
- * @tx_comp_ring_size: tx comp ring size
- * @tx_num_alloc_buffer: number of allocated tx buffer
- * @rx_rdy_ring_base_paddr: rx ready ring base physical address
- * @rx_rdy_ring_size: rx ready ring size
- * @rx_proc_done_idx_paddr: rx process done index physical address
- * @rx_proc_done_idx_vaddr: rx process done index virtual address
- * @rx2_rdy_ring_base_paddr: rx done ring base physical address
- * @rx2_rdy_ring_size: rx done ring size
- * @rx2_proc_done_idx_paddr: rx done index physical address
- * @rx2_proc_done_idx_vaddr: rx done index virtual address
- *
- * OL client will reuqest IPA UC related resource information
- * Resource information will be distributted to IPA module
- * All of the required resources should be pre-allocated
- *
- * Return: none
- */
- void
- ol_txrx_ipa_uc_get_resource(ol_txrx_pdev_handle pdev,
- cdf_dma_addr_t *ce_sr_base_paddr,
- uint32_t *ce_sr_ring_size,
- cdf_dma_addr_t *ce_reg_paddr,
- cdf_dma_addr_t *tx_comp_ring_base_paddr,
- uint32_t *tx_comp_ring_size,
- uint32_t *tx_num_alloc_buffer,
- cdf_dma_addr_t *rx_rdy_ring_base_paddr,
- uint32_t *rx_rdy_ring_size,
- cdf_dma_addr_t *rx_proc_done_idx_paddr,
- void **rx_proc_done_idx_vaddr,
- cdf_dma_addr_t *rx2_rdy_ring_base_paddr,
- uint32_t *rx2_rdy_ring_size,
- cdf_dma_addr_t *rx2_proc_done_idx2_paddr,
- void **rx2_proc_done_idx2_vaddr)
- {
- htt_ipa_uc_get_resource(pdev->htt_pdev,
- ce_sr_base_paddr,
- ce_sr_ring_size,
- ce_reg_paddr,
- tx_comp_ring_base_paddr,
- tx_comp_ring_size,
- tx_num_alloc_buffer,
- rx_rdy_ring_base_paddr,
- rx_rdy_ring_size, rx_proc_done_idx_paddr,
- rx_proc_done_idx_vaddr,
- rx2_rdy_ring_base_paddr,
- rx2_rdy_ring_size, rx2_proc_done_idx2_paddr,
- rx2_proc_done_idx2_vaddr);
- }
- /**
- * ol_txrx_ipa_uc_set_doorbell_paddr() - Client set IPA UC doorbell register
- * @pdev: handle to the HTT instance
- * @ipa_uc_tx_doorbell_paddr: tx comp doorbell physical address
- * @ipa_uc_rx_doorbell_paddr: rx ready doorbell physical address
- *
- * IPA UC let know doorbell register physical address
- * WLAN firmware will use this physical address to notify IPA UC
- *
- * Return: none
- */
- void
- ol_txrx_ipa_uc_set_doorbell_paddr(ol_txrx_pdev_handle pdev,
- cdf_dma_addr_t ipa_tx_uc_doorbell_paddr,
- cdf_dma_addr_t ipa_rx_uc_doorbell_paddr)
- {
- htt_ipa_uc_set_doorbell_paddr(pdev->htt_pdev,
- ipa_tx_uc_doorbell_paddr,
- ipa_rx_uc_doorbell_paddr);
- }
- /**
- * ol_txrx_ipa_uc_set_active() - Client notify IPA UC data path active or not
- * @pdev: handle to the HTT instance
- * @ipa_uc_tx_doorbell_paddr: tx comp doorbell physical address
- * @ipa_uc_rx_doorbell_paddr: rx ready doorbell physical address
- *
- * IPA UC let know doorbell register physical address
- * WLAN firmware will use this physical address to notify IPA UC
- *
- * Return: none
- */
- void
- ol_txrx_ipa_uc_set_active(ol_txrx_pdev_handle pdev, bool uc_active, bool is_tx)
- {
- htt_h2t_ipa_uc_set_active(pdev->htt_pdev, uc_active, is_tx);
- }
- /**
- * ol_txrx_ipa_uc_fw_op_event_handler() - opcode event handler
- * @context: pdev context
- * @rxpkt: received packet
- * @staid: peer id
- *
- * Return: None
- */
- void ol_txrx_ipa_uc_fw_op_event_handler(void *context,
- void *rxpkt,
- uint16_t staid)
- {
- ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)context;
- if (cdf_unlikely(!pdev)) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: Invalid context", __func__);
- cdf_mem_free(rxpkt);
- return;
- }
- if (pdev->ipa_uc_op_cb) {
- pdev->ipa_uc_op_cb(rxpkt, pdev->osif_dev);
- } else {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: ipa_uc_op_cb NULL", __func__);
- cdf_mem_free(rxpkt);
- }
- }
- #ifdef QCA_CONFIG_SMP
- /**
- * ol_txrx_ipa_uc_op_response() - Handle OP command response from firmware
- * @pdev: handle to the HTT instance
- * @op_msg: op response message from firmware
- *
- * Return: none
- */
- void ol_txrx_ipa_uc_op_response(ol_txrx_pdev_handle pdev, uint8_t *op_msg)
- {
- p_cds_sched_context sched_ctx = get_cds_sched_ctxt();
- struct cds_ol_rx_pkt *pkt;
- if (cdf_unlikely(!sched_ctx))
- return;
- pkt = cds_alloc_ol_rx_pkt(sched_ctx);
- if (cdf_unlikely(!pkt)) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: Not able to allocate context", __func__);
- return;
- }
- pkt->callback = (cds_ol_rx_thread_cb) ol_txrx_ipa_uc_fw_op_event_handler;
- pkt->context = pdev;
- pkt->Rxpkt = (void *)op_msg;
- pkt->staId = 0;
- cds_indicate_rxpkt(sched_ctx, pkt);
- }
- #else
- void ol_txrx_ipa_uc_op_response(ol_txrx_pdev_handle pdev,
- uint8_t *op_msg)
- {
- if (pdev->ipa_uc_op_cb) {
- pdev->ipa_uc_op_cb(op_msg, pdev->osif_dev);
- } else {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: IPA callback function is not registered", __func__);
- cdf_mem_free(op_msg);
- return;
- }
- }
- #endif
- /**
- * ol_txrx_ipa_uc_register_op_cb() - Register OP handler function
- * @pdev: handle to the HTT instance
- * @op_cb: handler function pointer
- * @osif_dev: register client context
- *
- * Return: none
- */
- void ol_txrx_ipa_uc_register_op_cb(ol_txrx_pdev_handle pdev,
- ipa_uc_op_cb_type op_cb, void *osif_dev)
- {
- pdev->ipa_uc_op_cb = op_cb;
- pdev->osif_dev = osif_dev;
- }
- /**
- * ol_txrx_ipa_uc_get_stat() - Get firmware wdi status
- * @pdev: handle to the HTT instance
- *
- * Return: none
- */
- void ol_txrx_ipa_uc_get_stat(ol_txrx_pdev_handle pdev)
- {
- htt_h2t_ipa_uc_get_stats(pdev->htt_pdev);
- }
- #endif /* IPA_UC_OFFLOAD */
- void ol_txrx_display_stats(uint16_t value)
- {
- ol_txrx_pdev_handle pdev;
- pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- if (!pdev) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: pdev is NULL", __func__);
- return;
- }
- switch (value) {
- case WLAN_TXRX_STATS:
- ol_txrx_stats_display(pdev);
- break;
- case WLAN_TXRX_TSO_STATS:
- #if defined(FEATURE_TSO) && defined(FEATURE_TSO_DEBUG)
- ol_txrx_stats_display_tso(pdev);
- #else
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: TSO not supported", __func__);
- #endif
- break;
- case WLAN_DUMP_TX_FLOW_POOL_INFO:
- ol_tx_dump_flow_pool_info();
- break;
- case WLAN_TXRX_DESC_STATS:
- cdf_nbuf_tx_desc_count_display();
- break;
- default:
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: Unknown value", __func__);
- break;
- }
- }
- void ol_txrx_clear_stats(uint16_t value)
- {
- ol_txrx_pdev_handle pdev;
- pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- if (!pdev) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: pdev is NULL", __func__);
- return;
- }
- switch (value) {
- case WLAN_TXRX_STATS:
- ol_txrx_stats_clear(pdev);
- break;
- case WLAN_DUMP_TX_FLOW_POOL_INFO:
- ol_tx_clear_flow_pool_stats();
- break;
- case WLAN_TXRX_DESC_STATS:
- cdf_nbuf_tx_desc_count_clear();
- break;
- default:
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: Unknown value", __func__);
- break;
- }
- }
- /**
- * ol_rx_data_cb() - data rx callback
- * @peer: peer
- * @buf_list: buffer list
- *
- * Return: None
- */
- static void ol_rx_data_cb(struct ol_txrx_peer_t *peer,
- cdf_nbuf_t buf_list)
- {
- void *cds_ctx = cds_get_global_context();
- cdf_nbuf_t buf, next_buf;
- CDF_STATUS ret;
- ol_rx_callback_fp data_rx = NULL;
- if (cdf_unlikely(!cds_ctx))
- goto free_buf;
- cdf_spin_lock_bh(&peer->peer_info_lock);
- if (cdf_unlikely(!(peer->state >= ol_txrx_peer_state_conn))) {
- cdf_spin_unlock_bh(&peer->peer_info_lock);
- goto free_buf;
- }
- data_rx = peer->osif_rx;
- cdf_spin_unlock_bh(&peer->peer_info_lock);
- cdf_spin_lock_bh(&peer->bufq_lock);
- if (!list_empty(&peer->cached_bufq)) {
- cdf_spin_unlock_bh(&peer->bufq_lock);
- /* Flush the cached frames to HDD before passing new rx frame */
- ol_txrx_flush_rx_frames(peer, 0);
- } else
- cdf_spin_unlock_bh(&peer->bufq_lock);
- buf = buf_list;
- while (buf) {
- next_buf = cdf_nbuf_queue_next(buf);
- cdf_nbuf_set_next(buf, NULL); /* Add NULL terminator */
- ret = data_rx(cds_ctx, buf, peer->local_id);
- if (ret != CDF_STATUS_SUCCESS) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Frame Rx to HDD failed");
- cdf_nbuf_free(buf);
- }
- buf = next_buf;
- }
- return;
- free_buf:
- TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, "%s:Dropping frames", __func__);
- buf = buf_list;
- while (buf) {
- next_buf = cdf_nbuf_queue_next(buf);
- cdf_nbuf_free(buf);
- buf = next_buf;
- }
- }
- /**
- * ol_rx_data_process() - process rx frame
- * @peer: peer
- * @rx_buf_list: rx buffer list
- *
- * Return: None
- */
- void ol_rx_data_process(struct ol_txrx_peer_t *peer,
- cdf_nbuf_t rx_buf_list)
- {
- /* Firmware data path active response will use shim RX thread
- * T2H MSG running on SIRQ context,
- * IPA kernel module API should not be called on SIRQ CTXT */
- cdf_nbuf_t buf, next_buf;
- ol_rx_callback_fp data_rx = NULL;
- ol_txrx_pdev_handle pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- if ((!peer) || (!pdev)) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "peer/pdev is NULL");
- goto drop_rx_buf;
- }
- cdf_spin_lock_bh(&peer->peer_info_lock);
- if (peer->state >= ol_txrx_peer_state_conn)
- data_rx = peer->osif_rx;
- cdf_spin_unlock_bh(&peer->peer_info_lock);
- /*
- * If there is a data frame from peer before the peer is
- * registered for data service, enqueue them on to pending queue
- * which will be flushed to HDD once that station is registered.
- */
- if (!data_rx) {
- struct ol_rx_cached_buf *cache_buf;
- buf = rx_buf_list;
- while (buf) {
- next_buf = cdf_nbuf_queue_next(buf);
- cache_buf = cdf_mem_malloc(sizeof(*cache_buf));
- if (!cache_buf) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
- "Failed to allocate buf to cache the rx frames");
- cdf_nbuf_free(buf);
- } else {
- /* Add NULL terminator */
- cdf_nbuf_set_next(buf, NULL);
- cache_buf->buf = buf;
- cdf_spin_lock_bh(&peer->bufq_lock);
- list_add_tail(&cache_buf->list,
- &peer->cached_bufq);
- cdf_spin_unlock_bh(&peer->bufq_lock);
- }
- buf = next_buf;
- }
- } else {
- #ifdef QCA_CONFIG_SMP
- /*
- * If the kernel is SMP, schedule rx thread to
- * better use multicores.
- */
- if (!ol_cfg_is_rx_thread_enabled(pdev->ctrl_pdev)) {
- ol_rx_data_cb(peer, rx_buf_list);
- } else {
- p_cds_sched_context sched_ctx =
- get_cds_sched_ctxt();
- struct cds_ol_rx_pkt *pkt;
- if (unlikely(!sched_ctx))
- goto drop_rx_buf;
- pkt = cds_alloc_ol_rx_pkt(sched_ctx);
- if (!pkt) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR,
- "No available Rx message buffer");
- goto drop_rx_buf;
- }
- pkt->callback = (cds_ol_rx_thread_cb)
- ol_rx_data_cb;
- pkt->context = (void *)peer;
- pkt->Rxpkt = (void *)rx_buf_list;
- pkt->staId = peer->local_id;
- cds_indicate_rxpkt(sched_ctx, pkt);
- }
- #else /* QCA_CONFIG_SMP */
- ol_rx_data_cb(peer, rx_buf_list, 0);
- #endif /* QCA_CONFIG_SMP */
- }
- return;
- drop_rx_buf:
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Dropping rx packets");
- buf = rx_buf_list;
- while (buf) {
- next_buf = cdf_nbuf_queue_next(buf);
- cdf_nbuf_free(buf);
- buf = next_buf;
- }
- }
- /**
- * ol_txrx_register_peer() - register peer
- * @rxcb: rx callback
- * @sta_desc: sta descriptor
- *
- * Return: CDF Status
- */
- CDF_STATUS ol_txrx_register_peer(ol_rx_callback_fp rxcb,
- struct ol_txrx_desc_type *sta_desc)
- {
- struct ol_txrx_peer_t *peer;
- struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- union ol_txrx_peer_update_param_t param;
- struct privacy_exemption privacy_filter;
- if (!pdev) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Pdev is NULL");
- return CDF_STATUS_E_INVAL;
- }
- if (sta_desc->sta_id >= WLAN_MAX_STA_COUNT) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Invalid sta id :%d",
- sta_desc->sta_id);
- return CDF_STATUS_E_INVAL;
- }
- peer = ol_txrx_peer_find_by_local_id(pdev, sta_desc->sta_id);
- if (!peer)
- return CDF_STATUS_E_FAULT;
- cdf_spin_lock_bh(&peer->peer_info_lock);
- peer->osif_rx = rxcb;
- peer->state = ol_txrx_peer_state_conn;
- cdf_spin_unlock_bh(&peer->peer_info_lock);
- param.qos_capable = sta_desc->is_qos_enabled;
- ol_txrx_peer_update(peer->vdev, peer->mac_addr.raw, ¶m,
- ol_txrx_peer_update_qos_capable);
- if (sta_desc->is_wapi_supported) {
- /*Privacy filter to accept unencrypted WAI frames */
- privacy_filter.ether_type = ETHERTYPE_WAI;
- privacy_filter.filter_type = PRIVACY_FILTER_ALWAYS;
- privacy_filter.packet_type = PRIVACY_FILTER_PACKET_BOTH;
- ol_txrx_set_privacy_filters(peer->vdev, &privacy_filter, 1);
- }
- ol_txrx_flush_rx_frames(peer, 0);
- return CDF_STATUS_SUCCESS;
- }
- /**
- * ol_txrx_clear_peer() - clear peer
- * @sta_id: sta id
- *
- * Return: CDF Status
- */
- CDF_STATUS ol_txrx_clear_peer(uint8_t sta_id)
- {
- struct ol_txrx_peer_t *peer;
- struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- if (!pdev) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: Unable to find pdev!",
- __func__);
- return CDF_STATUS_E_FAILURE;
- }
- if (sta_id >= WLAN_MAX_STA_COUNT) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Invalid sta id %d", sta_id);
- return CDF_STATUS_E_INVAL;
- }
- #ifdef QCA_CONFIG_SMP
- {
- p_cds_sched_context sched_ctx = get_cds_sched_ctxt();
- /* Drop pending Rx frames in CDS */
- if (sched_ctx)
- cds_drop_rxpkt_by_staid(sched_ctx, sta_id);
- }
- #endif
- peer = ol_txrx_peer_find_by_local_id(pdev, sta_id);
- if (!peer)
- return CDF_STATUS_E_FAULT;
- /* Purge the cached rx frame queue */
- ol_txrx_flush_rx_frames(peer, 1);
- cdf_spin_lock_bh(&peer->peer_info_lock);
- peer->osif_rx = NULL;
- peer->state = ol_txrx_peer_state_disc;
- cdf_spin_unlock_bh(&peer->peer_info_lock);
- return CDF_STATUS_SUCCESS;
- }
- /**
- * ol_txrx_register_ocb_peer - Function to register the OCB peer
- * @cds_ctx: Pointer to the global OS context
- * @mac_addr: MAC address of the self peer
- * @peer_id: Pointer to the peer ID
- *
- * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE on failure
- */
- CDF_STATUS ol_txrx_register_ocb_peer(void *cds_ctx, uint8_t *mac_addr,
- uint8_t *peer_id)
- {
- ol_txrx_pdev_handle pdev;
- ol_txrx_peer_handle peer;
- if (!cds_ctx) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: Invalid context",
- __func__);
- return CDF_STATUS_E_FAILURE;
- }
- pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- if (!pdev) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: Unable to find pdev!",
- __func__);
- return CDF_STATUS_E_FAILURE;
- }
- peer = ol_txrx_find_peer_by_addr(pdev, mac_addr, peer_id);
- if (!peer) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: Unable to find OCB peer!",
- __func__);
- return CDF_STATUS_E_FAILURE;
- }
- ol_txrx_set_ocb_peer(pdev, peer);
- /* Set peer state to connected */
- ol_txrx_peer_state_update(pdev, peer->mac_addr.raw,
- ol_txrx_peer_state_auth);
- return CDF_STATUS_SUCCESS;
- }
- /**
- * ol_txrx_set_ocb_peer - Function to store the OCB peer
- * @pdev: Handle to the HTT instance
- * @peer: Pointer to the peer
- */
- void ol_txrx_set_ocb_peer(struct ol_txrx_pdev_t *pdev,
- struct ol_txrx_peer_t *peer)
- {
- if (pdev == NULL)
- return;
- pdev->ocb_peer = peer;
- pdev->ocb_peer_valid = (NULL != peer);
- }
- /**
- * ol_txrx_get_ocb_peer - Function to retrieve the OCB peer
- * @pdev: Handle to the HTT instance
- * @peer: Pointer to the returned peer
- *
- * Return: true if the peer is valid, false if not
- */
- bool ol_txrx_get_ocb_peer(struct ol_txrx_pdev_t *pdev,
- struct ol_txrx_peer_t **peer)
- {
- int rc;
- if ((pdev == NULL) || (peer == NULL)) {
- rc = false;
- goto exit;
- }
- if (pdev->ocb_peer_valid) {
- *peer = pdev->ocb_peer;
- rc = true;
- } else {
- rc = false;
- }
- exit:
- return rc;
- }
- #ifdef QCA_LL_TX_FLOW_CONTROL_V2
- /**
- * ol_txrx_register_pause_cb() - register pause callback
- * @pause_cb: pause callback
- *
- * Return: CDF status
- */
- CDF_STATUS ol_txrx_register_pause_cb(ol_tx_pause_callback_fp pause_cb)
- {
- struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- if (!pdev || !pause_cb) {
- TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "pdev or pause_cb is NULL");
- return CDF_STATUS_E_INVAL;
- }
- pdev->pause_cb = pause_cb;
- return CDF_STATUS_SUCCESS;
- }
- #endif
- #if defined(FEATURE_LRO)
- /**
- * ol_txrx_lro_flush_handler() - LRO flush handler
- * @context: dev handle
- * @rxpkt: rx data
- * @staid: station id
- *
- * This function handles an LRO flush indication.
- * If the rx thread is enabled, it will be invoked by the rx
- * thread else it will be called in the tasklet context
- *
- * Return: none
- */
- void ol_txrx_lro_flush_handler(void *context,
- void *rxpkt,
- uint16_t staid)
- {
- ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)context;
- if (cdf_unlikely(!pdev)) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: Invalid context", __func__);
- cdf_assert(0);
- return;
- }
- if (pdev->lro_info.lro_flush_cb)
- pdev->lro_info.lro_flush_cb(pdev->lro_info.lro_data);
- else
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: lro_flush_cb NULL", __func__);
- }
- /**
- * ol_txrx_lro_flush() - LRO flush callback
- * @data: opaque data pointer
- *
- * This is the callback registered with CE to trigger
- * an LRO flush
- *
- * Return: none
- */
- void ol_txrx_lro_flush(void *data)
- {
- p_cds_sched_context sched_ctx = get_cds_sched_ctxt();
- struct cds_ol_rx_pkt *pkt;
- ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)data;
- if (cdf_unlikely(!sched_ctx))
- return;
- if (!ol_cfg_is_rx_thread_enabled(pdev->ctrl_pdev)) {
- ol_txrx_lro_flush_handler((void *)pdev, NULL, 0);
- } else {
- pkt = cds_alloc_ol_rx_pkt(sched_ctx);
- if (cdf_unlikely(!pkt)) {
- CDF_TRACE(CDF_MODULE_ID_TXRX, CDF_TRACE_LEVEL_ERROR,
- "%s: Not able to allocate context", __func__);
- return;
- }
- pkt->callback =
- (cds_ol_rx_thread_cb) ol_txrx_lro_flush_handler;
- pkt->context = pdev;
- pkt->Rxpkt = NULL;
- pkt->staId = 0;
- cds_indicate_rxpkt(sched_ctx, pkt);
- }
- }
- /**
- * ol_register_lro_flush_cb() - register the LRO flush callback
- * @handler: callback function
- * @data: opaque data pointer to be passed back
- *
- * Store the LRO flush callback provided and in turn
- * register OL's LRO flush handler with CE
- *
- * Return: none
- */
- void ol_register_lro_flush_cb(void (handler)(void *), void *data)
- {
- struct ol_softc *hif_device =
- (struct ol_softc *)cds_get_context(CDF_MODULE_ID_HIF);
- struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- pdev->lro_info.lro_flush_cb = handler;
- pdev->lro_info.lro_data = data;
- ce_lro_flush_cb_register(hif_device, ol_txrx_lro_flush, pdev);
- }
- /**
- * ol_deregister_lro_flush_cb() - deregister the LRO flush
- * callback
- *
- * Remove the LRO flush callback provided and in turn
- * deregister OL's LRO flush handler with CE
- *
- * Return: none
- */
- void ol_deregister_lro_flush_cb(void)
- {
- struct ol_softc *hif_device =
- (struct ol_softc *)cds_get_context(CDF_MODULE_ID_HIF);
- struct ol_txrx_pdev_t *pdev = cds_get_context(CDF_MODULE_ID_TXRX);
- ce_lro_flush_cb_deregister(hif_device);
- pdev->lro_info.lro_flush_cb = NULL;
- pdev->lro_info.lro_data = NULL;
- }
- #endif /* FEATURE_LRO */
|