hif_napi.c 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093
  1. /*
  2. * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved.
  3. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for
  6. * any purpose with or without fee is hereby granted, provided that the
  7. * above copyright notice and this permission notice appear in all
  8. * copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  11. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  12. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  13. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  14. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  15. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  16. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  17. * PERFORMANCE OF THIS SOFTWARE.
  18. */
  19. /**
  20. * DOC: hif_napi.c
  21. *
  22. * HIF NAPI interface implementation
  23. */
  24. #include <linux/string.h> /* memset */
  25. /* Linux headers */
  26. #include <linux/cpumask.h>
  27. #include <linux/cpufreq.h>
  28. #include <linux/cpu.h>
  29. #include <linux/topology.h>
  30. #include <linux/interrupt.h>
  31. #ifdef CONFIG_SCHED_CORE_CTL
  32. #include <linux/sched/core_ctl.h>
  33. #endif
  34. #include <pld_common.h>
  35. #include <linux/pm.h>
  36. /* Driver headers */
  37. #include <hif_napi.h>
  38. #include <hif_debug.h>
  39. #include <hif_io32.h>
  40. #include <ce_api.h>
  41. #include <ce_internal.h>
  42. #include <hif_irq_affinity.h>
  43. #include "qdf_cpuhp.h"
  44. #include "qdf_module.h"
  45. #include "qdf_net_if.h"
  46. #include "qdf_dev.h"
  47. #include "qdf_irq.h"
  48. enum napi_decision_vector {
  49. HIF_NAPI_NOEVENT = 0,
  50. HIF_NAPI_INITED = 1,
  51. HIF_NAPI_CONF_UP = 2
  52. };
  53. #define ENABLE_NAPI_MASK (HIF_NAPI_INITED | HIF_NAPI_CONF_UP)
  54. #ifdef RECEIVE_OFFLOAD
  55. /**
  56. * hif_rxthread_napi_poll() - dummy napi poll for rx_thread NAPI
  57. * @napi: Rx_thread NAPI
  58. * @budget: NAPI BUDGET
  59. *
  60. * Return: 0 as it is not supposed to be polled at all as it is not scheduled.
  61. */
  62. static int hif_rxthread_napi_poll(struct napi_struct *napi, int budget)
  63. {
  64. hif_err("This napi_poll should not be polled as we don't schedule it");
  65. QDF_ASSERT(0);
  66. return 0;
  67. }
  68. /**
  69. * hif_init_rx_thread_napi() - Initialize dummy Rx_thread NAPI
  70. * @napii: Handle to napi_info holding rx_thread napi
  71. *
  72. * Return: None
  73. */
  74. static void hif_init_rx_thread_napi(struct qca_napi_info *napii)
  75. {
  76. struct qdf_net_if *nd = (struct qdf_net_if *)&napii->rx_thread_netdev;
  77. qdf_net_if_create_dummy_if(nd);
  78. qdf_netif_napi_add(&napii->rx_thread_netdev, &napii->rx_thread_napi,
  79. hif_rxthread_napi_poll, 64);
  80. qdf_napi_enable(&napii->rx_thread_napi);
  81. }
  82. /**
  83. * hif_deinit_rx_thread_napi() - Deinitialize dummy Rx_thread NAPI
  84. * @napii: Handle to napi_info holding rx_thread napi
  85. *
  86. * Return: None
  87. */
  88. static void hif_deinit_rx_thread_napi(struct qca_napi_info *napii)
  89. {
  90. qdf_netif_napi_del(&napii->rx_thread_napi);
  91. }
  92. #else /* RECEIVE_OFFLOAD */
  93. static void hif_init_rx_thread_napi(struct qca_napi_info *napii)
  94. {
  95. }
  96. static void hif_deinit_rx_thread_napi(struct qca_napi_info *napii)
  97. {
  98. }
  99. #endif
  100. /**
  101. * hif_napi_create() - creates the NAPI structures for a given CE
  102. * @hif_ctx: pointer to hif context
  103. * @poll: poll function to be used for this NAPI instance
  104. * @budget: budget to be registered with the NAPI instance
  105. * @scale: scale factor on the weight (to scaler budget to 1000)
  106. * @flags: feature flags
  107. *
  108. * Description:
  109. * Creates NAPI instances. This function is called
  110. * unconditionally during initialization. It creates
  111. * napi structures through the proper HTC/HIF calls.
  112. * The structures are disabled on creation.
  113. * Note that for each NAPI instance a separate dummy netdev is used
  114. *
  115. * Return:
  116. * < 0: error
  117. * = 0: <should never happen>
  118. * > 0: id of the created object (for multi-NAPI, number of objects created)
  119. */
  120. int hif_napi_create(struct hif_opaque_softc *hif_ctx,
  121. int (*poll)(struct napi_struct *, int),
  122. int budget,
  123. int scale,
  124. uint8_t flags)
  125. {
  126. int i;
  127. struct qca_napi_data *napid;
  128. struct qca_napi_info *napii;
  129. struct CE_state *ce_state;
  130. struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx);
  131. int rc = 0;
  132. NAPI_DEBUG("-->(budget=%d, scale=%d)",
  133. budget, scale);
  134. NAPI_DEBUG("hif->napi_data.state = 0x%08x",
  135. hif->napi_data.state);
  136. NAPI_DEBUG("hif->napi_data.ce_map = 0x%08x",
  137. hif->napi_data.ce_map);
  138. napid = &(hif->napi_data);
  139. if (0 == (napid->state & HIF_NAPI_INITED)) {
  140. memset(napid, 0, sizeof(struct qca_napi_data));
  141. qdf_spinlock_create(&(napid->lock));
  142. napid->state |= HIF_NAPI_INITED;
  143. napid->flags = flags;
  144. rc = hif_napi_cpu_init(hif_ctx);
  145. if (rc != 0 && rc != -EALREADY) {
  146. hif_err("NAPI_initialization failed(rc=%d)", rc);
  147. rc = napid->ce_map;
  148. goto hnc_err;
  149. } else
  150. rc = 0;
  151. hif_debug("NAPI structures initialized, rc=%d", rc);
  152. }
  153. for (i = 0; i < hif->ce_count; i++) {
  154. ce_state = hif->ce_id_to_state[i];
  155. NAPI_DEBUG("ce %d: htt_rx=%d htt_tx=%d",
  156. i, ce_state->htt_rx_data,
  157. ce_state->htt_tx_data);
  158. if (ce_srng_based(hif))
  159. continue;
  160. if (!ce_state->htt_rx_data)
  161. continue;
  162. /* Now this is a CE where we need NAPI on */
  163. NAPI_DEBUG("Creating NAPI on pipe %d", i);
  164. napii = qdf_mem_malloc(sizeof(*napii));
  165. napid->napis[i] = napii;
  166. if (!napii) {
  167. rc = -ENOMEM;
  168. goto napii_free;
  169. }
  170. }
  171. for (i = 0; i < hif->ce_count; i++) {
  172. napii = napid->napis[i];
  173. if (!napii)
  174. continue;
  175. NAPI_DEBUG("initializing NAPI for pipe %d", i);
  176. memset(napii, 0, sizeof(struct qca_napi_info));
  177. napii->scale = scale;
  178. napii->id = NAPI_PIPE2ID(i);
  179. napii->hif_ctx = hif_ctx;
  180. napii->irq = pld_get_irq(hif->qdf_dev->dev, i);
  181. if (napii->irq < 0)
  182. hif_warn("bad IRQ value for CE %d: %d", i, napii->irq);
  183. qdf_net_if_create_dummy_if((struct qdf_net_if *)&napii->netdev);
  184. NAPI_DEBUG("adding napi=%pK to netdev=%pK (poll=%pK, bdgt=%d)",
  185. &(napii->napi), &(napii->netdev), poll, budget);
  186. qdf_netif_napi_add(&(napii->netdev), &(napii->napi),
  187. poll, budget);
  188. NAPI_DEBUG("after napi_add");
  189. NAPI_DEBUG("napi=0x%pK, netdev=0x%pK",
  190. &(napii->napi), &(napii->netdev));
  191. NAPI_DEBUG("napi.dev_list.prev=0x%pK, next=0x%pK",
  192. napii->napi.dev_list.prev,
  193. napii->napi.dev_list.next);
  194. NAPI_DEBUG("dev.napi_list.prev=0x%pK, next=0x%pK",
  195. napii->netdev.napi_list.prev,
  196. napii->netdev.napi_list.next);
  197. hif_init_rx_thread_napi(napii);
  198. napii->lro_ctx = qdf_lro_init();
  199. NAPI_DEBUG("Registering LRO for ce_id %d NAPI callback for %d lro_ctx %pK\n",
  200. i, napii->id, napii->lro_ctx);
  201. /* It is OK to change the state variable below without
  202. * protection as there should be no-one around yet
  203. */
  204. napid->ce_map |= (0x01 << i);
  205. hif_debug("NAPI id %d created for pipe %d", napii->id, i);
  206. }
  207. /* no ces registered with the napi */
  208. if (!ce_srng_based(hif) && napid->ce_map == 0) {
  209. hif_warn("no napis created for copy engines");
  210. rc = -EFAULT;
  211. goto napii_free;
  212. }
  213. NAPI_DEBUG("napi map = %x", napid->ce_map);
  214. NAPI_DEBUG("NAPI ids created for all applicable pipes");
  215. return napid->ce_map;
  216. napii_free:
  217. for (i = 0; i < hif->ce_count; i++) {
  218. napii = napid->napis[i];
  219. napid->napis[i] = NULL;
  220. if (napii)
  221. qdf_mem_free(napii);
  222. }
  223. hnc_err:
  224. NAPI_DEBUG("<--napi_instances_map=%x]", napid->ce_map);
  225. return rc;
  226. }
  227. qdf_export_symbol(hif_napi_create);
  228. #ifdef RECEIVE_OFFLOAD
  229. void hif_napi_rx_offld_flush_cb_register(struct hif_opaque_softc *hif_hdl,
  230. void (offld_flush_handler)(void *))
  231. {
  232. int i;
  233. struct CE_state *ce_state;
  234. struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl);
  235. struct qca_napi_data *napid;
  236. struct qca_napi_info *napii;
  237. if (!scn) {
  238. hif_err("hif_state NULL!");
  239. QDF_ASSERT(0);
  240. return;
  241. }
  242. napid = hif_napi_get_all(hif_hdl);
  243. for (i = 0; i < scn->ce_count; i++) {
  244. ce_state = scn->ce_id_to_state[i];
  245. if (ce_state && (ce_state->htt_rx_data)) {
  246. napii = napid->napis[i];
  247. napii->offld_flush_cb = offld_flush_handler;
  248. hif_debug("Registering offload for ce_id %d NAPI callback for %d flush_cb %pK",
  249. i, napii->id, napii->offld_flush_cb);
  250. }
  251. }
  252. }
  253. void hif_napi_rx_offld_flush_cb_deregister(struct hif_opaque_softc *hif_hdl)
  254. {
  255. int i;
  256. struct CE_state *ce_state;
  257. struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl);
  258. struct qca_napi_data *napid;
  259. struct qca_napi_info *napii;
  260. if (!scn) {
  261. hif_err("hif_state NULL!");
  262. QDF_ASSERT(0);
  263. return;
  264. }
  265. napid = hif_napi_get_all(hif_hdl);
  266. for (i = 0; i < scn->ce_count; i++) {
  267. ce_state = scn->ce_id_to_state[i];
  268. if (ce_state && (ce_state->htt_rx_data)) {
  269. napii = napid->napis[i];
  270. hif_debug("deRegistering offld for ce_id %d NAPI callback for %d flush_cb %pK",
  271. i, napii->id, napii->offld_flush_cb);
  272. /* Not required */
  273. napii->offld_flush_cb = NULL;
  274. }
  275. }
  276. }
  277. #endif /* RECEIVE_OFFLOAD */
  278. /**
  279. * hif_napi_destroy() - destroys the NAPI structures for a given instance
  280. * @hif_ctx: pointer to hif context
  281. * @id: the CE id whose napi instance will be destroyed
  282. * @force: if set, will destroy even if entry is active (de-activates)
  283. *
  284. * Description:
  285. * Destroy a given NAPI instance. This function is called
  286. * unconditionally during cleanup.
  287. * Refuses to destroy an entry of it is still enabled (unless force=1)
  288. * Marks the whole napi_data invalid if all instances are destroyed.
  289. *
  290. * Return:
  291. * -EINVAL: specific entry has not been created
  292. * -EPERM : specific entry is still active
  293. * 0 < : error
  294. * 0 = : success
  295. */
  296. int hif_napi_destroy(struct hif_opaque_softc *hif_ctx,
  297. uint8_t id,
  298. int force)
  299. {
  300. uint8_t ce = NAPI_ID2PIPE(id);
  301. int rc = 0;
  302. struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx);
  303. NAPI_DEBUG("-->(id=%d, force=%d)", id, force);
  304. if (0 == (hif->napi_data.state & HIF_NAPI_INITED)) {
  305. hif_err("NAPI not initialized or entry %d not created", id);
  306. rc = -EINVAL;
  307. } else if (0 == (hif->napi_data.ce_map & (0x01 << ce))) {
  308. hif_err("NAPI instance %d (pipe %d) not created", id, ce);
  309. if (hif->napi_data.napis[ce])
  310. hif_err("memory allocated but ce_map not set %d (pipe %d)",
  311. id, ce);
  312. rc = -EINVAL;
  313. } else {
  314. struct qca_napi_data *napid;
  315. struct qca_napi_info *napii;
  316. napid = &(hif->napi_data);
  317. napii = napid->napis[ce];
  318. if (!napii) {
  319. if (napid->ce_map & (0x01 << ce))
  320. hif_err("napii & ce_map out of sync(ce %d)", ce);
  321. return -EINVAL;
  322. }
  323. if (hif->napi_data.state == HIF_NAPI_CONF_UP) {
  324. if (force) {
  325. qdf_napi_disable(&(napii->napi));
  326. hif_debug("NAPI entry %d force disabled", id);
  327. NAPI_DEBUG("NAPI %d force disabled", id);
  328. } else {
  329. hif_err("Cannot destroy active NAPI %d", id);
  330. rc = -EPERM;
  331. }
  332. }
  333. if (0 == rc) {
  334. NAPI_DEBUG("before napi_del");
  335. NAPI_DEBUG("napi.dlist.prv=0x%pK, next=0x%pK",
  336. napii->napi.dev_list.prev,
  337. napii->napi.dev_list.next);
  338. NAPI_DEBUG("dev.napi_l.prv=0x%pK, next=0x%pK",
  339. napii->netdev.napi_list.prev,
  340. napii->netdev.napi_list.next);
  341. qdf_lro_deinit(napii->lro_ctx);
  342. qdf_netif_napi_del(&(napii->napi));
  343. hif_deinit_rx_thread_napi(napii);
  344. napid->ce_map &= ~(0x01 << ce);
  345. napid->napis[ce] = NULL;
  346. napii->scale = 0;
  347. qdf_mem_free(napii);
  348. hif_debug("NAPI %d destroyed", id);
  349. /* if there are no active instances and
  350. * if they are all destroyed,
  351. * set the whole structure to uninitialized state
  352. */
  353. if (napid->ce_map == 0) {
  354. rc = hif_napi_cpu_deinit(hif_ctx);
  355. /* caller is tolerant to receiving !=0 rc */
  356. qdf_spinlock_destroy(&(napid->lock));
  357. memset(napid,
  358. 0, sizeof(struct qca_napi_data));
  359. hif_debug("no NAPI instances. Zapped");
  360. }
  361. }
  362. }
  363. return rc;
  364. }
  365. qdf_export_symbol(hif_napi_destroy);
  366. #ifdef FEATURE_LRO
  367. void *hif_napi_get_lro_info(struct hif_opaque_softc *hif_hdl, int napi_id)
  368. {
  369. struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl);
  370. struct qca_napi_data *napid;
  371. struct qca_napi_info *napii;
  372. napid = &(scn->napi_data);
  373. napii = napid->napis[NAPI_ID2PIPE(napi_id)];
  374. if (napii)
  375. return napii->lro_ctx;
  376. return 0;
  377. }
  378. #endif
  379. /**
  380. * hif_napi_get_all() - returns the address of the whole HIF NAPI structure
  381. * @hif_ctx: pointer to hif context
  382. *
  383. * Description:
  384. * Returns the address of the whole structure
  385. *
  386. * Return:
  387. * <addr>: address of the whole HIF NAPI structure
  388. */
  389. inline struct qca_napi_data *hif_napi_get_all(struct hif_opaque_softc *hif_ctx)
  390. {
  391. struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx);
  392. return &(hif->napi_data);
  393. }
  394. struct qca_napi_info *hif_get_napi(int napi_id, struct qca_napi_data *napid)
  395. {
  396. int id = NAPI_ID2PIPE(napi_id);
  397. return napid->napis[id];
  398. }
  399. /**
  400. * hif_napi_event() - reacts to events that impact NAPI
  401. * @hif_ctx: pointer to hif context
  402. * @event: event that has been detected
  403. * @data: more data regarding the event
  404. *
  405. * Description:
  406. * This function handles two types of events:
  407. * 1- Events that change the state of NAPI (enabled/disabled):
  408. * {NAPI_EVT_INI_FILE, NAPI_EVT_CMD_STATE}
  409. * The state is retrievable by "hdd_napi_enabled(-1)"
  410. * - NAPI will be on if either INI file is on and it has not been disabled
  411. * by a subsequent vendor CMD,
  412. * or it has been enabled by a vendor CMD.
  413. * 2- Events that change the CPU affinity of a NAPI instance/IRQ:
  414. * {NAPI_EVT_TPUT_STATE, NAPI_EVT_CPU_STATE}
  415. * - NAPI will support a throughput mode (HI/LO), kept at napid->napi_mode
  416. * - NAPI will switch throughput mode based on hdd_napi_throughput_policy()
  417. * - In LO tput mode, NAPI will yield control if its interrupts to the system
  418. * management functions. However in HI throughput mode, NAPI will actively
  419. * manage its interrupts/instances (by trying to disperse them out to
  420. * separate performance cores).
  421. * - CPU eligibility is kept up-to-date by NAPI_EVT_CPU_STATE events.
  422. *
  423. * + In some cases (roaming peer management is the only case so far), a
  424. * a client can trigger a "SERIALIZE" event. Basically, this means that the
  425. * users is asking NAPI to go into a truly single execution context state.
  426. * So, NAPI indicates to msm-irqbalancer that it wants to be denylisted,
  427. * (if called for the first time) and then moves all IRQs (for NAPI
  428. * instances) to be collapsed to a single core. If called multiple times,
  429. * it will just re-collapse the CPUs. This is because denylist-on() API
  430. * is reference-counted, and because the API has already been called.
  431. *
  432. * Such a user, should call "DESERIALIZE" (NORMAL) event, to set NAPI to go
  433. * to its "normal" operation. Optionally, they can give a timeout value (in
  434. * multiples of BusBandwidthCheckPeriod -- 100 msecs by default). In this
  435. * case, NAPI will just set the current throughput state to uninitialized
  436. * and set the delay period. Once policy handler is called, it would skip
  437. * applying the policy delay period times, and otherwise apply the policy.
  438. *
  439. * Return:
  440. * < 0: some error
  441. * = 0: event handled successfully
  442. */
  443. int hif_napi_event(struct hif_opaque_softc *hif_ctx, enum qca_napi_event event,
  444. void *data)
  445. {
  446. int rc = 0;
  447. uint32_t prev_state;
  448. int i;
  449. bool state_changed;
  450. struct napi_struct *napi;
  451. struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx);
  452. struct qca_napi_data *napid = &(hif->napi_data);
  453. enum qca_napi_tput_state tput_mode = QCA_NAPI_TPUT_UNINITIALIZED;
  454. enum {
  455. DENYLIST_NOT_PENDING,
  456. DENYLIST_ON_PENDING,
  457. DENYLIST_OFF_PENDING
  458. } denylist_pending = DENYLIST_NOT_PENDING;
  459. NAPI_DEBUG("%s: -->(event=%d, aux=%pK)", __func__, event, data);
  460. if (ce_srng_based(hif))
  461. return hif_exec_event(hif_ctx, event, data);
  462. if ((napid->state & HIF_NAPI_INITED) == 0) {
  463. NAPI_DEBUG("%s: got event when NAPI not initialized",
  464. __func__);
  465. return -EINVAL;
  466. }
  467. qdf_spin_lock_bh(&(napid->lock));
  468. prev_state = napid->state;
  469. switch (event) {
  470. case NAPI_EVT_INI_FILE:
  471. case NAPI_EVT_CMD_STATE:
  472. case NAPI_EVT_INT_STATE: {
  473. int on = (data != ((void *)0));
  474. hif_debug("recved evnt: STATE_CMD %d; v = %d (state=0x%0x)",
  475. event, on, prev_state);
  476. if (on)
  477. if (prev_state & HIF_NAPI_CONF_UP) {
  478. hif_debug("Duplicate NAPI conf ON msg");
  479. } else {
  480. hif_debug("Setting state to ON");
  481. napid->state |= HIF_NAPI_CONF_UP;
  482. }
  483. else /* off request */
  484. if (prev_state & HIF_NAPI_CONF_UP) {
  485. hif_debug("Setting state to OFF");
  486. napid->state &= ~HIF_NAPI_CONF_UP;
  487. } else {
  488. hif_debug("Duplicate NAPI conf OFF msg");
  489. }
  490. break;
  491. }
  492. /* case NAPI_INIT_FILE/CMD_STATE */
  493. case NAPI_EVT_CPU_STATE: {
  494. int cpu = ((unsigned long int)data >> 16);
  495. int val = ((unsigned long int)data & 0x0ff);
  496. NAPI_DEBUG("%s: evt=CPU_STATE on CPU %d value=%d",
  497. __func__, cpu, val);
  498. /* state has already been set by hnc_cpu_notify_cb */
  499. if ((val == QCA_NAPI_CPU_DOWN) &&
  500. (napid->napi_mode == QCA_NAPI_TPUT_HI) && /* we manage */
  501. (napid->napi_cpu[cpu].napis != 0)) {
  502. NAPI_DEBUG("%s: Migrating NAPIs out of cpu %d",
  503. __func__, cpu);
  504. rc = hif_napi_cpu_migrate(napid,
  505. cpu,
  506. HNC_ACT_RELOCATE);
  507. napid->napi_cpu[cpu].napis = 0;
  508. }
  509. /* in QCA_NAPI_TPUT_LO case, napis MUST == 0 */
  510. break;
  511. }
  512. case NAPI_EVT_TPUT_STATE: {
  513. tput_mode = (enum qca_napi_tput_state)data;
  514. if (tput_mode == QCA_NAPI_TPUT_LO) {
  515. /* from TPUT_HI -> TPUT_LO */
  516. NAPI_DEBUG("%s: Moving to napi_tput_LO state",
  517. __func__);
  518. denylist_pending = DENYLIST_OFF_PENDING;
  519. /*
  520. * Ideally we should "collapse" interrupts here, since
  521. * we are "dispersing" interrupts in the "else" case.
  522. * This allows the possibility that our interrupts may
  523. * still be on the perf cluster the next time we enter
  524. * high tput mode. However, the irq_balancer is free
  525. * to move our interrupts to power cluster once
  526. * denylisting has been turned off in the "else" case.
  527. */
  528. } else {
  529. /* from TPUT_LO -> TPUT->HI */
  530. NAPI_DEBUG("%s: Moving to napi_tput_HI state",
  531. __func__);
  532. rc = hif_napi_cpu_migrate(napid,
  533. HNC_ANY_CPU,
  534. HNC_ACT_DISPERSE);
  535. denylist_pending = DENYLIST_ON_PENDING;
  536. }
  537. napid->napi_mode = tput_mode;
  538. break;
  539. }
  540. case NAPI_EVT_USR_SERIAL: {
  541. unsigned long users = (unsigned long)data;
  542. NAPI_DEBUG("%s: User forced SERIALIZATION; users=%ld",
  543. __func__, users);
  544. rc = hif_napi_cpu_migrate(napid,
  545. HNC_ANY_CPU,
  546. HNC_ACT_COLLAPSE);
  547. if ((users == 0) && (rc == 0))
  548. denylist_pending = DENYLIST_ON_PENDING;
  549. break;
  550. }
  551. case NAPI_EVT_USR_NORMAL: {
  552. NAPI_DEBUG("%s: User forced DE-SERIALIZATION", __func__);
  553. if (!napid->user_cpu_affin_mask)
  554. denylist_pending = DENYLIST_OFF_PENDING;
  555. /*
  556. * Deserialization timeout is handled at hdd layer;
  557. * just mark current mode to uninitialized to ensure
  558. * it will be set when the delay is over
  559. */
  560. napid->napi_mode = QCA_NAPI_TPUT_UNINITIALIZED;
  561. break;
  562. }
  563. default: {
  564. hif_err("Unknown event: %d (data=0x%0lx)",
  565. event, (unsigned long) data);
  566. break;
  567. } /* default */
  568. }; /* switch */
  569. switch (denylist_pending) {
  570. case DENYLIST_ON_PENDING:
  571. /* assume the control of WLAN IRQs */
  572. hif_napi_cpu_denylist(napid, DENYLIST_ON);
  573. break;
  574. case DENYLIST_OFF_PENDING:
  575. /* yield the control of WLAN IRQs */
  576. hif_napi_cpu_denylist(napid, DENYLIST_OFF);
  577. break;
  578. default: /* nothing to do */
  579. break;
  580. } /* switch denylist_pending */
  581. /* we want to perform the comparison in lock:
  582. * there is a possibility of hif_napi_event get called
  583. * from two different contexts (driver unload and cpu hotplug
  584. * notification) and napid->state get changed
  585. * in driver unload context and can lead to race condition
  586. * in cpu hotplug context. Therefore, perform the napid->state
  587. * comparison before releasing lock.
  588. */
  589. state_changed = (prev_state != napid->state);
  590. qdf_spin_unlock_bh(&(napid->lock));
  591. if (state_changed) {
  592. if (napid->state == ENABLE_NAPI_MASK) {
  593. rc = 1;
  594. for (i = 0; i < CE_COUNT_MAX; i++) {
  595. struct qca_napi_info *napii = napid->napis[i];
  596. if (napii) {
  597. napi = &(napii->napi);
  598. NAPI_DEBUG("%s: enabling NAPI %d",
  599. __func__, i);
  600. qdf_napi_enable(napi);
  601. }
  602. }
  603. } else {
  604. rc = 0;
  605. for (i = 0; i < CE_COUNT_MAX; i++) {
  606. struct qca_napi_info *napii = napid->napis[i];
  607. if (napii) {
  608. napi = &(napii->napi);
  609. NAPI_DEBUG("%s: disabling NAPI %d",
  610. __func__, i);
  611. qdf_napi_disable(napi);
  612. /* in case it is affined, remove it */
  613. qdf_dev_set_irq_affinity(napii->irq,
  614. NULL);
  615. }
  616. }
  617. }
  618. } else {
  619. hif_debug("no change in hif napi state (still %d)", prev_state);
  620. }
  621. NAPI_DEBUG("<--[rc=%d]", rc);
  622. return rc;
  623. }
  624. qdf_export_symbol(hif_napi_event);
  625. /**
  626. * hif_napi_enabled() - checks whether NAPI is enabled for given ce or not
  627. * @hif_ctx: hif context
  628. * @ce: CE instance (or -1, to check if any CEs are enabled)
  629. *
  630. * Return: bool
  631. */
  632. int hif_napi_enabled(struct hif_opaque_softc *hif_ctx, int ce)
  633. {
  634. int rc;
  635. struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx);
  636. if (-1 == ce)
  637. rc = ((hif->napi_data.state == ENABLE_NAPI_MASK));
  638. else
  639. rc = ((hif->napi_data.state == ENABLE_NAPI_MASK) &&
  640. (hif->napi_data.ce_map & (0x01 << ce)));
  641. return rc;
  642. }
  643. qdf_export_symbol(hif_napi_enabled);
  644. /**
  645. * hif_napi_created() - checks whether NAPI is created for given ce or not
  646. * @hif_ctx: hif context
  647. * @ce: CE instance
  648. *
  649. * Return: bool
  650. */
  651. bool hif_napi_created(struct hif_opaque_softc *hif_ctx, int ce)
  652. {
  653. int rc;
  654. struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx);
  655. rc = (hif->napi_data.ce_map & (0x01 << ce));
  656. return !!rc;
  657. }
  658. qdf_export_symbol(hif_napi_created);
  659. /**
  660. * hif_napi_enable_irq() - enables bus interrupts after napi_complete
  661. *
  662. * @hif: hif context
  663. * @id: id of NAPI instance calling this (used to determine the CE)
  664. *
  665. * Return: void
  666. */
  667. inline void hif_napi_enable_irq(struct hif_opaque_softc *hif, int id)
  668. {
  669. struct hif_softc *scn = HIF_GET_SOFTC(hif);
  670. hif_irq_enable(scn, NAPI_ID2PIPE(id));
  671. }
  672. #if defined(QCA_WIFI_WCN6450) && defined(HIF_LATENCY_PROFILE_ENABLE)
  673. /*
  674. * hif_napi_latency_profile_start() - update the schedule start timestamp
  675. *
  676. * @scn: HIF context
  677. * ce_id: Copyengine id
  678. *
  679. * Return: None
  680. */
  681. static inline void hif_napi_latency_profile_start(struct hif_softc *scn,
  682. int ce_id)
  683. {
  684. struct qca_napi_info *napii;
  685. napii = scn->napi_data.napis[ce_id];
  686. if (napii)
  687. napii->tstamp = qdf_ktime_to_ms(qdf_ktime_get());
  688. }
  689. /*
  690. * hif_napi_latency_profile_measure() - calculate the NAPI schedule latency
  691. * and update histogram
  692. *
  693. * @napi_info: pointer to qca_napi_info for the napi instance
  694. *
  695. * Return: None
  696. */
  697. static void hif_napi_latency_profile_measure(struct qca_napi_info *napi_info)
  698. {
  699. int64_t cur_tstamp;
  700. int64_t time_elapsed;
  701. cur_tstamp = qdf_ktime_to_ms(qdf_ktime_get());
  702. if (cur_tstamp > napi_info->tstamp)
  703. time_elapsed = (cur_tstamp - napi_info->tstamp);
  704. else
  705. time_elapsed = ~0x0 - (napi_info->tstamp - cur_tstamp);
  706. napi_info->tstamp = cur_tstamp;
  707. if (time_elapsed <= HIF_SCHED_LATENCY_BUCKET_0_2)
  708. napi_info->sched_latency_stats[0]++;
  709. else if (time_elapsed <= HIF_SCHED_LATENCY_BUCKET_3_10)
  710. napi_info->sched_latency_stats[1]++;
  711. else if (time_elapsed <= HIF_SCHED_LATENCY_BUCKET_11_20)
  712. napi_info->sched_latency_stats[2]++;
  713. else if (time_elapsed <= HIF_SCHED_LATENCY_BUCKET_21_50)
  714. napi_info->sched_latency_stats[3]++;
  715. else if (time_elapsed <= HIF_SCHED_LATENCY_BUCKET_51_100)
  716. napi_info->sched_latency_stats[4]++;
  717. else if (time_elapsed <= HIF_SCHED_LATENCY_BUCKET_101_250)
  718. napi_info->sched_latency_stats[5]++;
  719. else if (time_elapsed <= HIF_SCHED_LATENCY_BUCKET_251_500)
  720. napi_info->sched_latency_stats[6]++;
  721. else
  722. napi_info->sched_latency_stats[7]++;
  723. }
  724. static void hif_print_napi_latency_stats(struct qca_napi_info *napii, int ce_id)
  725. {
  726. int i;
  727. int64_t cur_tstamp;
  728. const char time_str[HIF_SCHED_LATENCY_BUCKETS][15] = {
  729. "0-2 ms",
  730. "3-10 ms",
  731. "11-20 ms",
  732. "21-50 ms",
  733. "51-100 ms",
  734. "101-250 ms",
  735. "251-500 ms",
  736. "> 500 ms"
  737. };
  738. cur_tstamp = qdf_ktime_to_ms(qdf_ktime_get());
  739. QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO_HIGH,
  740. "Current timestamp: %lld", cur_tstamp);
  741. QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO_HIGH,
  742. "ce id %d Last serviced timestamp: %lld",
  743. ce_id, napii->tstamp);
  744. QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO_HIGH,
  745. "Latency Bucket | Time elapsed");
  746. for (i = 0; i < HIF_SCHED_LATENCY_BUCKETS; i++)
  747. QDF_TRACE(QDF_MODULE_ID_HIF,
  748. QDF_TRACE_LEVEL_INFO_HIGH,
  749. "%s | %lld",
  750. time_str[i],
  751. napii->sched_latency_stats[i]);
  752. }
  753. #else
  754. static inline void
  755. hif_napi_latency_profile_start(struct hif_softc *scn, int ce_id)
  756. {
  757. }
  758. static inline void
  759. hif_napi_latency_profile_measure(struct qca_napi_info *napi_info)
  760. {
  761. }
  762. static inline void
  763. hif_print_napi_latency_stats(struct qca_napi_info *napii, int ce_id)
  764. {
  765. }
  766. #endif
  767. #ifdef QCA_WIFI_WCN6450
  768. #ifdef WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT
  769. /**
  770. * hif_napi_update_service_start_time() - Update NAPI poll start time
  771. *
  772. * @napi_info: per NAPI instance data structure
  773. *
  774. * The function is called at the beginning of a NAPI poll to record the poll
  775. * start time.
  776. *
  777. * Return: None
  778. */
  779. static inline void
  780. hif_napi_update_service_start_time(struct qca_napi_info *napi_info)
  781. {
  782. napi_info->poll_start_time = qdf_time_sched_clock();
  783. }
  784. /**
  785. * hif_napi_fill_poll_time_histogram() - fills poll time histogram for a NAPI
  786. *
  787. * @napi_info: per NAPI instance data structure
  788. *
  789. * The function is called at the end of a NAPI poll to calculate poll time
  790. * buckets.
  791. *
  792. * Return: void
  793. */
  794. static void hif_napi_fill_poll_time_histogram(struct qca_napi_info *napi_info)
  795. {
  796. struct qca_napi_stat *napi_stat;
  797. unsigned long long poll_time_ns;
  798. uint32_t poll_time_us;
  799. uint32_t bucket_size_us = 500;
  800. uint32_t bucket;
  801. uint32_t cpu_id = qdf_get_cpu();
  802. poll_time_ns = qdf_time_sched_clock() - napi_info->poll_start_time;
  803. poll_time_us = qdf_do_div(poll_time_ns, 1000);
  804. napi_stat = &napi_info->stats[cpu_id];
  805. if (poll_time_ns > napi_info->stats[cpu_id].napi_max_poll_time)
  806. napi_info->stats[cpu_id].napi_max_poll_time = poll_time_ns;
  807. bucket = poll_time_us / bucket_size_us;
  808. if (bucket >= QCA_NAPI_NUM_BUCKETS)
  809. bucket = QCA_NAPI_NUM_BUCKETS - 1;
  810. ++napi_stat->poll_time_buckets[bucket];
  811. }
  812. /*
  813. * hif_get_poll_times_hist_str() - Get HIF poll times histogram string
  814. * @stats: NAPI stats to get poll time buckets
  815. * @buf: buffer to fill histogram string
  816. * @buf_len: length of the buffer
  817. *
  818. * Return: void
  819. */
  820. static void hif_get_poll_times_hist_str(struct qca_napi_stat *stats, char *buf,
  821. uint8_t buf_len)
  822. {
  823. int i;
  824. int str_index = 0;
  825. for (i = 0; i < QCA_NAPI_NUM_BUCKETS; i++)
  826. str_index += qdf_scnprintf(buf + str_index, buf_len - str_index,
  827. "%u|", stats->poll_time_buckets[i]);
  828. }
  829. void hif_print_napi_stats(struct hif_opaque_softc *hif_ctx)
  830. {
  831. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  832. struct qca_napi_info *napii;
  833. struct qca_napi_stat *napi_stats;
  834. int ce_id, cpu;
  835. /*
  836. * Max value of uint_32 (poll_time_bucket) = 4294967295
  837. * Thus we need 10 chars + 1 space =11 chars for each bucket value.
  838. * +1 space for '\0'.
  839. */
  840. char hist_str[(QCA_NAPI_NUM_BUCKETS * 11) + 1] = {'\0'};
  841. QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO_HIGH,
  842. "NAPI[#]CPU[#] |scheds |polls |comps |dones |t-lim |max(us)|hist(500us buckets)");
  843. for (ce_id = 0; ce_id < CE_COUNT_MAX; ce_id++) {
  844. if (!hif_napi_enabled(hif_ctx, ce_id))
  845. continue;
  846. napii = scn->napi_data.napis[ce_id];
  847. if (napii) {
  848. for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
  849. napi_stats = &napii->stats[cpu];
  850. hif_get_poll_times_hist_str(napi_stats,
  851. hist_str,
  852. sizeof(hist_str));
  853. if (napi_stats->napi_schedules != 0)
  854. QDF_TRACE(QDF_MODULE_ID_HIF,
  855. QDF_TRACE_LEVEL_INFO_HIGH,
  856. "NAPI[%d]CPU[%d]: %7u %7u %7u %7u %7u %7llu %s",
  857. ce_id, cpu,
  858. napi_stats->napi_schedules,
  859. napi_stats->napi_polls,
  860. napi_stats->napi_completes,
  861. napi_stats->napi_workdone,
  862. napi_stats->time_limit_reached,
  863. qdf_do_div(napi_stats->napi_max_poll_time, 1000),
  864. hist_str);
  865. }
  866. hif_print_napi_latency_stats(napii, ce_id);
  867. }
  868. }
  869. }
  870. #else
  871. static inline void
  872. hif_napi_update_service_start_time(struct qca_napi_info *napi_info)
  873. {
  874. }
  875. static inline void
  876. hif_napi_fill_poll_time_histogram(struct qca_napi_info *napi_info)
  877. {
  878. }
  879. void hif_print_napi_stats(struct hif_opaque_softc *hif_ctx)
  880. {
  881. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  882. struct qca_napi_info *napii;
  883. struct qca_napi_stat *napi_stats;
  884. int ce_id, cpu;
  885. QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_FATAL,
  886. "NAPI[#ctx]CPU[#] |schedules |polls |completes |workdone");
  887. for (ce_id = 0; ce_id < CE_COUNT_MAX; ce_id++) {
  888. if (!hif_napi_enabled(hif_ctx, ce_id))
  889. continue;
  890. napii = scn->napi_data.napis[ce_id];
  891. if (napii) {
  892. for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
  893. napi_stats = &napii->stats[cpu];
  894. if (napi_stats->napi_schedules != 0)
  895. QDF_TRACE(QDF_MODULE_ID_HIF,
  896. QDF_TRACE_LEVEL_FATAL,
  897. "NAPI[%2d]CPU[%d]: "
  898. "%7d %7d %7d %7d ",
  899. ce_id, cpu,
  900. napi_stats->napi_schedules,
  901. napi_stats->napi_polls,
  902. napi_stats->napi_completes,
  903. napi_stats->napi_workdone);
  904. }
  905. hif_print_napi_latency_stats(napii, ce_id);
  906. }
  907. }
  908. }
  909. #endif
  910. #ifdef HIF_LATENCY_PROFILE_ENABLE
  911. void hif_clear_napi_stats(struct hif_opaque_softc *hif_ctx)
  912. {
  913. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  914. struct qca_napi_info *napii;
  915. int ce_id;
  916. for (ce_id = 0; ce_id < CE_COUNT_MAX; ce_id++) {
  917. if (!hif_napi_enabled(hif_ctx, ce_id))
  918. continue;
  919. napii = scn->napi_data.napis[ce_id];
  920. if (napii)
  921. qdf_mem_set(napii->sched_latency_stats,
  922. sizeof(napii->sched_latency_stats), 0);
  923. }
  924. }
  925. #else
  926. inline void hif_clear_napi_stats(struct hif_opaque_softc *hif_ctx)
  927. {
  928. }
  929. #endif /* HIF_LATENCY_PROFILE_ENABLE */
  930. #else
  931. static inline void
  932. hif_napi_update_service_start_time(struct qca_napi_info *napi_info)
  933. {
  934. }
  935. static inline void
  936. hif_napi_fill_poll_time_histogram(struct qca_napi_info *napi_info)
  937. {
  938. }
  939. #endif
  940. /**
  941. * hif_napi_schedule() - schedules napi, updates stats
  942. * @hif_ctx: hif context
  943. * @ce_id: index of napi instance
  944. *
  945. * Return: false if napi didn't enable or already scheduled, otherwise true
  946. */
  947. bool hif_napi_schedule(struct hif_opaque_softc *hif_ctx, int ce_id)
  948. {
  949. int cpu = smp_processor_id();
  950. struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
  951. struct qca_napi_info *napii;
  952. napii = scn->napi_data.napis[ce_id];
  953. if (qdf_unlikely(!napii)) {
  954. hif_err("scheduling unallocated napi (ce:%d)", ce_id);
  955. qdf_atomic_dec(&scn->active_tasklet_cnt);
  956. return false;
  957. }
  958. if (test_bit(NAPI_STATE_SCHED, &napii->napi.state)) {
  959. NAPI_DEBUG("napi scheduled, return");
  960. qdf_atomic_dec(&scn->active_tasklet_cnt);
  961. return false;
  962. }
  963. hif_record_ce_desc_event(scn, ce_id, NAPI_SCHEDULE,
  964. NULL, NULL, 0, 0);
  965. napii->stats[cpu].napi_schedules++;
  966. NAPI_DEBUG("scheduling napi %d (ce:%d)", napii->id, ce_id);
  967. hif_napi_latency_profile_start(scn, ce_id);
  968. napi_schedule(&(napii->napi));
  969. return true;
  970. }
  971. qdf_export_symbol(hif_napi_schedule);
  972. /**
  973. * hif_napi_correct_cpu() - correct the interrupt affinity for napi if needed
  974. * @napi_info: pointer to qca_napi_info for the napi instance
  975. *
  976. * Return: true => interrupt already on correct cpu, no correction needed
  977. * false => interrupt on wrong cpu, correction done for cpu affinity
  978. * of the interrupt
  979. */
  980. static inline
  981. bool hif_napi_correct_cpu(struct qca_napi_info *napi_info)
  982. {
  983. bool right_cpu = true;
  984. int rc = 0;
  985. int cpu;
  986. struct qca_napi_data *napid;
  987. QDF_STATUS ret;
  988. napid = hif_napi_get_all(GET_HIF_OPAQUE_HDL(napi_info->hif_ctx));
  989. if (napid->flags & QCA_NAPI_FEATURE_CPU_CORRECTION) {
  990. cpu = qdf_get_cpu();
  991. if (unlikely((hif_napi_cpu_denylist(napid,
  992. DENYLIST_QUERY) > 0) &&
  993. cpu != napi_info->cpu)) {
  994. right_cpu = false;
  995. NAPI_DEBUG("interrupt on wrong CPU, correcting");
  996. napi_info->cpumask.bits[0] = (0x01 << napi_info->cpu);
  997. qdf_dev_modify_irq_status(napi_info->irq,
  998. QDF_IRQ_NO_BALANCING, 0);
  999. ret = qdf_dev_set_irq_affinity(napi_info->irq,
  1000. (struct qdf_cpu_mask *)
  1001. &napi_info->cpumask);
  1002. rc = qdf_status_to_os_return(ret);
  1003. qdf_dev_modify_irq_status(napi_info->irq, 0,
  1004. QDF_IRQ_NO_BALANCING);
  1005. if (rc)
  1006. hif_err("Setting irq affinity hint: %d", rc);
  1007. else
  1008. napi_info->stats[cpu].cpu_corrected++;
  1009. }
  1010. }
  1011. return right_cpu;
  1012. }
  1013. #ifdef RECEIVE_OFFLOAD
  1014. /**
  1015. * hif_napi_offld_flush_cb() - Call upper layer flush callback
  1016. * @napi_info: Handle to hif_napi_info
  1017. *
  1018. * Return: None
  1019. */
  1020. static void hif_napi_offld_flush_cb(struct qca_napi_info *napi_info)
  1021. {
  1022. if (napi_info->offld_flush_cb)
  1023. napi_info->offld_flush_cb(napi_info);
  1024. }
  1025. #else
  1026. static void hif_napi_offld_flush_cb(struct qca_napi_info *napi_info)
  1027. {
  1028. }
  1029. #endif
  1030. /**
  1031. * hif_napi_poll() - NAPI poll routine
  1032. * @hif_ctx: HIF context
  1033. * @napi: pointer to NAPI struct as kernel holds it
  1034. * @budget:
  1035. *
  1036. * This is the body of the poll function.
  1037. * The poll function is called by kernel. So, there is a wrapper
  1038. * function in HDD, which in turn calls this function.
  1039. * Two main reasons why the whole thing is not implemented in HDD:
  1040. * a) references to things like ce_service that HDD is not aware of
  1041. * b) proximity to the implementation of ce_tasklet, which the body
  1042. * of this function should be very close to.
  1043. *
  1044. * NOTE TO THE MAINTAINER:
  1045. * Consider this function and ce_tasklet very tightly coupled pairs.
  1046. * Any changes to ce_tasklet or this function may likely need to be
  1047. * reflected in the counterpart.
  1048. *
  1049. * Returns:
  1050. * int: the amount of work done in this poll (<= budget)
  1051. */
  1052. int hif_napi_poll(struct hif_opaque_softc *hif_ctx,
  1053. struct napi_struct *napi,
  1054. int budget)
  1055. {
  1056. int rc = 0; /* default: no work done, also takes care of error */
  1057. int normalized = 0;
  1058. int bucket;
  1059. int cpu = smp_processor_id();
  1060. bool poll_on_right_cpu;
  1061. struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx);
  1062. struct qca_napi_info *napi_info;
  1063. struct CE_state *ce_state = NULL;
  1064. if (unlikely(!hif)) {
  1065. hif_err("hif context is NULL");
  1066. QDF_ASSERT(0);
  1067. goto out;
  1068. }
  1069. napi_info = (struct qca_napi_info *)
  1070. container_of(napi, struct qca_napi_info, napi);
  1071. hif_napi_update_service_start_time(napi_info);
  1072. hif_napi_latency_profile_measure(napi_info);
  1073. NAPI_DEBUG("%s -->(napi(%d, irq=%d), budget=%d)",
  1074. __func__, napi_info->id, napi_info->irq, budget);
  1075. napi_info->stats[cpu].napi_polls++;
  1076. hif_record_ce_desc_event(hif, NAPI_ID2PIPE(napi_info->id),
  1077. NAPI_POLL_ENTER, NULL, NULL, cpu, 0);
  1078. rc = ce_per_engine_service(hif, NAPI_ID2PIPE(napi_info->id));
  1079. NAPI_DEBUG("%s: ce_per_engine_service processed %d msgs",
  1080. __func__, rc);
  1081. hif_napi_offld_flush_cb(napi_info);
  1082. /* do not return 0, if there was some work done,
  1083. * even if it is below the scale
  1084. */
  1085. if (rc) {
  1086. napi_info->stats[cpu].napi_workdone += rc;
  1087. normalized = (rc / napi_info->scale);
  1088. if (normalized == 0)
  1089. normalized++;
  1090. bucket = (normalized - 1) /
  1091. (QCA_NAPI_BUDGET / QCA_NAPI_NUM_BUCKETS);
  1092. if (bucket >= QCA_NAPI_NUM_BUCKETS) {
  1093. bucket = QCA_NAPI_NUM_BUCKETS - 1;
  1094. hif_err("Bad bucket#(%d) > QCA_NAPI_NUM_BUCKETS(%d)"
  1095. " normalized %d, napi budget %d",
  1096. bucket, QCA_NAPI_NUM_BUCKETS,
  1097. normalized, QCA_NAPI_BUDGET);
  1098. }
  1099. napi_info->stats[cpu].napi_budget_uses[bucket]++;
  1100. } else {
  1101. /* if ce_per engine reports 0, then poll should be terminated */
  1102. NAPI_DEBUG("%s:%d: nothing processed by CE. Completing NAPI",
  1103. __func__, __LINE__);
  1104. }
  1105. ce_state = hif->ce_id_to_state[NAPI_ID2PIPE(napi_info->id)];
  1106. /*
  1107. * Not using the API hif_napi_correct_cpu directly in the if statement
  1108. * below since the API may not get evaluated if put at the end if any
  1109. * prior condition would evaluate to be true. The CPU correction
  1110. * check should kick in every poll.
  1111. */
  1112. #ifdef NAPI_YIELD_BUDGET_BASED
  1113. if (ce_state && (ce_state->force_break || 0 == rc)) {
  1114. #else
  1115. poll_on_right_cpu = hif_napi_correct_cpu(napi_info);
  1116. if ((ce_state) &&
  1117. (!ce_check_rx_pending(ce_state) || (0 == rc) ||
  1118. !poll_on_right_cpu)) {
  1119. #endif
  1120. napi_info->stats[cpu].napi_completes++;
  1121. #ifdef NAPI_YIELD_BUDGET_BASED
  1122. ce_state->force_break = 0;
  1123. #endif
  1124. hif_record_ce_desc_event(hif, ce_state->id, NAPI_COMPLETE,
  1125. NULL, NULL, 0, 0);
  1126. if (normalized >= budget)
  1127. normalized = budget - 1;
  1128. napi_complete(napi);
  1129. /* enable interrupts */
  1130. hif_napi_enable_irq(hif_ctx, napi_info->id);
  1131. /* support suspend/resume */
  1132. qdf_atomic_dec(&(hif->active_tasklet_cnt));
  1133. NAPI_DEBUG("%s:%d: napi_complete + enabling the interrupts",
  1134. __func__, __LINE__);
  1135. } else {
  1136. /* 4.4 kernel NAPI implementation requires drivers to
  1137. * return full work when they ask to be re-scheduled,
  1138. * or napi_complete and re-start with a fresh interrupt
  1139. */
  1140. normalized = budget;
  1141. }
  1142. hif_record_ce_desc_event(hif, NAPI_ID2PIPE(napi_info->id),
  1143. NAPI_POLL_EXIT, NULL, NULL, normalized, 0);
  1144. hif_napi_fill_poll_time_histogram(napi_info);
  1145. NAPI_DEBUG("%s <--[normalized=%d]", __func__, normalized);
  1146. return normalized;
  1147. out:
  1148. return rc;
  1149. }
  1150. qdf_export_symbol(hif_napi_poll);
  1151. void hif_update_napi_max_poll_time(struct CE_state *ce_state,
  1152. int ce_id,
  1153. int cpu_id)
  1154. {
  1155. struct hif_softc *hif;
  1156. struct qca_napi_info *napi_info;
  1157. unsigned long long napi_poll_time = qdf_time_sched_clock() -
  1158. ce_state->ce_service_start_time;
  1159. hif = ce_state->scn;
  1160. napi_info = hif->napi_data.napis[ce_id];
  1161. if (napi_poll_time >
  1162. napi_info->stats[cpu_id].napi_max_poll_time)
  1163. napi_info->stats[cpu_id].napi_max_poll_time = napi_poll_time;
  1164. }
  1165. qdf_export_symbol(hif_update_napi_max_poll_time);
  1166. #ifdef HIF_IRQ_AFFINITY
  1167. /**
  1168. * hif_napi_update_yield_stats() - update NAPI yield related stats
  1169. * @ce_state: CE state structure
  1170. * @time_limit_reached: indicates whether the time limit was reached
  1171. * @rxpkt_thresh_reached: indicates whether rx packet threshold was reached
  1172. *
  1173. * Return: None
  1174. */
  1175. void hif_napi_update_yield_stats(struct CE_state *ce_state,
  1176. bool time_limit_reached,
  1177. bool rxpkt_thresh_reached)
  1178. {
  1179. struct hif_softc *hif;
  1180. struct qca_napi_data *napi_data = NULL;
  1181. int ce_id = 0;
  1182. int cpu_id = 0;
  1183. if (unlikely(!ce_state)) {
  1184. QDF_ASSERT(ce_state);
  1185. return;
  1186. }
  1187. hif = ce_state->scn;
  1188. if (unlikely(!hif)) {
  1189. QDF_ASSERT(hif);
  1190. return;
  1191. }
  1192. napi_data = &(hif->napi_data);
  1193. if (unlikely(!napi_data)) {
  1194. QDF_ASSERT(napi_data);
  1195. return;
  1196. }
  1197. ce_id = ce_state->id;
  1198. cpu_id = qdf_get_cpu();
  1199. if (unlikely(!napi_data->napis[ce_id])) {
  1200. return;
  1201. }
  1202. if (time_limit_reached)
  1203. napi_data->napis[ce_id]->stats[cpu_id].time_limit_reached++;
  1204. else
  1205. napi_data->napis[ce_id]->stats[cpu_id].rxpkt_thresh_reached++;
  1206. hif_update_napi_max_poll_time(ce_state, ce_id,
  1207. cpu_id);
  1208. }
  1209. /**
  1210. * hif_napi_stats() - display NAPI CPU statistics
  1211. * @napid: pointer to qca_napi_data
  1212. *
  1213. * Description:
  1214. * Prints the various CPU cores on which the NAPI instances /CEs interrupts
  1215. * are being executed. Can be called from outside NAPI layer.
  1216. *
  1217. * Return: None
  1218. */
  1219. void hif_napi_stats(struct qca_napi_data *napid)
  1220. {
  1221. int i;
  1222. struct qca_napi_cpu *cpu;
  1223. if (!napid) {
  1224. qdf_debug("%s: napiid struct is null", __func__);
  1225. return;
  1226. }
  1227. cpu = napid->napi_cpu;
  1228. qdf_debug("NAPI CPU TABLE");
  1229. qdf_debug("lilclhead=%d, bigclhead=%d",
  1230. napid->lilcl_head, napid->bigcl_head);
  1231. for (i = 0; i < NR_CPUS; i++) {
  1232. qdf_debug("CPU[%02d]: state:%d crid=%02d clid=%02d crmk:0x%0lx thmk:0x%0lx frq:%d napi = 0x%08x lnk:%d",
  1233. i,
  1234. cpu[i].state, cpu[i].core_id, cpu[i].cluster_id,
  1235. cpu[i].core_mask.bits[0],
  1236. cpu[i].thread_mask.bits[0],
  1237. cpu[i].max_freq, cpu[i].napis,
  1238. cpu[i].cluster_nxt);
  1239. }
  1240. }
  1241. #ifdef FEATURE_NAPI_DEBUG
  1242. /*
  1243. * Local functions
  1244. * - no argument checks, all internal/trusted callers
  1245. */
  1246. static void hnc_dump_cpus(struct qca_napi_data *napid)
  1247. {
  1248. hif_napi_stats(napid);
  1249. }
  1250. #else
  1251. static void hnc_dump_cpus(struct qca_napi_data *napid) { /* no-op */ };
  1252. #endif /* FEATURE_NAPI_DEBUG */
  1253. #define HNC_MIN_CLUSTER 0
  1254. #define HNC_MAX_CLUSTER 1
  1255. /**
  1256. * hnc_link_clusters() - partitions to cpu table into clusters
  1257. * @napid: pointer to NAPI data
  1258. *
  1259. * Takes in a CPU topology table and builds two linked lists
  1260. * (big cluster cores, list-head at bigcl_head, and little cluster
  1261. * cores, list-head at lilcl_head) out of it.
  1262. *
  1263. * If there are more than two clusters:
  1264. * - bigcl_head and lilcl_head will be different,
  1265. * - the cluster with highest cpufreq will be considered the "big" cluster.
  1266. * If there are more than one with the highest frequency, the *last* of such
  1267. * clusters will be designated as the "big cluster"
  1268. * - the cluster with lowest cpufreq will be considered the "li'l" cluster.
  1269. * If there are more than one clusters with the lowest cpu freq, the *first*
  1270. * of such clusters will be designated as the "little cluster"
  1271. * - We only support up to 32 clusters
  1272. * Return: 0 : OK
  1273. * !0: error (at least one of lil/big clusters could not be found)
  1274. */
  1275. static int hnc_link_clusters(struct qca_napi_data *napid)
  1276. {
  1277. int rc = 0;
  1278. int i;
  1279. int it = 0;
  1280. uint32_t cl_done = 0x0;
  1281. int cl, curcl, curclhead = 0;
  1282. int more;
  1283. unsigned int lilfrq = INT_MAX;
  1284. unsigned int bigfrq = 0;
  1285. unsigned int clfrq = 0;
  1286. int prev = 0;
  1287. struct qca_napi_cpu *cpus = napid->napi_cpu;
  1288. napid->lilcl_head = napid->bigcl_head = -1;
  1289. do {
  1290. more = 0;
  1291. it++; curcl = -1;
  1292. for (i = 0; i < NR_CPUS; i++) {
  1293. cl = cpus[i].cluster_id;
  1294. NAPI_DEBUG("Processing cpu[%d], cluster=%d\n",
  1295. i, cl);
  1296. if ((cl < HNC_MIN_CLUSTER) || (cl > HNC_MAX_CLUSTER)) {
  1297. NAPI_DEBUG("Bad cluster (%d). SKIPPED\n", cl);
  1298. /* continue if ASSERTs are disabled */
  1299. continue;
  1300. };
  1301. if (cpumask_weight(&(cpus[i].core_mask)) == 0) {
  1302. NAPI_DEBUG("Core mask 0. SKIPPED\n");
  1303. continue;
  1304. }
  1305. if (cl_done & (0x01 << cl)) {
  1306. NAPI_DEBUG("Cluster already processed. SKIPPED\n");
  1307. continue;
  1308. } else {
  1309. if (more == 0) {
  1310. more = 1;
  1311. curcl = cl;
  1312. curclhead = i; /* row */
  1313. clfrq = cpus[i].max_freq;
  1314. prev = -1;
  1315. };
  1316. if ((curcl >= 0) && (curcl != cl)) {
  1317. NAPI_DEBUG("Entry cl(%d) != curcl(%d). SKIPPED\n",
  1318. cl, curcl);
  1319. continue;
  1320. }
  1321. if (cpus[i].max_freq != clfrq)
  1322. NAPI_DEBUG("WARN: frq(%d)!=clfrq(%d)\n",
  1323. cpus[i].max_freq, clfrq);
  1324. if (clfrq >= bigfrq) {
  1325. bigfrq = clfrq;
  1326. napid->bigcl_head = curclhead;
  1327. NAPI_DEBUG("bigcl=%d\n", curclhead);
  1328. }
  1329. if (clfrq < lilfrq) {
  1330. lilfrq = clfrq;
  1331. napid->lilcl_head = curclhead;
  1332. NAPI_DEBUG("lilcl=%d\n", curclhead);
  1333. }
  1334. if (prev != -1)
  1335. cpus[prev].cluster_nxt = i;
  1336. prev = i;
  1337. }
  1338. }
  1339. if (curcl >= 0)
  1340. cl_done |= (0x01 << curcl);
  1341. } while (more);
  1342. if (qdf_unlikely((napid->lilcl_head < 0) && (napid->bigcl_head < 0)))
  1343. rc = -EFAULT;
  1344. hnc_dump_cpus(napid); /* if NAPI_DEBUG */
  1345. return rc;
  1346. }
  1347. #undef HNC_MIN_CLUSTER
  1348. #undef HNC_MAX_CLUSTER
  1349. /*
  1350. * hotplug function group
  1351. */
  1352. /**
  1353. * hnc_cpu_online_cb() - handles CPU hotplug "up" events
  1354. * @context: the associated HIF context
  1355. * @cpu: the CPU Id of the CPU the event happened on
  1356. *
  1357. * Return: None
  1358. */
  1359. static void hnc_cpu_online_cb(void *context, uint32_t cpu)
  1360. {
  1361. struct hif_softc *hif = context;
  1362. struct qca_napi_data *napid = &hif->napi_data;
  1363. if (cpu >= NR_CPUS)
  1364. return;
  1365. NAPI_DEBUG("-->%s(act=online, cpu=%u)", __func__, cpu);
  1366. napid->napi_cpu[cpu].state = QCA_NAPI_CPU_UP;
  1367. NAPI_DEBUG("%s: CPU %u marked %d",
  1368. __func__, cpu, napid->napi_cpu[cpu].state);
  1369. NAPI_DEBUG("<--%s", __func__);
  1370. }
  1371. /**
  1372. * hnc_cpu_before_offline_cb() - handles CPU hotplug "prepare down" events
  1373. * @context: the associated HIF context
  1374. * @cpu: the CPU Id of the CPU the event happened on
  1375. *
  1376. * On transition to offline, we act on PREP events, because we may need to move
  1377. * the irqs/NAPIs to another CPU before it is actually off-lined.
  1378. *
  1379. * Return: None
  1380. */
  1381. static void hnc_cpu_before_offline_cb(void *context, uint32_t cpu)
  1382. {
  1383. struct hif_softc *hif = context;
  1384. struct qca_napi_data *napid = &hif->napi_data;
  1385. if (cpu >= NR_CPUS)
  1386. return;
  1387. NAPI_DEBUG("-->%s(act=before_offline, cpu=%u)", __func__, cpu);
  1388. napid->napi_cpu[cpu].state = QCA_NAPI_CPU_DOWN;
  1389. NAPI_DEBUG("%s: CPU %u marked %d; updating affinity",
  1390. __func__, cpu, napid->napi_cpu[cpu].state);
  1391. /**
  1392. * we need to move any NAPIs on this CPU out.
  1393. * if we are in LO throughput mode, then this is valid
  1394. * if the CPU is the the low designated CPU.
  1395. */
  1396. hif_napi_event(GET_HIF_OPAQUE_HDL(hif),
  1397. NAPI_EVT_CPU_STATE,
  1398. (void *)
  1399. ((size_t)cpu << 16 | napid->napi_cpu[cpu].state));
  1400. NAPI_DEBUG("<--%s", __func__);
  1401. }
  1402. static int hnc_hotplug_register(struct hif_softc *hif_sc)
  1403. {
  1404. QDF_STATUS status;
  1405. NAPI_DEBUG("-->%s", __func__);
  1406. status = qdf_cpuhp_register(&hif_sc->napi_data.cpuhp_handler,
  1407. hif_sc,
  1408. hnc_cpu_online_cb,
  1409. hnc_cpu_before_offline_cb);
  1410. NAPI_DEBUG("<--%s [%d]", __func__, status);
  1411. return qdf_status_to_os_return(status);
  1412. }
  1413. static void hnc_hotplug_unregister(struct hif_softc *hif_sc)
  1414. {
  1415. NAPI_DEBUG("-->%s", __func__);
  1416. if (hif_sc->napi_data.cpuhp_handler)
  1417. qdf_cpuhp_unregister(&hif_sc->napi_data.cpuhp_handler);
  1418. NAPI_DEBUG("<--%s", __func__);
  1419. }
  1420. /**
  1421. * hnc_tput_hook() - installs a callback in the throughput detector
  1422. * @install: !0 => install; =0: uninstall
  1423. *
  1424. * installs a callback to be called when wifi driver throughput (tx+rx)
  1425. * crosses a threshold. Currently, we are using the same criteria as
  1426. * TCP ack suppression (500 packets/100ms by default).
  1427. *
  1428. * Return: 0 : success
  1429. * <0: failure
  1430. */
  1431. static int hnc_tput_hook(int install)
  1432. {
  1433. int rc = 0;
  1434. /*
  1435. * Nothing, until the bw_calculation accepts registration
  1436. * it is now hardcoded in the wlan_hdd_main.c::hdd_bus_bw_compute_cbk
  1437. * hdd_napi_throughput_policy(...)
  1438. */
  1439. return rc;
  1440. }
  1441. /*
  1442. * Implementation of hif_napi_cpu API
  1443. */
  1444. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
  1445. static inline void record_sibling_cpumask(struct qca_napi_cpu *cpus, int i)
  1446. {
  1447. cpumask_copy(&(cpus[i].thread_mask),
  1448. topology_sibling_cpumask(i));
  1449. }
  1450. #else
  1451. static inline void record_sibling_cpumask(struct qca_napi_cpu *cpus, int i)
  1452. {
  1453. }
  1454. #endif
  1455. /**
  1456. * hif_napi_cpu_init() - initialization of irq affinity block
  1457. * @hif: HIF context
  1458. *
  1459. * called by hif_napi_create, after the first instance is called
  1460. * - builds napi_rss_cpus table from cpu topology
  1461. * - links cores of the same clusters together
  1462. * - installs hot-plug notifier
  1463. * - installs throughput trigger notifier (when such mechanism exists)
  1464. *
  1465. * Return: 0: OK
  1466. * <0: error code
  1467. */
  1468. int hif_napi_cpu_init(struct hif_opaque_softc *hif)
  1469. {
  1470. int rc = 0;
  1471. int i;
  1472. struct qca_napi_data *napid = &HIF_GET_SOFTC(hif)->napi_data;
  1473. struct qca_napi_cpu *cpus = napid->napi_cpu;
  1474. NAPI_DEBUG("--> ");
  1475. if (cpus[0].state != QCA_NAPI_CPU_UNINITIALIZED) {
  1476. NAPI_DEBUG("NAPI RSS table already initialized.\n");
  1477. rc = -EALREADY;
  1478. goto lab_rss_init;
  1479. }
  1480. /* build CPU topology table */
  1481. for_each_possible_cpu(i) {
  1482. cpus[i].state = ((cpumask_test_cpu(i, cpu_online_mask)
  1483. ? QCA_NAPI_CPU_UP
  1484. : QCA_NAPI_CPU_DOWN));
  1485. cpus[i].core_id = topology_core_id(i);
  1486. cpus[i].cluster_id = topology_physical_package_id(i);
  1487. cpumask_copy(&(cpus[i].core_mask),
  1488. topology_core_cpumask(i));
  1489. record_sibling_cpumask(cpus, i);
  1490. cpus[i].max_freq = cpufreq_quick_get_max(i);
  1491. cpus[i].napis = 0x0;
  1492. cpus[i].cluster_nxt = -1; /* invalid */
  1493. }
  1494. /* link clusters together */
  1495. rc = hnc_link_clusters(napid);
  1496. if (0 != rc)
  1497. goto lab_err_topology;
  1498. /* install hotplug notifier */
  1499. rc = hnc_hotplug_register(HIF_GET_SOFTC(hif));
  1500. if (0 != rc)
  1501. goto lab_err_hotplug;
  1502. /* install throughput notifier */
  1503. rc = hnc_tput_hook(1);
  1504. if (0 == rc)
  1505. goto lab_rss_init;
  1506. lab_err_hotplug:
  1507. hnc_tput_hook(0);
  1508. hnc_hotplug_unregister(HIF_GET_SOFTC(hif));
  1509. lab_err_topology:
  1510. memset(napid->napi_cpu, 0, sizeof(struct qca_napi_cpu) * NR_CPUS);
  1511. lab_rss_init:
  1512. NAPI_DEBUG("<-- [rc=%d]", rc);
  1513. return rc;
  1514. }
  1515. /**
  1516. * hif_napi_cpu_deinit() - clean-up of irq affinity block
  1517. * @hif: HIF context
  1518. *
  1519. * called by hif_napi_destroy, when the last instance is removed
  1520. * - uninstalls throughput and hotplug notifiers
  1521. * - clears cpu topology table
  1522. * Return: 0: OK
  1523. */
  1524. int hif_napi_cpu_deinit(struct hif_opaque_softc *hif)
  1525. {
  1526. int rc = 0;
  1527. struct qca_napi_data *napid = &HIF_GET_SOFTC(hif)->napi_data;
  1528. NAPI_DEBUG("-->%s(...)", __func__);
  1529. /* uninstall tput notifier */
  1530. rc = hnc_tput_hook(0);
  1531. /* uninstall hotplug notifier */
  1532. hnc_hotplug_unregister(HIF_GET_SOFTC(hif));
  1533. /* clear the topology table */
  1534. memset(napid->napi_cpu, 0, sizeof(struct qca_napi_cpu) * NR_CPUS);
  1535. NAPI_DEBUG("<--%s[rc=%d]", __func__, rc);
  1536. return rc;
  1537. }
  1538. /**
  1539. * hncm_migrate_to() - migrates a NAPI to a CPU
  1540. * @napid: pointer to NAPI block
  1541. * @napi_ce: CE_id of the NAPI instance
  1542. * @didx: index in the CPU topology table for the CPU to migrate to
  1543. *
  1544. * Migrates NAPI (identified by the CE_id) to the destination core
  1545. * Updates the napi_map of the destination entry
  1546. *
  1547. * Return:
  1548. * =0 : success
  1549. * <0 : error
  1550. */
  1551. static int hncm_migrate_to(struct qca_napi_data *napid,
  1552. int napi_ce,
  1553. int didx)
  1554. {
  1555. int rc = 0;
  1556. QDF_STATUS status;
  1557. NAPI_DEBUG("-->%s(napi_cd=%d, didx=%d)", __func__, napi_ce, didx);
  1558. if (!napid->napis[napi_ce])
  1559. return -EINVAL;
  1560. napid->napis[napi_ce]->cpumask.bits[0] = (1 << didx);
  1561. qdf_dev_modify_irq_status(napid->napis[napi_ce]->irq,
  1562. QDF_IRQ_NO_BALANCING, 0);
  1563. status = qdf_dev_set_irq_affinity(napid->napis[napi_ce]->irq,
  1564. (struct qdf_cpu_mask *)
  1565. &napid->napis[napi_ce]->cpumask);
  1566. rc = qdf_status_to_os_return(status);
  1567. /* unmark the napis bitmap in the cpu table */
  1568. napid->napi_cpu[napid->napis[napi_ce]->cpu].napis &= ~(0x01 << napi_ce);
  1569. /* mark the napis bitmap for the new designated cpu */
  1570. napid->napi_cpu[didx].napis |= (0x01 << napi_ce);
  1571. napid->napis[napi_ce]->cpu = didx;
  1572. NAPI_DEBUG("<--%s[%d]", __func__, rc);
  1573. return rc;
  1574. }
  1575. /**
  1576. * hncm_dest_cpu() - finds a destination CPU for NAPI
  1577. * @napid: pointer to NAPI block
  1578. * @act: RELOCATE | COLLAPSE | DISPERSE
  1579. *
  1580. * Finds the designated destination for the next IRQ.
  1581. * RELOCATE: translated to either COLLAPSE or DISPERSE based
  1582. * on napid->napi_mode (throughput state)
  1583. * COLLAPSE: All have the same destination: the first online CPU in lilcl
  1584. * DISPERSE: One of the CPU in bigcl, which has the smallest number of
  1585. * NAPIs on it
  1586. *
  1587. * Return: >=0 : index in the cpu topology table
  1588. * : < 0 : error
  1589. */
  1590. static int hncm_dest_cpu(struct qca_napi_data *napid, int act)
  1591. {
  1592. int destidx = -1;
  1593. int head, i;
  1594. NAPI_DEBUG("-->%s(act=%d)", __func__, act);
  1595. if (act == HNC_ACT_RELOCATE) {
  1596. if (napid->napi_mode == QCA_NAPI_TPUT_LO)
  1597. act = HNC_ACT_COLLAPSE;
  1598. else
  1599. act = HNC_ACT_DISPERSE;
  1600. NAPI_DEBUG("%s: act changed from HNC_ACT_RELOCATE to %d",
  1601. __func__, act);
  1602. }
  1603. if (act == HNC_ACT_COLLAPSE) {
  1604. head = i = napid->lilcl_head;
  1605. retry_collapse:
  1606. while (i >= 0) {
  1607. if (napid->napi_cpu[i].state == QCA_NAPI_CPU_UP) {
  1608. destidx = i;
  1609. break;
  1610. }
  1611. i = napid->napi_cpu[i].cluster_nxt;
  1612. }
  1613. if ((destidx < 0) && (head == napid->lilcl_head)) {
  1614. NAPI_DEBUG("%s: COLLAPSE: no lilcl dest, try bigcl",
  1615. __func__);
  1616. head = i = napid->bigcl_head;
  1617. goto retry_collapse;
  1618. }
  1619. } else { /* HNC_ACT_DISPERSE */
  1620. int smallest = 99; /* all 32 bits full */
  1621. int smallidx = -1;
  1622. head = i = napid->bigcl_head;
  1623. retry_disperse:
  1624. while (i >= 0) {
  1625. if ((napid->napi_cpu[i].state == QCA_NAPI_CPU_UP) &&
  1626. (hweight32(napid->napi_cpu[i].napis) <= smallest)) {
  1627. smallest = napid->napi_cpu[i].napis;
  1628. smallidx = i;
  1629. }
  1630. i = napid->napi_cpu[i].cluster_nxt;
  1631. }
  1632. /* Check if matches with user specified CPU mask */
  1633. smallidx = ((1 << smallidx) & napid->user_cpu_affin_mask) ?
  1634. smallidx : -1;
  1635. if ((smallidx < 0) && (head == napid->bigcl_head)) {
  1636. NAPI_DEBUG("%s: DISPERSE: no bigcl dest, try lilcl",
  1637. __func__);
  1638. head = i = napid->lilcl_head;
  1639. goto retry_disperse;
  1640. }
  1641. destidx = smallidx;
  1642. }
  1643. NAPI_DEBUG("<--%s[dest=%d]", __func__, destidx);
  1644. return destidx;
  1645. }
  1646. /**
  1647. * hif_napi_cpu_migrate() - migrate IRQs away
  1648. * @napid: pointer to NAPI block
  1649. * @cpu: -1: all CPUs <n> specific CPU
  1650. * @action: COLLAPSE | DISPERSE
  1651. *
  1652. * Moves IRQs/NAPIs from specific or all CPUs (specified by @cpu) to eligible
  1653. * cores. Eligible cores are:
  1654. * act=COLLAPSE -> the first online core of the little cluster
  1655. * act=DISPERSE -> separate cores of the big cluster, so that each core will
  1656. * host minimum number of NAPIs/IRQs (napid->cpus[cpu].napis)
  1657. *
  1658. * Note that this function is called with a spinlock acquired already.
  1659. *
  1660. * Return: =0: success
  1661. * <0: error
  1662. */
  1663. int hif_napi_cpu_migrate(struct qca_napi_data *napid, int cpu, int action)
  1664. {
  1665. int rc = 0;
  1666. struct qca_napi_cpu *cpup;
  1667. int i, dind;
  1668. uint32_t napis;
  1669. NAPI_DEBUG("-->%s(.., cpu=%d, act=%d)",
  1670. __func__, cpu, action);
  1671. /* the following is really: hif_napi_enabled() with less overhead */
  1672. if (napid->ce_map == 0) {
  1673. NAPI_DEBUG("%s: NAPI disabled. Not migrating.", __func__);
  1674. goto hncm_return;
  1675. }
  1676. cpup = napid->napi_cpu;
  1677. switch (action) {
  1678. case HNC_ACT_RELOCATE:
  1679. case HNC_ACT_DISPERSE:
  1680. case HNC_ACT_COLLAPSE: {
  1681. /* first find the src napi set */
  1682. if (cpu == HNC_ANY_CPU)
  1683. napis = napid->ce_map;
  1684. else
  1685. napis = cpup[cpu].napis;
  1686. /* then clear the napi bitmap on each CPU */
  1687. for (i = 0; i < NR_CPUS; i++)
  1688. cpup[i].napis = 0;
  1689. /* then for each of the NAPIs to disperse: */
  1690. for (i = 0; i < CE_COUNT_MAX; i++)
  1691. if (napis & (1 << i)) {
  1692. /* find a destination CPU */
  1693. dind = hncm_dest_cpu(napid, action);
  1694. if (dind >= 0) {
  1695. NAPI_DEBUG("Migrating NAPI ce%d to %d",
  1696. i, dind);
  1697. rc = hncm_migrate_to(napid, i, dind);
  1698. } else {
  1699. NAPI_DEBUG("No dest for NAPI ce%d", i);
  1700. hnc_dump_cpus(napid);
  1701. rc = -1;
  1702. }
  1703. }
  1704. break;
  1705. }
  1706. default: {
  1707. NAPI_DEBUG("%s: bad action: %d\n", __func__, action);
  1708. QDF_BUG(0);
  1709. break;
  1710. }
  1711. } /* switch action */
  1712. hncm_return:
  1713. hnc_dump_cpus(napid);
  1714. return rc;
  1715. }
  1716. /**
  1717. * hif_napi_dl_irq() - calls irq_modify_status to enable/disable denylisting
  1718. * @napid: pointer to qca_napi_data structure
  1719. * @dl_flag: denylist flag to enable/disable denylisting
  1720. *
  1721. * The function enables/disables denylisting for all the copy engine
  1722. * interrupts on which NAPI is enabled.
  1723. *
  1724. * Return: None
  1725. */
  1726. static inline void hif_napi_dl_irq(struct qca_napi_data *napid, bool dl_flag)
  1727. {
  1728. int i;
  1729. struct qca_napi_info *napii;
  1730. for (i = 0; i < CE_COUNT_MAX; i++) {
  1731. /* check if NAPI is enabled on the CE */
  1732. if (!(napid->ce_map & (0x01 << i)))
  1733. continue;
  1734. /*double check that NAPI is allocated for the CE */
  1735. napii = napid->napis[i];
  1736. if (!(napii))
  1737. continue;
  1738. if (dl_flag == true)
  1739. qdf_dev_modify_irq_status(napii->irq,
  1740. 0, QDF_IRQ_NO_BALANCING);
  1741. else
  1742. qdf_dev_modify_irq_status(napii->irq,
  1743. QDF_IRQ_NO_BALANCING, 0);
  1744. hif_debug("dl_flag %d CE %d", dl_flag, i);
  1745. }
  1746. }
  1747. /**
  1748. * hif_napi_cpu_denylist() - en(dis)ables denylisting for NAPI RX interrupts.
  1749. * @napid: pointer to qca_napi_data structure
  1750. * @op: denylist operation to perform
  1751. *
  1752. * The function enables/disables/queries denylisting for all CE RX
  1753. * interrupts with NAPI enabled. Besides denylisting, it also enables/disables
  1754. * core_ctl_set_boost.
  1755. * Once denylisting is enabled, the interrupts will not be managed by the IRQ
  1756. * balancer.
  1757. *
  1758. * Return: -EINVAL, in case IRQ_DENYLISTING and CORE_CTL_BOOST is not enabled
  1759. * for DENYLIST_QUERY op - denylist refcount
  1760. * for DENYLIST_ON op - return value from core_ctl_set_boost API
  1761. * for DENYLIST_OFF op - return value from core_ctl_set_boost API
  1762. */
  1763. int hif_napi_cpu_denylist(struct qca_napi_data *napid,
  1764. enum qca_denylist_op op)
  1765. {
  1766. int rc = 0;
  1767. static int ref_count; /* = 0 by the compiler */
  1768. uint8_t flags = napid->flags;
  1769. bool dl_en = flags & QCA_NAPI_FEATURE_IRQ_BLACKLISTING;
  1770. bool ccb_en = flags & QCA_NAPI_FEATURE_CORE_CTL_BOOST;
  1771. NAPI_DEBUG("-->%s(%d %d)", __func__, flags, op);
  1772. if (!(dl_en && ccb_en)) {
  1773. rc = -EINVAL;
  1774. goto out;
  1775. }
  1776. switch (op) {
  1777. case DENYLIST_QUERY:
  1778. rc = ref_count;
  1779. break;
  1780. case DENYLIST_ON:
  1781. ref_count++;
  1782. rc = 0;
  1783. if (ref_count == 1) {
  1784. rc = hif_napi_core_ctl_set_boost(true);
  1785. NAPI_DEBUG("boost_on() returns %d - refcnt=%d",
  1786. rc, ref_count);
  1787. hif_napi_dl_irq(napid, true);
  1788. }
  1789. break;
  1790. case DENYLIST_OFF:
  1791. if (ref_count) {
  1792. ref_count--;
  1793. rc = 0;
  1794. if (ref_count == 0) {
  1795. rc = hif_napi_core_ctl_set_boost(false);
  1796. NAPI_DEBUG("boost_off() returns %d - refcnt=%d",
  1797. rc, ref_count);
  1798. hif_napi_dl_irq(napid, false);
  1799. }
  1800. }
  1801. break;
  1802. default:
  1803. NAPI_DEBUG("Invalid denylist op: %d", op);
  1804. rc = -EINVAL;
  1805. } /* switch */
  1806. out:
  1807. NAPI_DEBUG("<--%s[%d]", __func__, rc);
  1808. return rc;
  1809. }
  1810. static unsigned long napi_serialize_reqs;
  1811. /**
  1812. * hif_napi_serialize() - [de-]serialize NAPI operations
  1813. * @hif: context
  1814. * @is_on: 1: serialize, 0: deserialize
  1815. *
  1816. * hif_napi_serialize(hif, 1) can be called multiple times. It will perform the
  1817. * following steps (see hif_napi_event for code):
  1818. * - put irqs of all NAPI instances on the same CPU
  1819. * - only for the first serialize call: denylist
  1820. *
  1821. * hif_napi_serialize(hif, 0):
  1822. * - start a timer (multiple of BusBandwidthTimer -- default: 100 msec)
  1823. * - at the end of the timer, check the current throughput state and
  1824. * implement it.
  1825. */
  1826. int hif_napi_serialize(struct hif_opaque_softc *hif, int is_on)
  1827. {
  1828. int rc = -EINVAL;
  1829. if (hif)
  1830. switch (is_on) {
  1831. case 0: { /* de-serialize */
  1832. rc = hif_napi_event(hif, NAPI_EVT_USR_NORMAL,
  1833. (void *) 0);
  1834. napi_serialize_reqs = 0;
  1835. break;
  1836. } /* end de-serialize */
  1837. case 1: { /* serialize */
  1838. rc = hif_napi_event(hif, NAPI_EVT_USR_SERIAL,
  1839. (void *)napi_serialize_reqs++);
  1840. break;
  1841. } /* end serialize */
  1842. default:
  1843. break; /* no-op */
  1844. } /* switch */
  1845. return rc;
  1846. }
  1847. #endif /* ifdef HIF_IRQ_AFFINITY */