12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
- */
- #include <linux/debugfs.h>
- #include <linux/kernel.h>
- #include <linux/delay.h>
- #include "ipa_i.h"
- #include "ipahal/ipahal.h"
- #include "ipahal/ipahal_hw_stats.h"
- #define IPA_CLIENT_BIT_32(client) \
- ((ipa3_get_ep_mapping(client) >= 0 && \
- ipa3_get_ep_mapping(client) < IPA_STATS_MAX_PIPE_BIT) ? \
- (1 << ipa3_get_ep_mapping(client)) : 0)
- int ipa_hw_stats_init(void)
- {
- int ret = 0, ep_index;
- struct ipa_teth_stats_endpoints *teth_stats_init;
- if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
- return 0;
- /* initialize stats here */
- ipa3_ctx->hw_stats.enabled = true;
- teth_stats_init = kzalloc(sizeof(*teth_stats_init), GFP_KERNEL);
- if (!teth_stats_init) {
- IPAERR("mem allocated failed!\n");
- return -ENOMEM;
- }
- /* enable prod mask */
- if (ipa3_ctx->platform_type == IPA_PLAT_TYPE_APQ) {
- teth_stats_init->prod_mask = (
- IPA_CLIENT_BIT_32(IPA_CLIENT_MHI_PRIME_TETH_PROD) |
- IPA_CLIENT_BIT_32(IPA_CLIENT_USB_PROD));
- if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_5)
- teth_stats_init->prod_mask |=
- IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN2_PROD);
- else
- teth_stats_init->prod_mask |=
- IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN1_PROD);
- if (IPA_CLIENT_BIT_32(IPA_CLIENT_MHI_PRIME_TETH_PROD)) {
- ep_index = ipa3_get_ep_mapping(
- IPA_CLIENT_MHI_PRIME_TETH_PROD);
- if (ep_index == -1) {
- IPAERR("Invalid client.\n");
- kfree(teth_stats_init);
- return -EINVAL;
- }
- teth_stats_init->dst_ep_mask[ep_index] =
- IPA_CLIENT_BIT_32(IPA_CLIENT_USB_CONS);
- if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_5)
- teth_stats_init->dst_ep_mask[ep_index] |=
- IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN2_CONS);
- else
- teth_stats_init->dst_ep_mask[ep_index] |=
- IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN1_CONS);
- }
- } else {
- teth_stats_init->prod_mask = (
- IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_PROD) |
- IPA_CLIENT_BIT_32(IPA_CLIENT_USB_PROD));
- if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_5)
- teth_stats_init->prod_mask |=
- IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN2_PROD);
- else
- teth_stats_init->prod_mask |=
- IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN1_PROD);
- if (IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_PROD)) {
- ep_index = ipa3_get_ep_mapping(IPA_CLIENT_Q6_WAN_PROD);
- if (ep_index == -1) {
- IPAERR("Invalid client.\n");
- kfree(teth_stats_init);
- return -EINVAL;
- }
- teth_stats_init->dst_ep_mask[ep_index] =
- IPA_CLIENT_BIT_32(IPA_CLIENT_USB_CONS);
- if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_5)
- teth_stats_init->dst_ep_mask[ep_index] |=
- IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN2_CONS);
- else
- teth_stats_init->dst_ep_mask[ep_index] |=
- IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN1_CONS);
- }
- }
- if (IPA_CLIENT_BIT_32(IPA_CLIENT_USB_PROD)) {
- ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD);
- if (ep_index == -1) {
- IPAERR("Invalid client.\n");
- kfree(teth_stats_init);
- return -EINVAL;
- }
- /* enable addtional pipe monitoring for pcie modem */
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_1)
- teth_stats_init->dst_ep_mask[ep_index] =
- (IPA_CLIENT_BIT_32(
- IPA_CLIENT_Q6_WAN_CONS) |
- IPA_CLIENT_BIT_32(
- IPA_CLIENT_MHI_PRIME_TETH_CONS));
- else
- teth_stats_init->dst_ep_mask[ep_index] =
- IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_CONS);
- }
- if (IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN1_PROD)) {
- ep_index = ipa3_get_ep_mapping(IPA_CLIENT_WLAN1_PROD);
- if (ep_index == -1) {
- IPAERR("Invalid client.\n");
- kfree(teth_stats_init);
- return -EINVAL;
- }
- /* enable addtional pipe monitoring for pcie modem*/
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_1)
- teth_stats_init->dst_ep_mask[ep_index] =
- (IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_CONS) |
- IPA_CLIENT_BIT_32(
- IPA_CLIENT_MHI_PRIME_TETH_CONS));
- else
- teth_stats_init->dst_ep_mask[ep_index] =
- IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_CONS);
- }
- if (IPA_CLIENT_BIT_32(IPA_CLIENT_WLAN2_PROD)) {
- ep_index = ipa3_get_ep_mapping(IPA_CLIENT_WLAN2_PROD);
- if (ep_index == -1) {
- IPAERR("Invalid client.\n");
- kfree(teth_stats_init);
- return -EINVAL;
- }
- /* enable addtional pipe monitoring for pcie modem*/
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_1)
- teth_stats_init->dst_ep_mask[ep_index] =
- (IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_CONS) |
- IPA_CLIENT_BIT_32(
- IPA_CLIENT_MHI_PRIME_TETH_CONS));
- else
- teth_stats_init->dst_ep_mask[ep_index] =
- IPA_CLIENT_BIT_32(IPA_CLIENT_Q6_WAN_CONS);
- }
- ret = ipa_init_teth_stats(teth_stats_init);
- if (ret != 0)
- IPAERR("init teth stats fails\n");
- kfree(teth_stats_init);
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) {
- ret = ipa_init_flt_rt_stats();
- if (ret != 0)
- IPAERR("init flt rt stats fails\n");
- }
- return ret;
- }
- int ipa_init_quota_stats(u32 pipe_bitmask)
- {
- struct ipahal_stats_init_pyld *pyld;
- struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
- struct ipahal_imm_cmd_pyld *cmd_pyld;
- struct ipahal_imm_cmd_register_write quota_base = {0};
- struct ipahal_imm_cmd_pyld *quota_base_pyld;
- struct ipahal_imm_cmd_register_write quota_mask = {0};
- struct ipahal_imm_cmd_pyld *quota_mask_pyld;
- struct ipa3_desc desc[3] = { {0} };
- dma_addr_t dma_address;
- int ret;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- /* reset driver's cache */
- memset(&ipa3_ctx->hw_stats.quota, 0, sizeof(ipa3_ctx->hw_stats.quota));
- ipa3_ctx->hw_stats.quota.init.enabled_bitmask = pipe_bitmask;
- IPADBG_LOW("pipe_bitmask=0x%x\n", pipe_bitmask);
- pyld = ipahal_stats_generate_init_pyld(IPAHAL_HW_STATS_QUOTA,
- &ipa3_ctx->hw_stats.quota.init, false);
- if (!pyld) {
- IPAERR("failed to generate pyld\n");
- return -EPERM;
- }
- if (pyld->len > IPA_MEM_PART(stats_quota_size)) {
- IPAERR("SRAM partition too small: %d needed %d\n",
- IPA_MEM_PART(stats_quota_size), pyld->len);
- ret = -EPERM;
- goto destroy_init_pyld;
- }
- dma_address = dma_map_single(ipa3_ctx->pdev,
- pyld->data,
- pyld->len,
- DMA_TO_DEVICE);
- if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) {
- IPAERR("failed to DMA map\n");
- ret = -EPERM;
- goto destroy_init_pyld;
- }
- /* setting the registers and init the stats pyld are done atomically */
- quota_mask.skip_pipeline_clear = false;
- quota_mask.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- quota_mask.offset = ipahal_get_reg_n_ofst(IPA_STAT_QUOTA_MASK_n,
- ipa3_ctx->ee);
- quota_mask.value = pipe_bitmask;
- quota_mask.value_mask = ~0;
- quota_mask_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
- "a_mask, false);
- if (!quota_mask_pyld) {
- IPAERR("failed to construct register_write imm cmd\n");
- ret = -ENOMEM;
- goto unmap;
- }
- desc[0].opcode = quota_mask_pyld->opcode;
- desc[0].pyld = quota_mask_pyld->data;
- desc[0].len = quota_mask_pyld->len;
- desc[0].type = IPA_IMM_CMD_DESC;
- quota_base.skip_pipeline_clear = false;
- quota_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- quota_base.offset = ipahal_get_reg_n_ofst(IPA_STAT_QUOTA_BASE_n,
- ipa3_ctx->ee);
- quota_base.value = ipa3_ctx->smem_restricted_bytes +
- IPA_MEM_PART(stats_quota_ofst);
- quota_base.value_mask = ~0;
- quota_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
- "a_base, false);
- if (!quota_base_pyld) {
- IPAERR("failed to construct register_write imm cmd\n");
- ret = -ENOMEM;
- goto destroy_quota_mask;
- }
- desc[1].opcode = quota_base_pyld->opcode;
- desc[1].pyld = quota_base_pyld->data;
- desc[1].len = quota_base_pyld->len;
- desc[1].type = IPA_IMM_CMD_DESC;
- cmd.is_read = false;
- cmd.skip_pipeline_clear = false;
- cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- cmd.size = pyld->len;
- cmd.system_addr = dma_address;
- cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
- IPA_MEM_PART(stats_quota_ofst);
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
- if (!cmd_pyld) {
- IPAERR("failed to construct dma_shared_mem imm cmd\n");
- ret = -ENOMEM;
- goto destroy_quota_base;
- }
- desc[2].opcode = cmd_pyld->opcode;
- desc[2].pyld = cmd_pyld->data;
- desc[2].len = cmd_pyld->len;
- desc[2].type = IPA_IMM_CMD_DESC;
- ret = ipa3_send_cmd(3, desc);
- if (ret) {
- IPAERR("failed to send immediate command (error %d)\n", ret);
- goto destroy_imm;
- }
- ret = 0;
- destroy_imm:
- ipahal_destroy_imm_cmd(cmd_pyld);
- destroy_quota_base:
- ipahal_destroy_imm_cmd(quota_base_pyld);
- destroy_quota_mask:
- ipahal_destroy_imm_cmd(quota_mask_pyld);
- unmap:
- dma_unmap_single(ipa3_ctx->pdev, dma_address, pyld->len, DMA_TO_DEVICE);
- destroy_init_pyld:
- ipahal_destroy_stats_init_pyld(pyld);
- return ret;
- }
- int ipa_get_quota_stats(struct ipa_quota_stats_all *out)
- {
- int i;
- int ret;
- struct ipahal_stats_get_offset_quota get_offset = { { 0 } };
- struct ipahal_stats_offset offset = { 0 };
- struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
- struct ipahal_imm_cmd_pyld *cmd_pyld;
- struct ipa_mem_buffer mem;
- struct ipa3_desc desc = { 0 };
- struct ipahal_stats_quota_all *stats;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- get_offset.init = ipa3_ctx->hw_stats.quota.init;
- ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_QUOTA, &get_offset,
- &offset);
- if (ret) {
- IPAERR("failed to get offset from hal %d\n", ret);
- return ret;
- }
- IPADBG_LOW("offset = %d size = %d\n", offset.offset, offset.size);
- if (offset.size == 0)
- return 0;
- mem.size = offset.size;
- mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
- mem.size,
- &mem.phys_base,
- GFP_KERNEL);
- if (!mem.base) {
- IPAERR("fail to alloc DMA memory");
- return ret;
- }
- cmd.is_read = true;
- cmd.clear_after_read = true;
- cmd.skip_pipeline_clear = false;
- cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
- cmd.size = mem.size;
- cmd.system_addr = mem.phys_base;
- cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
- IPA_MEM_PART(stats_quota_ofst) + offset.offset;
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
- if (!cmd_pyld) {
- IPAERR("failed to construct dma_shared_mem imm cmd\n");
- ret = -ENOMEM;
- goto free_dma_mem;
- }
- desc.opcode = cmd_pyld->opcode;
- desc.pyld = cmd_pyld->data;
- desc.len = cmd_pyld->len;
- desc.type = IPA_IMM_CMD_DESC;
- ret = ipa3_send_cmd(1, &desc);
- if (ret) {
- IPAERR("failed to send immediate command (error %d)\n", ret);
- goto destroy_imm;
- }
- stats = kzalloc(sizeof(*stats), GFP_KERNEL);
- if (!stats) {
- ret = -ENOMEM;
- goto destroy_imm;
- }
- ret = ipahal_parse_stats(IPAHAL_HW_STATS_QUOTA,
- &ipa3_ctx->hw_stats.quota.init, mem.base, stats);
- if (ret) {
- IPAERR("failed to parse stats (error %d)\n", ret);
- goto free_stats;
- }
- /*
- * update driver cache.
- * the stats were read from hardware with clear_after_read meaning
- * hardware stats are 0 now
- */
- for (i = 0; i < IPA_CLIENT_MAX; i++) {
- int ep_idx = ipa3_get_ep_mapping(i);
- if (ep_idx == -1 || ep_idx >= IPA3_MAX_NUM_PIPES)
- continue;
- if (ipa3_ctx->ep[ep_idx].client != i)
- continue;
- ipa3_ctx->hw_stats.quota.stats.client[i].num_ipv4_bytes +=
- stats->stats[ep_idx].num_ipv4_bytes;
- ipa3_ctx->hw_stats.quota.stats.client[i].num_ipv4_pkts +=
- stats->stats[ep_idx].num_ipv4_pkts;
- ipa3_ctx->hw_stats.quota.stats.client[i].num_ipv6_bytes +=
- stats->stats[ep_idx].num_ipv6_bytes;
- ipa3_ctx->hw_stats.quota.stats.client[i].num_ipv6_pkts +=
- stats->stats[ep_idx].num_ipv6_pkts;
- }
- /* copy results to out parameter */
- if (out)
- *out = ipa3_ctx->hw_stats.quota.stats;
- ret = 0;
- free_stats:
- kfree(stats);
- destroy_imm:
- ipahal_destroy_imm_cmd(cmd_pyld);
- free_dma_mem:
- dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
- return ret;
- }
- int ipa_reset_quota_stats(enum ipa_client_type client)
- {
- int ret;
- struct ipa_quota_stats *stats;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- if (client >= IPA_CLIENT_MAX) {
- IPAERR("invalid client %d\n", client);
- return -EINVAL;
- }
- /* reading stats will reset them in hardware */
- ret = ipa_get_quota_stats(NULL);
- if (ret) {
- IPAERR("ipa_get_quota_stats failed %d\n", ret);
- return ret;
- }
- /* reset driver's cache */
- stats = &ipa3_ctx->hw_stats.quota.stats.client[client];
- memset(stats, 0, sizeof(*stats));
- return 0;
- }
- int ipa_reset_all_quota_stats(void)
- {
- int ret;
- struct ipa_quota_stats_all *stats;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- /* reading stats will reset them in hardware */
- ret = ipa_get_quota_stats(NULL);
- if (ret) {
- IPAERR("ipa_get_quota_stats failed %d\n", ret);
- return ret;
- }
- /* reset driver's cache */
- stats = &ipa3_ctx->hw_stats.quota.stats;
- memset(stats, 0, sizeof(*stats));
- return 0;
- }
- int ipa_init_teth_stats(struct ipa_teth_stats_endpoints *in)
- {
- struct ipahal_stats_init_pyld *pyld;
- struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
- struct ipahal_imm_cmd_pyld *cmd_pyld;
- struct ipahal_imm_cmd_register_write teth_base = {0};
- struct ipahal_imm_cmd_pyld *teth_base_pyld;
- struct ipahal_imm_cmd_register_write teth_mask = { 0 };
- struct ipahal_imm_cmd_pyld *teth_mask_pyld;
- struct ipa3_desc desc[3] = { {0} };
- dma_addr_t dma_address;
- int ret;
- int i;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- if (!in || !in->prod_mask) {
- IPAERR("invalid params\n");
- return -EINVAL;
- }
- for (i = 0; i < IPA_STATS_MAX_PIPE_BIT; i++) {
- if ((in->prod_mask & (1 << i)) && !in->dst_ep_mask[i]) {
- IPAERR("prod %d doesn't have cons\n", i);
- return -EINVAL;
- }
- }
- IPADBG_LOW("prod_mask=0x%x\n", in->prod_mask);
- /* reset driver's cache */
- memset(&ipa3_ctx->hw_stats.teth.init, 0,
- sizeof(ipa3_ctx->hw_stats.teth.init));
- for (i = 0; i < IPA_CLIENT_MAX; i++) {
- memset(&ipa3_ctx->hw_stats.teth.prod_stats_sum[i], 0,
- sizeof(ipa3_ctx->hw_stats.teth.prod_stats_sum[i]));
- memset(&ipa3_ctx->hw_stats.teth.prod_stats[i], 0,
- sizeof(ipa3_ctx->hw_stats.teth.prod_stats[i]));
- }
- ipa3_ctx->hw_stats.teth.init.prod_bitmask = in->prod_mask;
- memcpy(ipa3_ctx->hw_stats.teth.init.cons_bitmask, in->dst_ep_mask,
- sizeof(ipa3_ctx->hw_stats.teth.init.cons_bitmask));
- pyld = ipahal_stats_generate_init_pyld(IPAHAL_HW_STATS_TETHERING,
- &ipa3_ctx->hw_stats.teth.init, false);
- if (!pyld) {
- IPAERR("failed to generate pyld\n");
- return -EPERM;
- }
- if (pyld->len > IPA_MEM_PART(stats_tethering_size)) {
- IPAERR("SRAM partition too small: %d needed %d\n",
- IPA_MEM_PART(stats_tethering_size), pyld->len);
- ret = -EPERM;
- goto destroy_init_pyld;
- }
- dma_address = dma_map_single(ipa3_ctx->pdev,
- pyld->data,
- pyld->len,
- DMA_TO_DEVICE);
- if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) {
- IPAERR("failed to DMA map\n");
- ret = -EPERM;
- goto destroy_init_pyld;
- }
- /* setting the registers and init the stats pyld are done atomically */
- teth_mask.skip_pipeline_clear = false;
- teth_mask.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- teth_mask.offset = ipahal_get_reg_n_ofst(IPA_STAT_TETHERING_MASK_n,
- ipa3_ctx->ee);
- teth_mask.value = in->prod_mask;
- teth_mask.value_mask = ~0;
- teth_mask_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
- &teth_mask, false);
- if (!teth_mask_pyld) {
- IPAERR("failed to construct register_write imm cmd\n");
- ret = -ENOMEM;
- goto unmap;
- }
- desc[0].opcode = teth_mask_pyld->opcode;
- desc[0].pyld = teth_mask_pyld->data;
- desc[0].len = teth_mask_pyld->len;
- desc[0].type = IPA_IMM_CMD_DESC;
- teth_base.skip_pipeline_clear = false;
- teth_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- teth_base.offset = ipahal_get_reg_n_ofst(IPA_STAT_TETHERING_BASE_n,
- ipa3_ctx->ee);
- teth_base.value = ipa3_ctx->smem_restricted_bytes +
- IPA_MEM_PART(stats_tethering_ofst);
- teth_base.value_mask = ~0;
- teth_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
- &teth_base, false);
- if (!teth_base_pyld) {
- IPAERR("failed to construct register_write imm cmd\n");
- ret = -ENOMEM;
- goto destroy_teth_mask;
- }
- desc[1].opcode = teth_base_pyld->opcode;
- desc[1].pyld = teth_base_pyld->data;
- desc[1].len = teth_base_pyld->len;
- desc[1].type = IPA_IMM_CMD_DESC;
- cmd.is_read = false;
- cmd.skip_pipeline_clear = false;
- cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- cmd.size = pyld->len;
- cmd.system_addr = dma_address;
- cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
- IPA_MEM_PART(stats_tethering_ofst);
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
- if (!cmd_pyld) {
- IPAERR("failed to construct dma_shared_mem imm cmd\n");
- ret = -ENOMEM;
- goto destroy_teth_base;
- }
- desc[2].opcode = cmd_pyld->opcode;
- desc[2].pyld = cmd_pyld->data;
- desc[2].len = cmd_pyld->len;
- desc[2].type = IPA_IMM_CMD_DESC;
- ret = ipa3_send_cmd(3, desc);
- if (ret) {
- IPAERR("failed to send immediate command (error %d)\n", ret);
- goto destroy_imm;
- }
- ret = 0;
- destroy_imm:
- ipahal_destroy_imm_cmd(cmd_pyld);
- destroy_teth_base:
- ipahal_destroy_imm_cmd(teth_base_pyld);
- destroy_teth_mask:
- ipahal_destroy_imm_cmd(teth_mask_pyld);
- unmap:
- dma_unmap_single(ipa3_ctx->pdev, dma_address, pyld->len, DMA_TO_DEVICE);
- destroy_init_pyld:
- ipahal_destroy_stats_init_pyld(pyld);
- return ret;
- }
- int ipa_get_teth_stats(void)
- {
- int i, j;
- int ret;
- struct ipahal_stats_get_offset_tethering get_offset = { { 0 } };
- struct ipahal_stats_offset offset = {0};
- struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
- struct ipahal_imm_cmd_pyld *cmd_pyld;
- struct ipa_mem_buffer mem;
- struct ipa3_desc desc = { 0 };
- struct ipahal_stats_tethering_all *stats_all;
- struct ipa_hw_stats_teth *sw_stats = &ipa3_ctx->hw_stats.teth;
- struct ipahal_stats_tethering *stats;
- struct ipa_quota_stats *quota_stats;
- struct ipahal_stats_init_tethering *init =
- (struct ipahal_stats_init_tethering *)
- &ipa3_ctx->hw_stats.teth.init;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- get_offset.init = ipa3_ctx->hw_stats.teth.init;
- ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_TETHERING, &get_offset,
- &offset);
- if (ret) {
- IPAERR("failed to get offset from hal %d\n", ret);
- return ret;
- }
- IPADBG_LOW("offset = %d size = %d\n", offset.offset, offset.size);
- if (offset.size == 0)
- return 0;
- mem.size = offset.size;
- mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
- mem.size,
- &mem.phys_base,
- GFP_KERNEL);
- if (!mem.base) {
- IPAERR("fail to alloc DMA memory\n");
- return ret;
- }
- cmd.is_read = true;
- cmd.clear_after_read = true;
- cmd.skip_pipeline_clear = false;
- cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
- cmd.size = mem.size;
- cmd.system_addr = mem.phys_base;
- cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
- IPA_MEM_PART(stats_tethering_ofst) + offset.offset;
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
- if (!cmd_pyld) {
- IPAERR("failed to construct dma_shared_mem imm cmd\n");
- ret = -ENOMEM;
- goto free_dma_mem;
- }
- desc.opcode = cmd_pyld->opcode;
- desc.pyld = cmd_pyld->data;
- desc.len = cmd_pyld->len;
- desc.type = IPA_IMM_CMD_DESC;
- ret = ipa3_send_cmd(1, &desc);
- if (ret) {
- IPAERR("failed to send immediate command (error %d)\n", ret);
- goto destroy_imm;
- }
- stats_all = kzalloc(sizeof(*stats_all), GFP_KERNEL);
- if (!stats_all) {
- IPADBG("failed to alloc memory\n");
- ret = -ENOMEM;
- goto destroy_imm;
- }
- ret = ipahal_parse_stats(IPAHAL_HW_STATS_TETHERING,
- &ipa3_ctx->hw_stats.teth.init, mem.base, stats_all);
- if (ret) {
- IPAERR("failed to parse stats_all (error %d)\n", ret);
- goto free_stats;
- }
- /* reset prod_stats cache */
- for (i = 0; i < IPA_CLIENT_MAX; i++) {
- memset(&ipa3_ctx->hw_stats.teth.prod_stats[i], 0,
- sizeof(ipa3_ctx->hw_stats.teth.prod_stats[i]));
- }
- /*
- * update driver cache.
- * the stats were read from hardware with clear_after_read meaning
- * hardware stats are 0 now
- */
- for (i = 0; i < IPA_CLIENT_MAX; i++) {
- for (j = 0; j < IPA_CLIENT_MAX; j++) {
- int prod_idx = ipa3_get_ep_mapping(i);
- int cons_idx = ipa3_get_ep_mapping(j);
- if (prod_idx == -1 || prod_idx >= IPA3_MAX_NUM_PIPES)
- continue;
- if (cons_idx == -1 || cons_idx >= IPA3_MAX_NUM_PIPES)
- continue;
- /* save hw-query result */
- if ((init->prod_bitmask & (1 << prod_idx)) &&
- (init->cons_bitmask[prod_idx]
- & (1 << cons_idx))) {
- IPADBG_LOW("prod %d cons %d\n",
- prod_idx, cons_idx);
- stats = &stats_all->stats[prod_idx][cons_idx];
- IPADBG_LOW("num_ipv4_bytes %lld\n",
- stats->num_ipv4_bytes);
- IPADBG_LOW("num_ipv4_pkts %lld\n",
- stats->num_ipv4_pkts);
- IPADBG_LOW("num_ipv6_pkts %lld\n",
- stats->num_ipv6_pkts);
- IPADBG_LOW("num_ipv6_bytes %lld\n",
- stats->num_ipv6_bytes);
- /* update stats*/
- quota_stats =
- &sw_stats->prod_stats[i].client[j];
- quota_stats->num_ipv4_bytes =
- stats->num_ipv4_bytes;
- quota_stats->num_ipv4_pkts =
- stats->num_ipv4_pkts;
- quota_stats->num_ipv6_bytes =
- stats->num_ipv6_bytes;
- quota_stats->num_ipv6_pkts =
- stats->num_ipv6_pkts;
- /* Accumulated stats */
- quota_stats =
- &sw_stats->prod_stats_sum[i].client[j];
- quota_stats->num_ipv4_bytes +=
- stats->num_ipv4_bytes;
- quota_stats->num_ipv4_pkts +=
- stats->num_ipv4_pkts;
- quota_stats->num_ipv6_bytes +=
- stats->num_ipv6_bytes;
- quota_stats->num_ipv6_pkts +=
- stats->num_ipv6_pkts;
- }
- }
- }
- ret = 0;
- free_stats:
- kfree(stats_all);
- stats = NULL;
- destroy_imm:
- ipahal_destroy_imm_cmd(cmd_pyld);
- free_dma_mem:
- dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
- return ret;
- }
- int ipa_query_teth_stats(enum ipa_client_type prod,
- struct ipa_quota_stats_all *out, bool reset)
- {
- if (!IPA_CLIENT_IS_PROD(prod) || ipa3_get_ep_mapping(prod) == -1) {
- IPAERR("invalid prod %d\n", prod);
- return -EINVAL;
- }
- /* copy results to out parameter */
- if (reset)
- *out = ipa3_ctx->hw_stats.teth.prod_stats[prod];
- else
- *out = ipa3_ctx->hw_stats.teth.prod_stats_sum[prod];
- return 0;
- }
- int ipa_reset_teth_stats(enum ipa_client_type prod, enum ipa_client_type cons)
- {
- int ret;
- struct ipa_quota_stats *stats;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- if (!IPA_CLIENT_IS_PROD(prod) || !IPA_CLIENT_IS_CONS(cons)) {
- IPAERR("invalid prod %d or cons %d\n", prod, cons);
- return -EINVAL;
- }
- /* reading stats will reset them in hardware */
- ret = ipa_get_teth_stats();
- if (ret) {
- IPAERR("ipa_get_teth_stats failed %d\n", ret);
- return ret;
- }
- /* reset driver's cache */
- stats = &ipa3_ctx->hw_stats.teth.prod_stats_sum[prod].client[cons];
- memset(stats, 0, sizeof(*stats));
- return 0;
- }
- int ipa_reset_all_cons_teth_stats(enum ipa_client_type prod)
- {
- int ret;
- int i;
- struct ipa_quota_stats *stats;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- if (!IPA_CLIENT_IS_PROD(prod)) {
- IPAERR("invalid prod %d\n", prod);
- return -EINVAL;
- }
- /* reading stats will reset them in hardware */
- ret = ipa_get_teth_stats();
- if (ret) {
- IPAERR("ipa_get_teth_stats failed %d\n", ret);
- return ret;
- }
- /* reset driver's cache */
- for (i = 0; i < IPA_CLIENT_MAX; i++) {
- stats = &ipa3_ctx->hw_stats.teth.prod_stats_sum[prod].client[i];
- memset(stats, 0, sizeof(*stats));
- }
- return 0;
- }
- int ipa_reset_all_teth_stats(void)
- {
- int i;
- int ret;
- struct ipa_quota_stats_all *stats;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- /* reading stats will reset them in hardware */
- for (i = 0; i < IPA_CLIENT_MAX; i++) {
- if (IPA_CLIENT_IS_PROD(i) && ipa3_get_ep_mapping(i) != -1) {
- ret = ipa_get_teth_stats();
- if (ret) {
- IPAERR("ipa_get_teth_stats failed %d\n", ret);
- return ret;
- }
- /* a single iteration will reset all hardware stats */
- break;
- }
- }
- /* reset driver's cache */
- for (i = 0; i < IPA_CLIENT_MAX; i++) {
- stats = &ipa3_ctx->hw_stats.teth.prod_stats_sum[i];
- memset(stats, 0, sizeof(*stats));
- }
- return 0;
- }
- int ipa_init_flt_rt_stats(void)
- {
- struct ipahal_stats_init_pyld *pyld;
- int smem_ofst, smem_size;
- int stats_base_flt_v4, stats_base_flt_v6;
- int stats_base_rt_v4, stats_base_rt_v6;
- struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
- struct ipahal_imm_cmd_pyld *cmd_pyld;
- struct ipahal_imm_cmd_register_write flt_v4_base = {0};
- struct ipahal_imm_cmd_pyld *flt_v4_base_pyld;
- struct ipahal_imm_cmd_register_write flt_v6_base = {0};
- struct ipahal_imm_cmd_pyld *flt_v6_base_pyld;
- struct ipahal_imm_cmd_register_write rt_v4_base = {0};
- struct ipahal_imm_cmd_pyld *rt_v4_base_pyld;
- struct ipahal_imm_cmd_register_write rt_v6_base = {0};
- struct ipahal_imm_cmd_pyld *rt_v6_base_pyld;
- struct ipa3_desc desc[5] = { {0} };
- dma_addr_t dma_address;
- int ret;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- smem_ofst = IPA_MEM_PART(stats_fnr_ofst);
- smem_size = IPA_MEM_PART(stats_fnr_size);
- pyld = ipahal_stats_generate_init_pyld(IPAHAL_HW_STATS_FNR,
- (void *)(uintptr_t)(IPA_MAX_FLT_RT_CNT_INDEX), false);
- if (!pyld) {
- IPAERR("failed to generate pyld\n");
- return -EPERM;
- }
- if (pyld->len > smem_size) {
- IPAERR("SRAM partition too small: %d needed %d\n",
- smem_size, pyld->len);
- ret = -EPERM;
- goto destroy_init_pyld;
- }
- dma_address = dma_map_single(ipa3_ctx->pdev,
- pyld->data,
- pyld->len,
- DMA_TO_DEVICE);
- if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) {
- IPAERR("failed to DMA map\n");
- ret = -EPERM;
- goto destroy_init_pyld;
- }
- stats_base_flt_v4 = ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV4_BASE);
- stats_base_flt_v6 = ipahal_get_reg_ofst(IPA_STAT_FILTER_IPV6_BASE);
- stats_base_rt_v4 = ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV4_BASE);
- stats_base_rt_v6 = ipahal_get_reg_ofst(IPA_STAT_ROUTER_IPV6_BASE);
- /* setting the registers and init the stats pyld are done atomically */
- /* set IPA_STAT_FILTER_IPV4_BASE */
- flt_v4_base.skip_pipeline_clear = false;
- flt_v4_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- flt_v4_base.offset = stats_base_flt_v4;
- flt_v4_base.value = ipa3_ctx->smem_restricted_bytes +
- smem_ofst;
- flt_v4_base.value_mask = ~0;
- flt_v4_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
- &flt_v4_base, false);
- if (!flt_v4_base_pyld) {
- IPAERR("failed to construct register_write imm cmd\n");
- ret = -ENOMEM;
- goto unmap;
- }
- desc[0].opcode = flt_v4_base_pyld->opcode;
- desc[0].pyld = flt_v4_base_pyld->data;
- desc[0].len = flt_v4_base_pyld->len;
- desc[0].type = IPA_IMM_CMD_DESC;
- /* set IPA_STAT_FILTER_IPV6_BASE */
- flt_v6_base.skip_pipeline_clear = false;
- flt_v6_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- flt_v6_base.offset = stats_base_flt_v6;
- flt_v6_base.value = ipa3_ctx->smem_restricted_bytes +
- smem_ofst;
- flt_v6_base.value_mask = ~0;
- flt_v6_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
- &flt_v6_base, false);
- if (!flt_v6_base_pyld) {
- IPAERR("failed to construct register_write imm cmd\n");
- ret = -ENOMEM;
- goto destroy_flt_v4_base;
- }
- desc[1].opcode = flt_v6_base_pyld->opcode;
- desc[1].pyld = flt_v6_base_pyld->data;
- desc[1].len = flt_v6_base_pyld->len;
- desc[1].type = IPA_IMM_CMD_DESC;
- /* set IPA_STAT_ROUTER_IPV4_BASE */
- rt_v4_base.skip_pipeline_clear = false;
- rt_v4_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- rt_v4_base.offset = stats_base_rt_v4;
- rt_v4_base.value = ipa3_ctx->smem_restricted_bytes +
- smem_ofst;
- rt_v4_base.value_mask = ~0;
- rt_v4_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
- &rt_v4_base, false);
- if (!rt_v4_base_pyld) {
- IPAERR("failed to construct register_write imm cmd\n");
- ret = -ENOMEM;
- goto destroy_flt_v6_base;
- }
- desc[2].opcode = rt_v4_base_pyld->opcode;
- desc[2].pyld = rt_v4_base_pyld->data;
- desc[2].len = rt_v4_base_pyld->len;
- desc[2].type = IPA_IMM_CMD_DESC;
- /* set IPA_STAT_ROUTER_IPV6_BASE */
- rt_v6_base.skip_pipeline_clear = false;
- rt_v6_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- rt_v6_base.offset = stats_base_rt_v6;
- rt_v6_base.value = ipa3_ctx->smem_restricted_bytes +
- smem_ofst;
- rt_v6_base.value_mask = ~0;
- rt_v6_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
- &rt_v6_base, false);
- if (!rt_v6_base_pyld) {
- IPAERR("failed to construct register_write imm cmd\n");
- ret = -ENOMEM;
- goto destroy_rt_v4_base;
- }
- desc[3].opcode = rt_v6_base_pyld->opcode;
- desc[3].pyld = rt_v6_base_pyld->data;
- desc[3].len = rt_v6_base_pyld->len;
- desc[3].type = IPA_IMM_CMD_DESC;
- cmd.is_read = false;
- cmd.skip_pipeline_clear = false;
- cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- cmd.size = pyld->len;
- cmd.system_addr = dma_address;
- cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
- smem_ofst;
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
- if (!cmd_pyld) {
- IPAERR("failed to construct dma_shared_mem imm cmd\n");
- ret = -ENOMEM;
- goto destroy_rt_v6_base;
- }
- desc[4].opcode = cmd_pyld->opcode;
- desc[4].pyld = cmd_pyld->data;
- desc[4].len = cmd_pyld->len;
- desc[4].type = IPA_IMM_CMD_DESC;
- ret = ipa3_send_cmd(5, desc);
- if (ret) {
- IPAERR("failed to send immediate command (error %d)\n", ret);
- goto destroy_imm;
- }
- ret = 0;
- destroy_imm:
- ipahal_destroy_imm_cmd(cmd_pyld);
- destroy_rt_v6_base:
- ipahal_destroy_imm_cmd(rt_v6_base_pyld);
- destroy_rt_v4_base:
- ipahal_destroy_imm_cmd(rt_v4_base_pyld);
- destroy_flt_v6_base:
- ipahal_destroy_imm_cmd(flt_v6_base_pyld);
- destroy_flt_v4_base:
- ipahal_destroy_imm_cmd(flt_v4_base_pyld);
- unmap:
- dma_unmap_single(ipa3_ctx->pdev, dma_address, pyld->len, DMA_TO_DEVICE);
- destroy_init_pyld:
- ipahal_destroy_stats_init_pyld(pyld);
- return ret;
- }
- static int __ipa_get_flt_rt_stats(struct ipa_ioc_flt_rt_query *query)
- {
- int ret;
- int smem_ofst;
- bool clear = query->reset;
- struct ipahal_stats_get_offset_flt_rt_v4_5 *get_offset;
- struct ipahal_stats_offset offset = { 0 };
- struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
- struct ipahal_imm_cmd_pyld *cmd_pyld;
- struct ipa_mem_buffer mem;
- struct ipa3_desc desc = { 0 };
- get_offset = kzalloc(sizeof(*get_offset), GFP_KERNEL);
- if (!get_offset) {
- IPADBG("no mem\n");
- return -ENOMEM;
- }
- smem_ofst = IPA_MEM_PART(stats_fnr_ofst);
- get_offset->start_id = query->start_id;
- get_offset->end_id = query->end_id;
- ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_FNR, get_offset,
- &offset);
- if (ret) {
- IPAERR("failed to get offset from hal %d\n", ret);
- goto free_offset;
- }
- IPADBG("offset = %d size = %d\n", offset.offset, offset.size);
- if (offset.size == 0) {
- ret = 0;
- goto free_offset;
- }
- mem.size = offset.size;
- mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
- mem.size,
- &mem.phys_base,
- GFP_KERNEL);
- if (!mem.base) {
- IPAERR("fail to alloc DMA memory\n");
- goto free_offset;
- }
- cmd.is_read = true;
- cmd.clear_after_read = clear;
- cmd.skip_pipeline_clear = false;
- cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
- cmd.size = mem.size;
- cmd.system_addr = mem.phys_base;
- cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
- smem_ofst + offset.offset;
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
- if (!cmd_pyld) {
- IPAERR("failed to construct dma_shared_mem imm cmd\n");
- ret = -ENOMEM;
- goto free_dma_mem;
- }
- desc.opcode = cmd_pyld->opcode;
- desc.pyld = cmd_pyld->data;
- desc.len = cmd_pyld->len;
- desc.type = IPA_IMM_CMD_DESC;
- ret = ipa3_send_cmd(1, &desc);
- if (ret) {
- IPAERR("failed to send immediate command (error %d)\n", ret);
- goto destroy_imm;
- }
- ret = ipahal_parse_stats(IPAHAL_HW_STATS_FNR,
- NULL, mem.base, query);
- if (ret) {
- IPAERR("failed to parse stats (error %d)\n", ret);
- goto destroy_imm;
- }
- ret = 0;
- destroy_imm:
- ipahal_destroy_imm_cmd(cmd_pyld);
- free_dma_mem:
- dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
- free_offset:
- kfree(get_offset);
- return ret;
- }
- int ipa_get_flt_rt_stats(struct ipa_ioc_flt_rt_query *query)
- {
- if (!ipa3_ctx->hw_stats.enabled) {
- IPAERR("hw_stats is not enabled\n");
- return 0;
- }
- if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) {
- IPAERR("FnR stats not supported in %d hw_type\n",
- ipa3_ctx->ipa_hw_type);
- return 0;
- }
- if (query->start_id == 0 || query->end_id == 0) {
- IPAERR("Invalid start_id/end_id, must be not 0\n");
- IPAERR("start_id %d, end_id %d\n",
- query->start_id, query->end_id);
- return -EINVAL;
- }
- if (query->start_id > IPA_MAX_FLT_RT_CNT_INDEX) {
- IPAERR("start_cnt_id %d out of range\n", query->start_id);
- return -EINVAL;
- }
- if (query->end_id > IPA_MAX_FLT_RT_CNT_INDEX) {
- IPAERR("end_cnt_id %d out of range\n", query->end_id);
- return -EINVAL;
- }
- if (query->end_id < query->start_id) {
- IPAERR("end_id %d < start_id %d\n",
- query->end_id, query->start_id);
- return -EINVAL;
- }
- if (query->stats_size > sizeof(struct ipa_flt_rt_stats)) {
- IPAERR("stats_size %d > ipa_flt_rt_stats %d\n",
- query->stats_size, sizeof(struct ipa_flt_rt_stats));
- return -EINVAL;
- }
- return __ipa_get_flt_rt_stats(query);
- }
- static int __ipa_set_flt_rt_stats(int index, struct ipa_flt_rt_stats stats)
- {
- int ret;
- int smem_ofst;
- struct ipahal_stats_get_offset_flt_rt_v4_5 *get_offset;
- struct ipahal_stats_offset offset = { 0 };
- struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
- struct ipahal_imm_cmd_pyld *cmd_pyld;
- struct ipa_mem_buffer mem;
- struct ipa3_desc desc = { 0 };
- get_offset = kzalloc(sizeof(*get_offset), GFP_KERNEL);
- if (!get_offset) {
- IPADBG("no mem\n");
- return -ENOMEM;
- }
- smem_ofst = IPA_MEM_PART(stats_fnr_ofst);
- get_offset->start_id = index;
- get_offset->end_id = index;
- ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_FNR, get_offset,
- &offset);
- if (ret) {
- IPAERR("failed to get offset from hal %d\n", ret);
- goto free_offset;
- }
- IPADBG("offset = %d size = %d\n", offset.offset, offset.size);
- if (offset.size == 0) {
- ret = 0;
- goto free_offset;
- }
- mem.size = offset.size;
- mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
- mem.size,
- &mem.phys_base,
- GFP_KERNEL);
- if (!mem.base) {
- IPAERR("fail to alloc DMA memory\n");
- goto free_offset;
- }
- ipahal_set_flt_rt_sw_stats(mem.base, stats);
- cmd.is_read = false;
- cmd.skip_pipeline_clear = false;
- cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
- cmd.size = mem.size;
- cmd.system_addr = mem.phys_base;
- cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
- smem_ofst + offset.offset;
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
- if (!cmd_pyld) {
- IPAERR("failed to construct dma_shared_mem imm cmd\n");
- ret = -ENOMEM;
- goto free_dma_mem;
- }
- desc.opcode = cmd_pyld->opcode;
- desc.pyld = cmd_pyld->data;
- desc.len = cmd_pyld->len;
- desc.type = IPA_IMM_CMD_DESC;
- ret = ipa3_send_cmd(1, &desc);
- if (ret) {
- IPAERR("failed to send immediate command (error %d)\n", ret);
- goto destroy_imm;
- }
- ret = 0;
- destroy_imm:
- ipahal_destroy_imm_cmd(cmd_pyld);
- free_dma_mem:
- dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
- free_offset:
- kfree(get_offset);
- return ret;
- }
- int ipa_set_flt_rt_stats(int index, struct ipa_flt_rt_stats stats)
- {
- if (!ipa3_ctx->hw_stats.enabled) {
- IPAERR("hw_stats is not enabled\n");
- return 0;
- }
- if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) {
- IPAERR("FnR stats not supported in %d hw_type\n",
- ipa3_ctx->ipa_hw_type);
- return 0;
- }
- if (index > IPA_MAX_FLT_RT_CNT_INDEX) {
- IPAERR("index %d out of range\n", index);
- return -EINVAL;
- }
- if (index <= IPA_FLT_RT_HW_COUNTER) {
- IPAERR("index %d invalid, only support sw counter set\n",
- index);
- return -EINVAL;
- }
- return __ipa_set_flt_rt_stats(index, stats);
- }
- int ipa_init_drop_stats(u32 pipe_bitmask)
- {
- struct ipahal_stats_init_pyld *pyld;
- struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
- struct ipahal_imm_cmd_pyld *cmd_pyld;
- struct ipahal_imm_cmd_register_write drop_base = {0};
- struct ipahal_imm_cmd_pyld *drop_base_pyld;
- struct ipahal_imm_cmd_register_write drop_mask = {0};
- struct ipahal_imm_cmd_pyld *drop_mask_pyld;
- struct ipa3_desc desc[3] = { {0} };
- dma_addr_t dma_address;
- int ret;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- /* reset driver's cache */
- memset(&ipa3_ctx->hw_stats.drop, 0, sizeof(ipa3_ctx->hw_stats.drop));
- ipa3_ctx->hw_stats.drop.init.enabled_bitmask = pipe_bitmask;
- IPADBG_LOW("pipe_bitmask=0x%x\n", pipe_bitmask);
- pyld = ipahal_stats_generate_init_pyld(IPAHAL_HW_STATS_DROP,
- &ipa3_ctx->hw_stats.drop.init, false);
- if (!pyld) {
- IPAERR("failed to generate pyld\n");
- return -EPERM;
- }
- if (pyld->len > IPA_MEM_PART(stats_drop_size)) {
- IPAERR("SRAM partition too small: %d needed %d\n",
- IPA_MEM_PART(stats_drop_size), pyld->len);
- ret = -EPERM;
- goto destroy_init_pyld;
- }
- dma_address = dma_map_single(ipa3_ctx->pdev,
- pyld->data,
- pyld->len,
- DMA_TO_DEVICE);
- if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) {
- IPAERR("failed to DMA map\n");
- ret = -EPERM;
- goto destroy_init_pyld;
- }
- /* setting the registers and init the stats pyld are done atomically */
- drop_mask.skip_pipeline_clear = false;
- drop_mask.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- drop_mask.offset = ipahal_get_reg_n_ofst(IPA_STAT_DROP_CNT_MASK_n,
- ipa3_ctx->ee);
- drop_mask.value = pipe_bitmask;
- drop_mask.value_mask = ~0;
- drop_mask_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
- &drop_mask, false);
- if (!drop_mask_pyld) {
- IPAERR("failed to construct register_write imm cmd\n");
- ret = -ENOMEM;
- goto unmap;
- }
- desc[0].opcode = drop_mask_pyld->opcode;
- desc[0].pyld = drop_mask_pyld->data;
- desc[0].len = drop_mask_pyld->len;
- desc[0].type = IPA_IMM_CMD_DESC;
- drop_base.skip_pipeline_clear = false;
- drop_base.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- drop_base.offset = ipahal_get_reg_n_ofst(IPA_STAT_DROP_CNT_BASE_n,
- ipa3_ctx->ee);
- drop_base.value = ipa3_ctx->smem_restricted_bytes +
- IPA_MEM_PART(stats_drop_ofst);
- drop_base.value_mask = ~0;
- drop_base_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_REGISTER_WRITE,
- &drop_base, false);
- if (!drop_base_pyld) {
- IPAERR("failed to construct register_write imm cmd\n");
- ret = -ENOMEM;
- goto destroy_drop_mask;
- }
- desc[1].opcode = drop_base_pyld->opcode;
- desc[1].pyld = drop_base_pyld->data;
- desc[1].len = drop_base_pyld->len;
- desc[1].type = IPA_IMM_CMD_DESC;
- cmd.is_read = false;
- cmd.skip_pipeline_clear = false;
- cmd.pipeline_clear_options = IPAHAL_FULL_PIPELINE_CLEAR;
- cmd.size = pyld->len;
- cmd.system_addr = dma_address;
- cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
- IPA_MEM_PART(stats_drop_ofst);
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
- if (!cmd_pyld) {
- IPAERR("failed to construct dma_shared_mem imm cmd\n");
- ret = -ENOMEM;
- goto destroy_drop_base;
- }
- desc[2].opcode = cmd_pyld->opcode;
- desc[2].pyld = cmd_pyld->data;
- desc[2].len = cmd_pyld->len;
- desc[2].type = IPA_IMM_CMD_DESC;
- ret = ipa3_send_cmd(3, desc);
- if (ret) {
- IPAERR("failed to send immediate command (error %d)\n", ret);
- goto destroy_imm;
- }
- ret = 0;
- destroy_imm:
- ipahal_destroy_imm_cmd(cmd_pyld);
- destroy_drop_base:
- ipahal_destroy_imm_cmd(drop_base_pyld);
- destroy_drop_mask:
- ipahal_destroy_imm_cmd(drop_mask_pyld);
- unmap:
- dma_unmap_single(ipa3_ctx->pdev, dma_address, pyld->len, DMA_TO_DEVICE);
- destroy_init_pyld:
- ipahal_destroy_stats_init_pyld(pyld);
- return ret;
- }
- int ipa_get_drop_stats(struct ipa_drop_stats_all *out)
- {
- int i;
- int ret;
- struct ipahal_stats_get_offset_drop get_offset = { { 0 } };
- struct ipahal_stats_offset offset = { 0 };
- struct ipahal_imm_cmd_dma_shared_mem cmd = { 0 };
- struct ipahal_imm_cmd_pyld *cmd_pyld;
- struct ipa_mem_buffer mem;
- struct ipa3_desc desc = { 0 };
- struct ipahal_stats_drop_all *stats;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- get_offset.init = ipa3_ctx->hw_stats.drop.init;
- ret = ipahal_stats_get_offset(IPAHAL_HW_STATS_DROP, &get_offset,
- &offset);
- if (ret) {
- IPAERR("failed to get offset from hal %d\n", ret);
- return ret;
- }
- IPADBG_LOW("offset = %d size = %d\n", offset.offset, offset.size);
- if (offset.size == 0)
- return 0;
- mem.size = offset.size;
- mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
- mem.size,
- &mem.phys_base,
- GFP_KERNEL);
- if (!mem.base) {
- IPAERR("fail to alloc DMA memory\n");
- return ret;
- }
- cmd.is_read = true;
- cmd.clear_after_read = true;
- cmd.skip_pipeline_clear = false;
- cmd.pipeline_clear_options = IPAHAL_HPS_CLEAR;
- cmd.size = mem.size;
- cmd.system_addr = mem.phys_base;
- cmd.local_addr = ipa3_ctx->smem_restricted_bytes +
- IPA_MEM_PART(stats_drop_ofst) + offset.offset;
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_SHARED_MEM, &cmd, false);
- if (!cmd_pyld) {
- IPAERR("failed to construct dma_shared_mem imm cmd\n");
- ret = -ENOMEM;
- goto free_dma_mem;
- }
- desc.opcode = cmd_pyld->opcode;
- desc.pyld = cmd_pyld->data;
- desc.len = cmd_pyld->len;
- desc.type = IPA_IMM_CMD_DESC;
- ret = ipa3_send_cmd(1, &desc);
- if (ret) {
- IPAERR("failed to send immediate command (error %d)\n", ret);
- goto destroy_imm;
- }
- stats = kzalloc(sizeof(*stats), GFP_KERNEL);
- if (!stats) {
- ret = -ENOMEM;
- goto destroy_imm;
- }
- ret = ipahal_parse_stats(IPAHAL_HW_STATS_DROP,
- &ipa3_ctx->hw_stats.drop.init, mem.base, stats);
- if (ret) {
- IPAERR("failed to parse stats (error %d)\n", ret);
- goto free_stats;
- }
- /*
- * update driver cache.
- * the stats were read from hardware with clear_after_read meaning
- * hardware stats are 0 now
- */
- for (i = 0; i < IPA_CLIENT_MAX; i++) {
- int ep_idx = ipa3_get_ep_mapping(i);
- if (ep_idx == -1 || ep_idx >= IPA3_MAX_NUM_PIPES)
- continue;
- if (ipa3_ctx->ep[ep_idx].client != i)
- continue;
- ipa3_ctx->hw_stats.drop.stats.client[i].drop_byte_cnt +=
- stats->stats[ep_idx].drop_byte_cnt;
- ipa3_ctx->hw_stats.drop.stats.client[i].drop_packet_cnt +=
- stats->stats[ep_idx].drop_packet_cnt;
- }
- if (!out) {
- ret = 0;
- goto free_stats;
- }
- /* copy results to out parameter */
- *out = ipa3_ctx->hw_stats.drop.stats;
- ret = 0;
- free_stats:
- kfree(stats);
- destroy_imm:
- ipahal_destroy_imm_cmd(cmd_pyld);
- free_dma_mem:
- dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base, mem.phys_base);
- return ret;
- }
- int ipa_reset_drop_stats(enum ipa_client_type client)
- {
- int ret;
- struct ipa_drop_stats *stats;
- if (client >= IPA_CLIENT_MAX) {
- IPAERR("invalid client %d\n", client);
- return -EINVAL;
- }
- /* reading stats will reset them in hardware */
- ret = ipa_get_drop_stats(NULL);
- if (ret) {
- IPAERR("ipa_get_drop_stats failed %d\n", ret);
- return ret;
- }
- /* reset driver's cache */
- stats = &ipa3_ctx->hw_stats.drop.stats.client[client];
- memset(stats, 0, sizeof(*stats));
- return 0;
- }
- int ipa_reset_all_drop_stats(void)
- {
- int ret;
- struct ipa_drop_stats_all *stats;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- /* reading stats will reset them in hardware */
- ret = ipa_get_drop_stats(NULL);
- if (ret) {
- IPAERR("ipa_get_drop_stats failed %d\n", ret);
- return ret;
- }
- /* reset driver's cache */
- stats = &ipa3_ctx->hw_stats.drop.stats;
- memset(stats, 0, sizeof(*stats));
- return 0;
- }
- #ifndef CONFIG_DEBUG_FS
- int ipa_debugfs_init_stats(struct dentry *parent) { return 0; }
- #else
- #define IPA_MAX_MSG_LEN 4096
- static char dbg_buff[IPA_MAX_MSG_LEN];
- static ssize_t ipa_debugfs_reset_quota_stats(struct file *file,
- const char __user *ubuf, size_t count, loff_t *ppos)
- {
- s8 client = 0;
- int ret;
- mutex_lock(&ipa3_ctx->lock);
- ret = kstrtos8_from_user(ubuf, count, 0, &client);
- if (ret)
- goto bail;
- if (client == -1)
- ipa_reset_all_quota_stats();
- else
- ipa_reset_quota_stats(client);
- ret = count;
- bail:
- mutex_unlock(&ipa3_ctx->lock);
- return ret;
- }
- static ssize_t ipa_debugfs_print_quota_stats(struct file *file,
- char __user *ubuf, size_t count, loff_t *ppos)
- {
- int nbytes = 0;
- struct ipa_quota_stats_all *out;
- int i;
- int res;
- out = kzalloc(sizeof(*out), GFP_KERNEL);
- if (!out)
- return -ENOMEM;
- mutex_lock(&ipa3_ctx->lock);
- res = ipa_get_quota_stats(out);
- if (res) {
- mutex_unlock(&ipa3_ctx->lock);
- kfree(out);
- return res;
- }
- for (i = 0; i < IPA_CLIENT_MAX; i++) {
- int ep_idx = ipa3_get_ep_mapping(i);
- if (ep_idx == -1)
- continue;
- if (IPA_CLIENT_IS_TEST(i))
- continue;
- if (!(ipa3_ctx->hw_stats.quota.init.enabled_bitmask &
- (1 << ep_idx)))
- continue;
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "%s:\n",
- ipa_clients_strings[i]);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "num_ipv4_bytes=%llu\n",
- out->client[i].num_ipv4_bytes);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "num_ipv6_bytes=%llu\n",
- out->client[i].num_ipv6_bytes);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "num_ipv4_pkts=%u\n",
- out->client[i].num_ipv4_pkts);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "num_ipv6_pkts=%u\n",
- out->client[i].num_ipv6_pkts);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "\n");
- }
- mutex_unlock(&ipa3_ctx->lock);
- kfree(out);
- return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
- }
- static ssize_t ipa_debugfs_reset_tethering_stats(struct file *file,
- const char __user *ubuf, size_t count, loff_t *ppos)
- {
- s8 client = 0;
- int ret;
- mutex_lock(&ipa3_ctx->lock);
- ret = kstrtos8_from_user(ubuf, count, 0, &client);
- if (ret)
- goto bail;
- if (client == -1)
- ipa_reset_all_teth_stats();
- else
- ipa_reset_all_cons_teth_stats(client);
- ret = count;
- bail:
- mutex_unlock(&ipa3_ctx->lock);
- return ret;
- }
- static ssize_t ipa_debugfs_print_tethering_stats(struct file *file,
- char __user *ubuf, size_t count, loff_t *ppos)
- {
- int nbytes = 0;
- struct ipa_quota_stats_all *out;
- int i, j;
- int res;
- out = kzalloc(sizeof(*out), GFP_KERNEL);
- if (!out)
- return -ENOMEM;
- mutex_lock(&ipa3_ctx->lock);
- for (i = 0; i < IPA_CLIENT_MAX; i++) {
- int ep_idx = ipa3_get_ep_mapping(i);
- if (ep_idx == -1)
- continue;
- if (!IPA_CLIENT_IS_PROD(i))
- continue;
- if (IPA_CLIENT_IS_TEST(i))
- continue;
- if (!(ipa3_ctx->hw_stats.teth.init.prod_bitmask &
- (1 << ep_idx)))
- continue;
- res = ipa_get_teth_stats();
- if (res) {
- mutex_unlock(&ipa3_ctx->lock);
- kfree(out);
- return res;
- }
- for (j = 0; j < IPA_CLIENT_MAX; j++) {
- int cons_idx = ipa3_get_ep_mapping(j);
- if (cons_idx == -1)
- continue;
- if (IPA_CLIENT_IS_TEST(j))
- continue;
- if (!(ipa3_ctx->hw_stats.teth.init.cons_bitmask[ep_idx]
- & (1 << cons_idx)))
- continue;
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "%s->%s:\n",
- ipa_clients_strings[i],
- ipa_clients_strings[j]);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "num_ipv4_bytes=%llu\n",
- out->client[j].num_ipv4_bytes);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "num_ipv6_bytes=%llu\n",
- out->client[j].num_ipv6_bytes);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "num_ipv4_pkts=%u\n",
- out->client[j].num_ipv4_pkts);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "num_ipv6_pkts=%u\n",
- out->client[j].num_ipv6_pkts);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "\n");
- }
- }
- mutex_unlock(&ipa3_ctx->lock);
- kfree(out);
- return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
- }
- static ssize_t ipa_debugfs_control_flt_rt_stats(struct file *file,
- const char __user *ubuf, size_t count, loff_t *ppos)
- {
- struct ipa_ioc_flt_rt_query *query;
- unsigned long missing;
- int pyld_size = 0;
- int ret;
- query = kzalloc(sizeof(struct ipa_ioc_flt_rt_query),
- GFP_KERNEL);
- if (!query)
- return -ENOMEM;
- query->stats_size = sizeof(struct ipa_flt_rt_stats);
- pyld_size = IPA_MAX_FLT_RT_CNT_INDEX *
- sizeof(struct ipa_flt_rt_stats);
- query->stats = (uint64_t)kzalloc(pyld_size, GFP_KERNEL);
- if (!query->stats) {
- kfree(query);
- return -ENOMEM;
- }
- mutex_lock(&ipa3_ctx->lock);
- if (count >= sizeof(dbg_buff)) {
- ret = -EFAULT;
- goto bail;
- }
- missing = copy_from_user(dbg_buff, ubuf, count);
- if (missing) {
- ret = -EFAULT;
- goto bail;
- }
- dbg_buff[count] = '\0';
- if (strcmp(dbg_buff, "reset\n") == 0) {
- query->reset = 1;
- query->start_id = 1;
- query->end_id = IPA_MAX_FLT_RT_CNT_INDEX;
- ipa_get_flt_rt_stats(query);
- } else {
- IPAERR("unsupport flt_rt command\n");
- }
- ret = count;
- bail:
- kfree((void *)(uintptr_t)(query->stats));
- kfree(query);
- mutex_unlock(&ipa3_ctx->lock);
- return ret;
- }
- static ssize_t ipa_debugfs_print_flt_rt_stats(struct file *file,
- char __user *ubuf, size_t count, loff_t *ppos)
- {
- int nbytes = 0;
- int i;
- int res;
- int pyld_size = 0;
- struct ipa_ioc_flt_rt_query *query;
- query = kzalloc(sizeof(struct ipa_ioc_flt_rt_query),
- GFP_KERNEL);
- if (!query)
- return -ENOMEM;
- query->start_id = 1;
- query->end_id = IPA_MAX_FLT_RT_CNT_INDEX;
- query->reset = true;
- query->stats_size = sizeof(struct ipa_flt_rt_stats);
- pyld_size = IPA_MAX_FLT_RT_CNT_INDEX *
- sizeof(struct ipa_flt_rt_stats);
- query->stats = (uint64_t)kzalloc(pyld_size, GFP_KERNEL);
- if (!query->stats) {
- kfree(query);
- return -ENOMEM;
- }
- mutex_lock(&ipa3_ctx->lock);
- res = ipa_get_flt_rt_stats(query);
- if (res) {
- mutex_unlock(&ipa3_ctx->lock);
- kfree((void *)(uintptr_t)(query->stats));
- kfree(query);
- return res;
- }
- for (i = 0; i < IPA_MAX_FLT_RT_CNT_INDEX; i++) {
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "cnt_id: %d\n", i + 1);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "num_pkts: %d\n",
- ((struct ipa_flt_rt_stats *)
- query->stats)[i].num_pkts);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "num_pkts_hash: %d\n",
- ((struct ipa_flt_rt_stats *)
- query->stats)[i].num_pkts_hash);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "num_bytes: %lld\n",
- ((struct ipa_flt_rt_stats *)
- query->stats)[i].num_bytes);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "\n");
- }
- mutex_unlock(&ipa3_ctx->lock);
- kfree((void *)(uintptr_t)(query->stats));
- kfree(query);
- return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
- }
- static ssize_t ipa_debugfs_reset_drop_stats(struct file *file,
- const char __user *ubuf, size_t count, loff_t *ppos)
- {
- s8 client = 0;
- int ret;
- mutex_lock(&ipa3_ctx->lock);
- ret = kstrtos8_from_user(ubuf, count, 0, &client);
- if (ret)
- goto bail;
- if (client == -1)
- ipa_reset_all_drop_stats();
- else
- ipa_reset_drop_stats(client);
- ret = count;
- bail:
- mutex_unlock(&ipa3_ctx->lock);
- return count;
- }
- static ssize_t ipa_debugfs_print_drop_stats(struct file *file,
- char __user *ubuf, size_t count, loff_t *ppos)
- {
- int nbytes = 0;
- struct ipa_drop_stats_all *out;
- int i;
- int res;
- out = kzalloc(sizeof(*out), GFP_KERNEL);
- if (!out)
- return -ENOMEM;
- mutex_lock(&ipa3_ctx->lock);
- res = ipa_get_drop_stats(out);
- if (res) {
- mutex_unlock(&ipa3_ctx->lock);
- kfree(out);
- return res;
- }
- for (i = 0; i < IPA_CLIENT_MAX; i++) {
- int ep_idx = ipa3_get_ep_mapping(i);
- if (ep_idx == -1)
- continue;
- if (!IPA_CLIENT_IS_CONS(i))
- continue;
- if (IPA_CLIENT_IS_TEST(i))
- continue;
- if (!(ipa3_ctx->hw_stats.drop.init.enabled_bitmask &
- (1 << ep_idx)))
- continue;
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "%s:\n",
- ipa_clients_strings[i]);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "drop_byte_cnt=%u\n",
- out->client[i].drop_byte_cnt);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "drop_packet_cnt=%u\n",
- out->client[i].drop_packet_cnt);
- nbytes += scnprintf(dbg_buff + nbytes,
- IPA_MAX_MSG_LEN - nbytes,
- "\n");
- }
- mutex_unlock(&ipa3_ctx->lock);
- kfree(out);
- return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
- }
- static const struct file_operations ipa3_quota_ops = {
- .read = ipa_debugfs_print_quota_stats,
- .write = ipa_debugfs_reset_quota_stats,
- };
- static const struct file_operations ipa3_tethering_ops = {
- .read = ipa_debugfs_print_tethering_stats,
- .write = ipa_debugfs_reset_tethering_stats,
- };
- static const struct file_operations ipa3_flt_rt_ops = {
- .read = ipa_debugfs_print_flt_rt_stats,
- .write = ipa_debugfs_control_flt_rt_stats,
- };
- static const struct file_operations ipa3_drop_ops = {
- .read = ipa_debugfs_print_drop_stats,
- .write = ipa_debugfs_reset_drop_stats,
- };
- int ipa_debugfs_init_stats(struct dentry *parent)
- {
- const mode_t read_write_mode = 0664;
- struct dentry *file;
- struct dentry *dent;
- if (!ipa3_ctx->hw_stats.enabled)
- return 0;
- dent = debugfs_create_dir("hw_stats", parent);
- if (IS_ERR_OR_NULL(dent)) {
- IPAERR("fail to create folder in debug_fs\n");
- return -EFAULT;
- }
- file = debugfs_create_file("quota", read_write_mode, dent, NULL,
- &ipa3_quota_ops);
- if (IS_ERR_OR_NULL(file)) {
- IPAERR("fail to create file %s\n", "quota");
- goto fail;
- }
- file = debugfs_create_file("drop", read_write_mode, dent, NULL,
- &ipa3_drop_ops);
- if (IS_ERR_OR_NULL(file)) {
- IPAERR("fail to create file %s\n", "drop");
- goto fail;
- }
- file = debugfs_create_file("tethering", read_write_mode, dent, NULL,
- &ipa3_tethering_ops);
- if (IS_ERR_OR_NULL(file)) {
- IPAERR("fail to create file %s\n", "tethering");
- goto fail;
- }
- file = debugfs_create_file("flt_rt", read_write_mode, dent, NULL,
- &ipa3_flt_rt_ops);
- if (IS_ERR_OR_NULL(file)) {
- IPAERR("fail to create file flt_rt\n");
- goto fail;
- }
- return 0;
- fail:
- debugfs_remove_recursive(dent);
- return -EFAULT;
- }
- #endif
|