12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
- */
- #include <linux/device.h>
- #include <linux/fs.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/mm.h>
- #include <linux/uaccess.h>
- #include <linux/dma-noncoherent.h>
- #include "ipa_i.h"
- #include "ipahal/ipahal.h"
- #include "ipahal/ipahal_nat.h"
- /*
- * The following for adding code (ie. for EMULATION) not found on x86.
- */
- #if defined(CONFIG_IPA_EMULATION)
- # include "ipa_emulation_stubs.h"
- #endif
- #define IPA_NAT_PHYS_MEM_OFFSET IPA_MEM_PART(nat_tbl_ofst)
- #define IPA_NAT_PHYS_MEM_SIZE IPA_RAM_NAT_SIZE
- #define IPA_IPV6CT_PHYS_MEM_OFFSET 0
- #define IPA_IPV6CT_PHYS_MEM_SIZE IPA_RAM_IPV6CT_SIZE
- #define IPA_NAT_IPV6CT_TEMP_MEM_SIZE 128
- #define IPA_NAT_MAX_NUM_OF_INIT_CMD_DESC 4
- #define IPA_IPV6CT_MAX_NUM_OF_INIT_CMD_DESC 3
- #define IPA_MAX_NUM_OF_TABLE_DMA_CMD_DESC 5
- /*
- * The base table max entries is limited by index into table 13 bits number.
- * Limit the memory size required by user to prevent kernel memory starvation
- */
- #define IPA_TABLE_MAX_ENTRIES 8192
- #define MAX_ALLOC_NAT_SIZE(size) (IPA_TABLE_MAX_ENTRIES * size)
- #define IPA_VALID_TBL_INDEX(ti) \
- ((ti) == 0)
- enum ipa_nat_ipv6ct_table_type {
- IPA_NAT_BASE_TBL = 0,
- IPA_NAT_EXPN_TBL = 1,
- IPA_NAT_INDX_TBL = 2,
- IPA_NAT_INDEX_EXPN_TBL = 3,
- IPA_IPV6CT_BASE_TBL = 4,
- IPA_IPV6CT_EXPN_TBL = 5
- };
- static bool sram_compatible;
- static vm_fault_t ipa3_nat_ipv6ct_vma_fault_remap(struct vm_fault *vmf)
- {
- vmf->page = NULL;
- IPADBG("\n");
- return VM_FAULT_SIGBUS;
- }
- /* VMA related file operations functions */
- static const struct vm_operations_struct ipa3_nat_ipv6ct_remap_vm_ops = {
- .fault = ipa3_nat_ipv6ct_vma_fault_remap,
- };
- static inline const char *ipa3_nat_mem_in_as_str(
- enum ipa3_nat_mem_in nmi)
- {
- switch (nmi) {
- case IPA_NAT_MEM_IN_DDR:
- return "IPA_NAT_MEM_IN_DDR";
- case IPA_NAT_MEM_IN_SRAM:
- return "IPA_NAT_MEM_IN_SRAM";
- default:
- break;
- }
- return "INVALID_MEM_TYPE";
- }
- static inline char *ipa_ioc_v4_nat_init_as_str(
- struct ipa_ioc_v4_nat_init *ptr,
- char *buf,
- uint32_t buf_sz)
- {
- if (ptr && buf && buf_sz) {
- snprintf(
- buf, buf_sz,
- "V4 NAT INIT: tbl_index(0x%02X) ipv4_rules_offset(0x%08X) expn_rules_offset(0x%08X) index_offset(0x%08X) index_expn_offset(0x%08X) table_entries(0x%04X) expn_table_entries(0x%04X) ip_addr(0x%08X)",
- ptr->tbl_index,
- ptr->ipv4_rules_offset,
- ptr->expn_rules_offset,
- ptr->index_offset,
- ptr->index_expn_offset,
- ptr->table_entries,
- ptr->expn_table_entries,
- ptr->ip_addr);
- }
- return buf;
- }
- static int ipa3_nat_ipv6ct_open(struct inode *inode, struct file *filp)
- {
- struct ipa3_nat_ipv6ct_common_mem *dev;
- IPADBG("\n");
- dev = container_of(inode->i_cdev,
- struct ipa3_nat_ipv6ct_common_mem, cdev);
- filp->private_data = dev;
- IPADBG("return\n");
- return 0;
- }
- static int ipa3_nat_ipv6ct_mmap(
- struct file *filp,
- struct vm_area_struct *vma)
- {
- struct ipa3_nat_ipv6ct_common_mem *dev =
- (struct ipa3_nat_ipv6ct_common_mem *)filp->private_data;
- unsigned long vsize = vma->vm_end - vma->vm_start;
- struct ipa_smmu_cb_ctx *cb = ipa3_get_smmu_ctx(IPA_SMMU_CB_AP);
- struct ipa3_nat_mem *nm_ptr = (struct ipa3_nat_mem *) dev;
- struct ipa3_nat_mem_loc_data *mld_ptr;
- enum ipa3_nat_mem_in nmi;
- int result = 0;
- nmi = nm_ptr->last_alloc_loc;
- IPADBG("In\n");
- if (!IPA_VALID_NAT_MEM_IN(nmi)) {
- IPAERR_RL("Bad ipa3_nat_mem_in type\n");
- result = -EPERM;
- goto bail;
- }
- mld_ptr = &nm_ptr->mem_loc[nmi];
- if (!dev->is_dev_init) {
- IPAERR("Attempt to mmap %s before dev init\n",
- dev->name);
- result = -EPERM;
- goto bail;
- }
- mutex_lock(&dev->lock);
- if (!mld_ptr->vaddr) {
- IPAERR_RL("Attempt to mmap %s before the memory allocation\n",
- dev->name);
- result = -EPERM;
- goto unlock;
- }
- if (mld_ptr->is_mapped) {
- IPAERR("%s already mapped, only 1 mapping supported\n",
- dev->name);
- result = -EINVAL;
- goto unlock;
- }
- if (nmi == IPA_NAT_MEM_IN_SRAM) {
- if (dev->phys_mem_size == 0 || dev->phys_mem_size > vsize) {
- IPAERR_RL("%s err vsize(0x%X) phys_mem_size(0x%X)\n",
- dev->name, vsize, dev->phys_mem_size);
- result = -EINVAL;
- goto unlock;
- }
- }
- /*
- * Check if no smmu or non dma coherent
- */
- if (!cb->valid || !dev_is_dma_coherent(cb->dev)) {
- IPADBG("Either smmu valid=%u and/or DMA coherent=%u false\n",
- cb->valid, !dev_is_dma_coherent(cb->dev));
- vma->vm_page_prot =
- pgprot_noncached(vma->vm_page_prot);
- }
- mld_ptr->base_address = NULL;
- IPADBG("Mapping %s\n", ipa3_nat_mem_in_as_str(nmi));
- if (nmi == IPA_NAT_MEM_IN_DDR) {
- IPADBG("map sz=0x%zx into vma size=0x%08x\n",
- mld_ptr->table_alloc_size,
- vsize);
- result =
- dma_mmap_coherent(
- ipa3_ctx->pdev,
- vma,
- mld_ptr->vaddr,
- mld_ptr->dma_handle,
- mld_ptr->table_alloc_size);
- if (result) {
- IPAERR("dma_mmap_coherent failed. Err:%d\n", result);
- goto unlock;
- }
- mld_ptr->base_address = mld_ptr->vaddr;
- } else {
- if (nmi == IPA_NAT_MEM_IN_SRAM) {
- IPADBG("map phys_mem_size(0x%08X) -> vma sz(0x%08X)\n",
- dev->phys_mem_size, vsize);
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- result = vm_iomap_memory(
- vma, mld_ptr->phys_addr, dev->phys_mem_size);
- if (result) {
- IPAERR("vm_iomap_memory failed. Err:%d\n",
- result);
- goto unlock;
- }
- mld_ptr->base_address = mld_ptr->vaddr;
- }
- }
- mld_ptr->is_mapped = true;
- vma->vm_ops = &ipa3_nat_ipv6ct_remap_vm_ops;
- unlock:
- mutex_unlock(&dev->lock);
- bail:
- IPADBG("Out\n");
- return result;
- }
- static const struct file_operations ipa3_nat_ipv6ct_fops = {
- .owner = THIS_MODULE,
- .open = ipa3_nat_ipv6ct_open,
- .mmap = ipa3_nat_ipv6ct_mmap
- };
- /**
- * ipa3_allocate_nat_ipv6ct_tmp_memory() - Allocates the NAT\IPv6CT temp memory
- */
- static struct ipa3_nat_ipv6ct_tmp_mem *ipa3_nat_ipv6ct_allocate_tmp_memory(void)
- {
- struct ipa3_nat_ipv6ct_tmp_mem *tmp_mem;
- gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO;
- IPADBG("\n");
- tmp_mem = kzalloc(sizeof(*tmp_mem), GFP_KERNEL);
- if (tmp_mem == NULL)
- return NULL;
- tmp_mem->vaddr =
- dma_alloc_coherent(ipa3_ctx->pdev, IPA_NAT_IPV6CT_TEMP_MEM_SIZE,
- &tmp_mem->dma_handle, gfp_flags);
- if (tmp_mem->vaddr == NULL)
- goto bail_tmp_mem;
- IPADBG("IPA successfully allocated temp memory\n");
- return tmp_mem;
- bail_tmp_mem:
- kfree(tmp_mem);
- return NULL;
- }
- static int ipa3_nat_ipv6ct_init_device(
- struct ipa3_nat_ipv6ct_common_mem *dev,
- const char *name,
- u32 phys_mem_size,
- u32 phys_mem_ofst,
- struct ipa3_nat_ipv6ct_tmp_mem *tmp_mem)
- {
- int result = 0;
- IPADBG("In: Init of %s\n", name);
- mutex_init(&dev->lock);
- dev->is_nat_mem = IS_NAT_MEM_DEV(dev);
- dev->is_ipv6ct_mem = IS_IPV6CT_MEM_DEV(dev);
- if (strnlen(name, IPA_DEV_NAME_MAX_LEN) == IPA_DEV_NAME_MAX_LEN) {
- IPAERR("device name is too long\n");
- result = -ENODEV;
- goto bail;
- }
- strlcpy(dev->name, name, IPA_DEV_NAME_MAX_LEN);
- dev->class = class_create(THIS_MODULE, name);
- if (IS_ERR(dev->class)) {
- IPAERR("unable to create the class for %s\n", name);
- result = -ENODEV;
- goto bail;
- }
- result = alloc_chrdev_region(&dev->dev_num, 0, 1, name);
- if (result) {
- IPAERR("alloc_chrdev_region err. for %s\n", name);
- result = -ENODEV;
- goto alloc_chrdev_region_fail;
- }
- dev->dev = device_create(dev->class, NULL, dev->dev_num, NULL, name);
- if (IS_ERR(dev->dev)) {
- IPAERR("device_create err:%ld\n", PTR_ERR(dev->dev));
- result = -ENODEV;
- goto device_create_fail;
- }
- cdev_init(&dev->cdev, &ipa3_nat_ipv6ct_fops);
- dev->cdev.owner = THIS_MODULE;
- mutex_lock(&dev->lock);
- result = cdev_add(&dev->cdev, dev->dev_num, 1);
- if (result) {
- IPAERR("cdev_add err=%d\n", -result);
- goto cdev_add_fail;
- }
- dev->tmp_mem = tmp_mem;
- dev->phys_mem_size = phys_mem_size;
- dev->phys_mem_ofst = phys_mem_ofst;
- dev->is_dev_init = true;
- mutex_unlock(&dev->lock);
- IPADBG("ipa dev %s added successfully. major:%d minor:%d\n", name,
- MAJOR(dev->dev_num), MINOR(dev->dev_num));
- result = 0;
- goto bail;
- cdev_add_fail:
- mutex_unlock(&dev->lock);
- device_destroy(dev->class, dev->dev_num);
- device_create_fail:
- unregister_chrdev_region(dev->dev_num, 1);
- alloc_chrdev_region_fail:
- class_destroy(dev->class);
- bail:
- IPADBG("Out\n");
- return result;
- }
- static void ipa3_nat_ipv6ct_destroy_device(
- struct ipa3_nat_ipv6ct_common_mem *dev)
- {
- IPADBG("In\n");
- mutex_lock(&dev->lock);
- if (dev->tmp_mem) {
- if (ipa3_ctx->nat_mem.is_tmp_mem_allocated) {
- dma_free_coherent(
- ipa3_ctx->pdev,
- IPA_NAT_IPV6CT_TEMP_MEM_SIZE,
- dev->tmp_mem->vaddr,
- dev->tmp_mem->dma_handle);
- kfree(dev->tmp_mem);
- dev->tmp_mem = NULL;
- ipa3_ctx->nat_mem.is_tmp_mem_allocated = false;
- }
- dev->tmp_mem = NULL;
- }
- device_destroy(dev->class, dev->dev_num);
- unregister_chrdev_region(dev->dev_num, 1);
- class_destroy(dev->class);
- dev->is_dev_init = false;
- mutex_unlock(&dev->lock);
- IPADBG("Out\n");
- }
- /**
- * ipa3_nat_ipv6ct_init_devices() - Initialize the NAT and IPv6CT devices
- *
- * Called during IPA init to create memory device
- *
- * Returns: 0 on success, negative on failure
- */
- int ipa3_nat_ipv6ct_init_devices(void)
- {
- struct ipa3_nat_ipv6ct_tmp_mem *tmp_mem;
- int result;
- IPADBG("\n");
- /*
- * Allocate NAT/IPv6CT temporary memory. The memory is never deleted,
- * because provided to HW once NAT or IPv6CT table is deleted.
- */
- tmp_mem = ipa3_nat_ipv6ct_allocate_tmp_memory();
- if (tmp_mem == NULL) {
- IPAERR("unable to allocate tmp_mem\n");
- return -ENOMEM;
- }
- ipa3_ctx->nat_mem.is_tmp_mem_allocated = true;
- if (ipa3_nat_ipv6ct_init_device(
- &ipa3_ctx->nat_mem.dev,
- IPA_NAT_DEV_NAME,
- IPA_NAT_PHYS_MEM_SIZE,
- IPA_NAT_PHYS_MEM_OFFSET,
- tmp_mem)) {
- IPAERR("unable to create nat device\n");
- result = -ENODEV;
- goto fail_init_nat_dev;
- }
- if ((ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) &&
- ipa3_nat_ipv6ct_init_device(
- &ipa3_ctx->ipv6ct_mem.dev,
- IPA_IPV6CT_DEV_NAME,
- IPA_IPV6CT_PHYS_MEM_SIZE,
- IPA_IPV6CT_PHYS_MEM_OFFSET,
- tmp_mem)) {
- IPAERR("unable to create IPv6CT device\n");
- result = -ENODEV;
- goto fail_init_ipv6ct_dev;
- }
- return 0;
- fail_init_ipv6ct_dev:
- ipa3_nat_ipv6ct_destroy_device(&ipa3_ctx->nat_mem.dev);
- fail_init_nat_dev:
- if (tmp_mem != NULL && ipa3_ctx->nat_mem.is_tmp_mem_allocated) {
- dma_free_coherent(ipa3_ctx->pdev, IPA_NAT_IPV6CT_TEMP_MEM_SIZE,
- tmp_mem->vaddr, tmp_mem->dma_handle);
- kfree(tmp_mem);
- ipa3_ctx->nat_mem.is_tmp_mem_allocated = false;
- }
- return result;
- }
- /**
- * ipa3_nat_ipv6ct_destroy_devices() - destroy the NAT and IPv6CT devices
- *
- * Called during IPA init to destroy nat device
- */
- void ipa3_nat_ipv6ct_destroy_devices(void)
- {
- ipa3_nat_ipv6ct_destroy_device(&ipa3_ctx->nat_mem.dev);
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
- ipa3_nat_ipv6ct_destroy_device(&ipa3_ctx->ipv6ct_mem.dev);
- }
- static int ipa3_nat_ipv6ct_allocate_mem(
- struct ipa3_nat_ipv6ct_common_mem *dev,
- struct ipa_ioc_nat_ipv6ct_table_alloc *table_alloc,
- enum ipahal_nat_type nat_type)
- {
- gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO;
- size_t nat_entry_size;
- struct ipa3_nat_mem *nm_ptr;
- struct ipa3_nat_mem_loc_data *mld_ptr;
- uintptr_t tmp_ptr;
- int result = 0;
- IPADBG("In: Requested alloc size %zu for %s\n",
- table_alloc->size, dev->name);
- if (!table_alloc->size) {
- IPAERR_RL("Invalid Parameters\n");
- result = -EPERM;
- goto bail;
- }
- if (!dev->is_dev_init) {
- IPAERR("%s hasn't been initialized\n", dev->name);
- result = -EPERM;
- goto bail;
- }
- if ((dev->is_nat_mem && nat_type != IPAHAL_NAT_IPV4) ||
- (dev->is_ipv6ct_mem && nat_type != IPAHAL_NAT_IPV6CT)) {
- IPAERR("%s dev type(%s) and nat_type(%s) mismatch\n",
- dev->name,
- (dev->is_nat_mem) ? "V4" : "V6",
- ipahal_nat_type_str(nat_type));
- result = -EPERM;
- goto bail;
- }
- ipahal_nat_entry_size(nat_type, &nat_entry_size);
- if (table_alloc->size > MAX_ALLOC_NAT_SIZE(nat_entry_size)) {
- IPAERR("Trying allocate more size = %zu, Max allowed = %zu\n",
- table_alloc->size,
- MAX_ALLOC_NAT_SIZE(nat_entry_size));
- result = -EPERM;
- goto bail;
- }
- if (nat_type == IPAHAL_NAT_IPV4) {
- nm_ptr = (struct ipa3_nat_mem *) dev;
- if (table_alloc->size <= IPA_NAT_PHYS_MEM_SIZE) {
- /*
- * CAN fit in SRAM, hence we'll use SRAM...
- */
- IPADBG("V4 NAT will reside in: %s\n",
- ipa3_nat_mem_in_as_str(IPA_NAT_MEM_IN_SRAM));
- if (nm_ptr->sram_in_use) {
- IPAERR("Memory already allocated\n");
- result = -EPERM;
- goto bail;
- }
- mld_ptr = &nm_ptr->mem_loc[IPA_NAT_MEM_IN_SRAM];
- mld_ptr->table_alloc_size = table_alloc->size;
- mld_ptr->phys_addr =
- ipa3_ctx->ipa_wrapper_base +
- ipa3_ctx->ctrl->ipa_reg_base_ofst +
- ipahal_get_reg_n_ofst(
- IPA_SW_AREA_RAM_DIRECT_ACCESS_n,
- 0) +
- IPA_NAT_PHYS_MEM_OFFSET;
- mld_ptr->io_vaddr = ioremap(
- mld_ptr->phys_addr, IPA_NAT_PHYS_MEM_SIZE);
- if (mld_ptr->io_vaddr == NULL) {
- IPAERR("ioremap failed\n");
- result = -ENOMEM;
- goto bail;
- }
- tmp_ptr = (uintptr_t) mld_ptr->io_vaddr;
- mld_ptr->vaddr = (void *) tmp_ptr;
- nm_ptr->sram_in_use = true;
- nm_ptr->last_alloc_loc = IPA_NAT_MEM_IN_SRAM;
- } else {
- /*
- * CAN NOT fit in SRAM, hence we'll allocate DDR...
- */
- IPADBG("V4 NAT will reside in: %s\n",
- ipa3_nat_mem_in_as_str(IPA_NAT_MEM_IN_DDR));
- if (nm_ptr->ddr_in_use) {
- IPAERR("Memory already allocated\n");
- result = -EPERM;
- goto bail;
- }
- mld_ptr = &nm_ptr->mem_loc[IPA_NAT_MEM_IN_DDR];
- mld_ptr->table_alloc_size = table_alloc->size;
- mld_ptr->vaddr =
- dma_alloc_coherent(
- ipa3_ctx->pdev,
- mld_ptr->table_alloc_size,
- &mld_ptr->dma_handle,
- gfp_flags);
- if (mld_ptr->vaddr == NULL) {
- IPAERR("memory alloc failed\n");
- result = -ENOMEM;
- goto bail;
- }
- nm_ptr->ddr_in_use = true;
- nm_ptr->last_alloc_loc = IPA_NAT_MEM_IN_DDR;
- }
- } else {
- if (nat_type == IPAHAL_NAT_IPV6CT) {
- dev->table_alloc_size = table_alloc->size;
- IPADBG("V6 NAT will reside in: %s\n",
- ipa3_nat_mem_in_as_str(IPA_NAT_MEM_IN_DDR));
- dev->vaddr =
- dma_alloc_coherent(
- ipa3_ctx->pdev,
- dev->table_alloc_size,
- &dev->dma_handle,
- gfp_flags);
- if (dev->vaddr == NULL) {
- IPAERR("memory alloc failed\n");
- result = -ENOMEM;
- goto bail;
- }
- }
- }
- bail:
- IPADBG("Out\n");
- return result;
- }
- /**
- * ipa3_allocate_nat_device() - Allocates memory for the NAT device
- * @mem: [in/out] memory parameters
- *
- * Called by NAT client driver to allocate memory for the NAT entries. Based on
- * the request size either shared or system memory will be used.
- *
- * Returns: 0 on success, negative on failure
- */
- int ipa3_allocate_nat_device(struct ipa_ioc_nat_alloc_mem *mem)
- {
- int result;
- struct ipa_ioc_nat_ipv6ct_table_alloc tmp;
- tmp.size = mem->size;
- tmp.offset = 0;
- result = ipa3_allocate_nat_table(&tmp);
- if (result)
- goto bail;
- mem->offset = tmp.offset;
- bail:
- return result;
- }
- /**
- * ipa3_allocate_nat_table() - Allocates memory for the NAT table
- * @table_alloc: [in/out] memory parameters
- *
- * Called by NAT client to allocate memory for the table entries.
- * Based on the request size either shared or system memory will be used.
- *
- * Returns: 0 on success, negative on failure
- */
- int ipa3_allocate_nat_table(
- struct ipa_ioc_nat_ipv6ct_table_alloc *table_alloc)
- {
- struct ipa3_nat_mem *nm_ptr = &(ipa3_ctx->nat_mem);
- struct ipa3_nat_mem_loc_data *mld_ptr;
- int result;
- IPADBG("table size:%u offset:%u\n",
- table_alloc->size, table_alloc->offset);
- mutex_lock(&nm_ptr->dev.lock);
- result = ipa3_nat_ipv6ct_allocate_mem(
- &nm_ptr->dev,
- table_alloc,
- IPAHAL_NAT_IPV4);
- if (result)
- goto bail;
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0
- &&
- nm_ptr->pdn_mem.base == NULL) {
- gfp_t gfp_flags = GFP_KERNEL | __GFP_ZERO;
- size_t pdn_entry_size;
- struct ipa_mem_buffer *pdn_mem_ptr = &nm_ptr->pdn_mem;
- ipahal_nat_entry_size(IPAHAL_NAT_IPV4_PDN, &pdn_entry_size);
- pdn_mem_ptr->size = pdn_entry_size * IPA_MAX_PDN_NUM;
- if (IPA_MEM_PART(pdn_config_size) < pdn_mem_ptr->size) {
- IPAERR(
- "number of PDN entries exceeds SRAM available space\n");
- result = -ENOMEM;
- goto fail_alloc_pdn;
- }
- pdn_mem_ptr->base =
- dma_alloc_coherent(
- ipa3_ctx->pdev,
- pdn_mem_ptr->size,
- &pdn_mem_ptr->phys_base,
- gfp_flags);
- if (pdn_mem_ptr->base == NULL) {
- IPAERR("fail to allocate PDN memory\n");
- result = -ENOMEM;
- goto fail_alloc_pdn;
- }
- IPADBG("IPA NAT dev allocated PDN memory successfully\n");
- }
- IPADBG("IPA NAT dev init successfully\n");
- mutex_unlock(&nm_ptr->dev.lock);
- IPADBG("return\n");
- return 0;
- fail_alloc_pdn:
- mld_ptr = &nm_ptr->mem_loc[nm_ptr->last_alloc_loc];
- if (nm_ptr->last_alloc_loc == IPA_NAT_MEM_IN_DDR) {
- if (mld_ptr->vaddr) {
- dma_free_coherent(
- ipa3_ctx->pdev,
- mld_ptr->table_alloc_size,
- mld_ptr->vaddr,
- mld_ptr->dma_handle);
- mld_ptr->vaddr = NULL;
- }
- }
- if (nm_ptr->last_alloc_loc == IPA_NAT_MEM_IN_SRAM) {
- if (mld_ptr->io_vaddr) {
- iounmap(mld_ptr->io_vaddr);
- mld_ptr->io_vaddr = NULL;
- mld_ptr->vaddr = NULL;
- }
- }
- bail:
- mutex_unlock(&nm_ptr->dev.lock);
- return result;
- }
- /**
- * ipa3_allocate_ipv6ct_table() - Allocates memory for the IPv6CT table
- * @table_alloc: [in/out] memory parameters
- *
- * Called by IPv6CT client to allocate memory for the table entries.
- * Based on the request size either shared or system memory will be used.
- *
- * Returns: 0 on success, negative on failure
- */
- int ipa3_allocate_ipv6ct_table(
- struct ipa_ioc_nat_ipv6ct_table_alloc *table_alloc)
- {
- int result;
- IPADBG("\n");
- if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
- IPAERR_RL("IPv6 connection tracking isn't supported\n");
- return -EPERM;
- }
- mutex_lock(&ipa3_ctx->ipv6ct_mem.dev.lock);
- result = ipa3_nat_ipv6ct_allocate_mem(
- &ipa3_ctx->ipv6ct_mem.dev,
- table_alloc,
- IPAHAL_NAT_IPV6CT);
- if (result)
- goto bail;
- IPADBG("IPA IPv6CT dev init successfully\n");
- bail:
- mutex_unlock(&ipa3_ctx->ipv6ct_mem.dev.lock);
- return result;
- }
- static int ipa3_nat_ipv6ct_check_table_params(
- struct ipa3_nat_ipv6ct_common_mem *dev,
- enum ipa3_nat_mem_in nmi,
- uint32_t offset,
- uint16_t entries_num,
- enum ipahal_nat_type nat_type)
- {
- size_t entry_size, table_size, orig_alloc_size;
- struct ipa3_nat_mem *nm_ptr;
- struct ipa3_nat_mem_loc_data *mld_ptr;
- int ret = 0;
- IPADBG("In\n");
- IPADBG(
- "v4(%u) v6(%u) nmi(%s) ofst(%u) ents(%u) nt(%s)\n",
- dev->is_nat_mem,
- dev->is_ipv6ct_mem,
- ipa3_nat_mem_in_as_str(nmi),
- offset,
- entries_num,
- ipahal_nat_type_str(nat_type));
- if (dev->is_ipv6ct_mem) {
- orig_alloc_size = dev->table_alloc_size;
- if (offset > UINT_MAX - dev->dma_handle) {
- IPAERR_RL("Failed due to integer overflow\n");
- IPAERR_RL("%s dma_handle: 0x%pa offset: 0x%x\n",
- dev->name, &dev->dma_handle, offset);
- ret = -EPERM;
- goto bail;
- }
- } else { /* dev->is_nat_mem */
- nm_ptr = (struct ipa3_nat_mem *) dev;
- mld_ptr = &nm_ptr->mem_loc[nmi];
- orig_alloc_size = mld_ptr->table_alloc_size;
- if (nmi == IPA_NAT_MEM_IN_DDR) {
- if (offset > UINT_MAX - mld_ptr->dma_handle) {
- IPAERR_RL("Failed due to integer overflow\n");
- IPAERR_RL("%s dma_handle: 0x%pa offset: 0x%x\n",
- dev->name, &mld_ptr->dma_handle, offset);
- ret = -EPERM;
- goto bail;
- }
- }
- }
- ret = ipahal_nat_entry_size(nat_type, &entry_size);
- if (ret) {
- IPAERR("Failed to retrieve size of entry for %s\n",
- ipahal_nat_type_str(nat_type));
- goto bail;
- }
- table_size = entry_size * entries_num;
- /* check for integer overflow */
- if (offset > UINT_MAX - table_size) {
- IPAERR_RL("Detected overflow\n");
- ret = -EPERM;
- goto bail;
- }
- /* Check offset is not beyond allocated size */
- if (offset + table_size > orig_alloc_size) {
- IPAERR_RL("Table offset not valid\n");
- IPAERR_RL("offset:%d entries:%d table_size:%zu mem_size:%zu\n",
- offset, entries_num, table_size, orig_alloc_size);
- ret = -EPERM;
- goto bail;
- }
- bail:
- IPADBG("Out\n");
- return ret;
- }
- static inline void ipa3_nat_ipv6ct_create_init_cmd(
- struct ipahal_imm_cmd_nat_ipv6ct_init_common *table_init_cmd,
- bool is_shared,
- dma_addr_t base_addr,
- uint8_t tbl_index,
- uint32_t base_table_offset,
- uint32_t expn_table_offset,
- uint16_t table_entries,
- uint16_t expn_table_entries,
- const char *table_name)
- {
- table_init_cmd->base_table_addr_shared = is_shared;
- table_init_cmd->expansion_table_addr_shared = is_shared;
- table_init_cmd->base_table_addr = base_addr + base_table_offset;
- IPADBG("%s base table offset:0x%x\n", table_name, base_table_offset);
- table_init_cmd->expansion_table_addr = base_addr + expn_table_offset;
- IPADBG("%s expn table offset:0x%x\n", table_name, expn_table_offset);
- table_init_cmd->table_index = tbl_index;
- IPADBG("%s table index:0x%x\n", table_name, tbl_index);
- table_init_cmd->size_base_table = table_entries;
- IPADBG("%s base table size:0x%x\n", table_name, table_entries);
- table_init_cmd->size_expansion_table = expn_table_entries;
- IPADBG("%s expansion table size:0x%x\n",
- table_name, expn_table_entries);
- }
- static inline bool chk_sram_offset_alignment(
- uintptr_t addr,
- u32 mask)
- {
- if (addr & (uintptr_t) mask) {
- IPAERR("sram addr(%pK) is not properly aligned\n", addr);
- return false;
- }
- return true;
- }
- static inline int ipa3_nat_ipv6ct_init_device_structure(
- struct ipa3_nat_ipv6ct_common_mem *dev,
- enum ipa3_nat_mem_in nmi,
- uint32_t base_table_offset,
- uint32_t expn_table_offset,
- uint16_t table_entries,
- uint16_t expn_table_entries,
- uint32_t index_offset,
- uint32_t index_expn_offset,
- uint8_t focus_change)
- {
- int ret = 0;
- IPADBG("In\n");
- IPADBG(
- "v4(%u) v6(%u) nmi(%s) bto(%u) eto(%u) t_ents(%u) et_ents(%u) io(%u) ieo(%u)\n",
- dev->is_nat_mem,
- dev->is_ipv6ct_mem,
- ipa3_nat_mem_in_as_str(nmi),
- base_table_offset,
- expn_table_offset,
- table_entries,
- expn_table_entries,
- index_offset,
- index_expn_offset);
- if (dev->is_ipv6ct_mem) {
- IPADBG("v6\n");
- dev->base_table_addr =
- (char *) dev->base_address + base_table_offset;
- IPADBG("%s base_table_addr: 0x%pK\n",
- dev->name, dev->base_table_addr);
- dev->expansion_table_addr =
- (char *) dev->base_address + expn_table_offset;
- IPADBG("%s expansion_table_addr: 0x%pK\n",
- dev->name, dev->expansion_table_addr);
- IPADBG("%s table_entries: %d\n",
- dev->name, table_entries);
- dev->table_entries = table_entries;
- IPADBG("%s expn_table_entries: %d\n",
- dev->name, expn_table_entries);
- dev->expn_table_entries = expn_table_entries;
- } else if (dev->is_nat_mem) {
- struct ipa3_nat_mem *nm_ptr = (struct ipa3_nat_mem *) dev;
- struct ipa3_nat_mem_loc_data *mld_p =
- &nm_ptr->mem_loc[nmi];
- IPADBG("v4\n");
- nm_ptr->active_table = nmi;
- mld_p->base_table_addr =
- (char *) mld_p->base_address + base_table_offset;
- IPADBG("%s base_table_addr: 0x%pK\n",
- dev->name, mld_p->base_table_addr);
- mld_p->expansion_table_addr =
- (char *) mld_p->base_address + expn_table_offset;
- IPADBG("%s expansion_table_addr: 0x%pK\n",
- dev->name, mld_p->expansion_table_addr);
- IPADBG("%s table_entries: %d\n",
- dev->name, table_entries);
- mld_p->table_entries = table_entries;
- IPADBG("%s expn_table_entries: %d\n",
- dev->name, expn_table_entries);
- mld_p->expn_table_entries = expn_table_entries;
- mld_p->index_table_addr =
- (char *) mld_p->base_address + index_offset;
- IPADBG("index_table_addr: 0x%pK\n",
- mld_p->index_table_addr);
- mld_p->index_table_expansion_addr =
- (char *) mld_p->base_address + index_expn_offset;
- IPADBG("index_table_expansion_addr: 0x%pK\n",
- mld_p->index_table_expansion_addr);
- if (nmi == IPA_NAT_MEM_IN_DDR) {
- if (focus_change)
- nm_ptr->switch2ddr_cnt++;
- } else {
- /*
- * The IPA wants certain SRAM addresses
- * to have particular low order bits to
- * be zero. We test here to ensure...
- */
- if (!chk_sram_offset_alignment(
- (uintptr_t) mld_p->base_table_addr,
- 31) ||
- !chk_sram_offset_alignment(
- (uintptr_t) mld_p->expansion_table_addr,
- 31) ||
- !chk_sram_offset_alignment(
- (uintptr_t) mld_p->index_table_addr,
- 3) ||
- !chk_sram_offset_alignment(
- (uintptr_t) mld_p->index_table_expansion_addr,
- 3)) {
- ret = -ENODEV;
- goto done;
- }
- if (focus_change)
- nm_ptr->switch2sram_cnt++;
- }
- }
- done:
- IPADBG("Out\n");
- return ret;
- }
- static void ipa3_nat_create_init_cmd(
- struct ipa_ioc_v4_nat_init *init,
- bool is_shared,
- dma_addr_t base_addr,
- struct ipahal_imm_cmd_ip_v4_nat_init *cmd)
- {
- IPADBG("\n");
- ipa3_nat_ipv6ct_create_init_cmd(
- &cmd->table_init,
- is_shared,
- base_addr,
- init->tbl_index,
- init->ipv4_rules_offset,
- init->expn_rules_offset,
- init->table_entries,
- init->expn_table_entries,
- ipa3_ctx->nat_mem.dev.name);
- cmd->index_table_addr_shared = is_shared;
- cmd->index_table_expansion_addr_shared = is_shared;
- cmd->index_table_addr =
- base_addr + init->index_offset;
- IPADBG("index_offset:0x%x\n", init->index_offset);
- cmd->index_table_expansion_addr =
- base_addr + init->index_expn_offset;
- IPADBG("index_expn_offset:0x%x\n", init->index_expn_offset);
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
- /*
- * starting IPAv4.0 public ip field changed to store the
- * PDN config table offset in SMEM
- */
- cmd->public_addr_info = IPA_MEM_PART(pdn_config_ofst);
- IPADBG("pdn config base:0x%x\n", cmd->public_addr_info);
- } else {
- cmd->public_addr_info = init->ip_addr;
- IPADBG("Public IP address:%pI4h\n", &cmd->public_addr_info);
- }
- IPADBG("return\n");
- }
- static void ipa3_nat_create_modify_pdn_cmd(
- struct ipahal_imm_cmd_dma_shared_mem *mem_cmd, bool zero_mem)
- {
- size_t pdn_entry_size, mem_size;
- IPADBG("\n");
- ipahal_nat_entry_size(IPAHAL_NAT_IPV4_PDN, &pdn_entry_size);
- mem_size = pdn_entry_size * IPA_MAX_PDN_NUM;
- if (zero_mem && ipa3_ctx->nat_mem.pdn_mem.base)
- memset(ipa3_ctx->nat_mem.pdn_mem.base, 0, mem_size);
- /* Copy the PDN config table to SRAM */
- mem_cmd->is_read = false;
- mem_cmd->skip_pipeline_clear = false;
- mem_cmd->pipeline_clear_options = IPAHAL_HPS_CLEAR;
- mem_cmd->size = mem_size;
- mem_cmd->system_addr = ipa3_ctx->nat_mem.pdn_mem.phys_base;
- mem_cmd->local_addr = ipa3_ctx->smem_restricted_bytes +
- IPA_MEM_PART(pdn_config_ofst);
- IPADBG("return\n");
- }
- static int ipa3_nat_send_init_cmd(struct ipahal_imm_cmd_ip_v4_nat_init *cmd,
- bool zero_pdn_table)
- {
- struct ipa3_desc desc[IPA_NAT_MAX_NUM_OF_INIT_CMD_DESC];
- struct ipahal_imm_cmd_pyld *cmd_pyld[IPA_NAT_MAX_NUM_OF_INIT_CMD_DESC];
- int i, num_cmd = 0, result;
- struct ipahal_reg_valmask valmask;
- struct ipahal_imm_cmd_register_write reg_write_coal_close;
- IPADBG("\n");
- memset(desc, 0, sizeof(desc));
- memset(cmd_pyld, 0, sizeof(cmd_pyld));
- /* IC to close the coal frame before HPS Clear if coal is enabled */
- if (ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS) != -1) {
- i = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS);
- reg_write_coal_close.skip_pipeline_clear = false;
- reg_write_coal_close.pipeline_clear_options = IPAHAL_HPS_CLEAR;
- reg_write_coal_close.offset = ipahal_get_reg_ofst(
- IPA_AGGR_FORCE_CLOSE);
- ipahal_get_aggr_force_close_valmask(i, &valmask);
- reg_write_coal_close.value = valmask.val;
- reg_write_coal_close.value_mask = valmask.mask;
- cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_REGISTER_WRITE,
- ®_write_coal_close, false);
- if (!cmd_pyld[num_cmd]) {
- IPAERR("failed to construct coal close IC\n");
- result = -ENOMEM;
- goto destroy_imm_cmd;
- }
- ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
- ++num_cmd;
- }
- /* NO-OP IC for ensuring that IPA pipeline is empty */
- cmd_pyld[num_cmd] =
- ipahal_construct_nop_imm_cmd(false, IPAHAL_HPS_CLEAR, false);
- if (!cmd_pyld[num_cmd]) {
- IPAERR("failed to construct NOP imm cmd\n");
- result = -ENOMEM;
- goto destroy_imm_cmd;
- }
- ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
- ++num_cmd;
- cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_IP_V4_NAT_INIT, cmd, false);
- if (!cmd_pyld[num_cmd]) {
- IPAERR_RL("fail to construct NAT init imm cmd\n");
- result = -EPERM;
- goto destroy_imm_cmd;
- }
- ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
- ++num_cmd;
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
- struct ipahal_imm_cmd_dma_shared_mem mem_cmd = { 0 };
- if (num_cmd >= IPA_NAT_MAX_NUM_OF_INIT_CMD_DESC) {
- IPAERR("number of commands is out of range\n");
- result = -ENOBUFS;
- goto destroy_imm_cmd;
- }
- /* Copy the PDN config table to SRAM */
- ipa3_nat_create_modify_pdn_cmd(&mem_cmd, zero_pdn_table);
- cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_SHARED_MEM, &mem_cmd, false);
- if (!cmd_pyld[num_cmd]) {
- IPAERR(
- "fail construct dma_shared_mem cmd: for pdn table");
- result = -ENOMEM;
- goto destroy_imm_cmd;
- }
- ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
- ++num_cmd;
- IPADBG("added PDN table copy cmd\n");
- }
- result = ipa3_send_cmd(num_cmd, desc);
- if (result) {
- IPAERR("fail to send NAT init immediate command\n");
- goto destroy_imm_cmd;
- }
- IPADBG("return\n");
- destroy_imm_cmd:
- for (i = 0; i < num_cmd; ++i)
- ipahal_destroy_imm_cmd(cmd_pyld[i]);
- return result;
- }
- static int ipa3_ipv6ct_send_init_cmd(struct ipahal_imm_cmd_ip_v6_ct_init *cmd)
- {
- struct ipa3_desc desc[IPA_IPV6CT_MAX_NUM_OF_INIT_CMD_DESC];
- struct ipahal_imm_cmd_pyld
- *cmd_pyld[IPA_IPV6CT_MAX_NUM_OF_INIT_CMD_DESC];
- int i, num_cmd = 0, result;
- struct ipahal_reg_valmask valmask;
- struct ipahal_imm_cmd_register_write reg_write_coal_close;
- IPADBG("\n");
- memset(desc, 0, sizeof(desc));
- memset(cmd_pyld, 0, sizeof(cmd_pyld));
- /* IC to close the coal frame before HPS Clear if coal is enabled */
- if (ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS) != -1) {
- i = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS);
- reg_write_coal_close.skip_pipeline_clear = false;
- reg_write_coal_close.pipeline_clear_options = IPAHAL_HPS_CLEAR;
- reg_write_coal_close.offset = ipahal_get_reg_ofst(
- IPA_AGGR_FORCE_CLOSE);
- ipahal_get_aggr_force_close_valmask(i, &valmask);
- reg_write_coal_close.value = valmask.val;
- reg_write_coal_close.value_mask = valmask.mask;
- cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_REGISTER_WRITE,
- ®_write_coal_close, false);
- if (!cmd_pyld[num_cmd]) {
- IPAERR("failed to construct coal close IC\n");
- result = -ENOMEM;
- goto destroy_imm_cmd;
- }
- ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
- ++num_cmd;
- }
- /* NO-OP IC for ensuring that IPA pipeline is empty */
- cmd_pyld[num_cmd] =
- ipahal_construct_nop_imm_cmd(false, IPAHAL_HPS_CLEAR, false);
- if (!cmd_pyld[num_cmd]) {
- IPAERR("failed to construct NOP imm cmd\n");
- result = -ENOMEM;
- goto destroy_imm_cmd;
- }
- ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
- ++num_cmd;
- if (num_cmd >= IPA_IPV6CT_MAX_NUM_OF_INIT_CMD_DESC) {
- IPAERR("number of commands is out of range\n");
- result = -ENOBUFS;
- goto destroy_imm_cmd;
- }
- cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_IP_V6_CT_INIT, cmd, false);
- if (!cmd_pyld[num_cmd]) {
- IPAERR_RL("fail to construct IPv6CT init imm cmd\n");
- result = -EPERM;
- goto destroy_imm_cmd;
- }
- ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
- ++num_cmd;
- result = ipa3_send_cmd(num_cmd, desc);
- if (result) {
- IPAERR("Fail to send IPv6CT init immediate command\n");
- goto destroy_imm_cmd;
- }
- IPADBG("return\n");
- destroy_imm_cmd:
- for (i = 0; i < num_cmd; ++i)
- ipahal_destroy_imm_cmd(cmd_pyld[i]);
- return result;
- }
- /* IOCTL function handlers */
- /**
- * ipa3_nat_init_cmd() - Post IP_V4_NAT_INIT command to IPA HW
- * @init: [in] initialization command attributes
- *
- * Called by NAT client driver to post IP_V4_NAT_INIT command to IPA HW
- *
- * Returns: 0 on success, negative on failure
- */
- int ipa3_nat_init_cmd(
- struct ipa_ioc_v4_nat_init *init)
- {
- struct ipa3_nat_ipv6ct_common_mem *dev = &ipa3_ctx->nat_mem.dev;
- struct ipa3_nat_mem *nm_ptr = (struct ipa3_nat_mem *) dev;
- enum ipa3_nat_mem_in nmi;
- struct ipa3_nat_mem_loc_data *mld_ptr;
- struct ipahal_imm_cmd_ip_v4_nat_init cmd;
- int result;
- IPADBG("In\n");
- if (!sram_compatible) {
- init->mem_type = 0;
- init->focus_change = 0;
- }
- nmi = init->mem_type;
- IPADBG("tbl_index(%d) table_entries(%u)\n",
- init->tbl_index,
- init->table_entries);
- memset(&cmd, 0, sizeof(cmd));
- if (!IPA_VALID_TBL_INDEX(init->tbl_index)) {
- IPAERR_RL("Unsupported table index %d\n",
- init->tbl_index);
- result = -EPERM;
- goto bail;
- }
- if (init->table_entries == 0) {
- IPAERR_RL("Table entries is zero\n");
- result = -EPERM;
- goto bail;
- }
- if (!IPA_VALID_NAT_MEM_IN(nmi)) {
- IPAERR_RL("Bad ipa3_nat_mem_in type\n");
- result = -EPERM;
- goto bail;
- }
- IPADBG("nmi(%s)\n", ipa3_nat_mem_in_as_str(nmi));
- mld_ptr = &nm_ptr->mem_loc[nmi];
- if (!mld_ptr->is_mapped) {
- IPAERR_RL("Attempt to init %s before mmap\n", dev->name);
- result = -EPERM;
- goto bail;
- }
- result = ipa3_nat_ipv6ct_check_table_params(
- dev, nmi,
- init->ipv4_rules_offset,
- init->table_entries + 1,
- IPAHAL_NAT_IPV4);
- if (result) {
- IPAERR_RL("Bad params for NAT base table\n");
- goto bail;
- }
- result = ipa3_nat_ipv6ct_check_table_params(
- dev, nmi,
- init->expn_rules_offset,
- init->expn_table_entries,
- IPAHAL_NAT_IPV4);
- if (result) {
- IPAERR_RL("Bad params for NAT expansion table\n");
- goto bail;
- }
- result = ipa3_nat_ipv6ct_check_table_params(
- dev, nmi,
- init->index_offset,
- init->table_entries + 1,
- IPAHAL_NAT_IPV4_INDEX);
- if (result) {
- IPAERR_RL("Bad params for index table\n");
- goto bail;
- }
- result = ipa3_nat_ipv6ct_check_table_params(
- dev, nmi,
- init->index_expn_offset,
- init->expn_table_entries,
- IPAHAL_NAT_IPV4_INDEX);
- if (result) {
- IPAERR_RL("Bad params for index expansion table\n");
- goto bail;
- }
- IPADBG("Table memory becoming active: %s\n",
- ipa3_nat_mem_in_as_str(nmi));
- if (nmi == IPA_NAT_MEM_IN_DDR) {
- ipa3_nat_create_init_cmd(
- init,
- false,
- mld_ptr->dma_handle,
- &cmd);
- } else {
- ipa3_nat_create_init_cmd(
- init,
- true,
- IPA_RAM_NAT_OFST,
- &cmd);
- }
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0
- &&
- nm_ptr->pdn_mem.base
- &&
- !init->focus_change) {
- struct ipahal_nat_pdn_entry pdn_entry;
- /* store ip in pdn entry cache array */
- pdn_entry.public_ip = init->ip_addr;
- pdn_entry.src_metadata = 0;
- pdn_entry.dst_metadata = 0;
- result = ipahal_nat_construct_entry(
- IPAHAL_NAT_IPV4_PDN,
- &pdn_entry,
- nm_ptr->pdn_mem.base);
- if (result) {
- IPAERR("Fail to construct NAT pdn entry\n");
- goto bail;
- }
- }
- IPADBG("Posting NAT init command\n");
- result = ipa3_nat_send_init_cmd(&cmd, false);
- if (result) {
- IPAERR("Fail to send NAT init immediate command\n");
- goto bail;
- }
- result = ipa3_nat_ipv6ct_init_device_structure(
- dev, nmi,
- init->ipv4_rules_offset,
- init->expn_rules_offset,
- init->table_entries,
- init->expn_table_entries,
- init->index_offset,
- init->index_expn_offset,
- init->focus_change);
- if (result) {
- IPAERR("Table offset initialization failure\n");
- goto bail;
- }
- nm_ptr->public_ip_addr = init->ip_addr;
- IPADBG("Public IP address:%pI4h\n", &nm_ptr->public_ip_addr);
- dev->is_hw_init = true;
- bail:
- IPADBG("Out\n");
- return result;
- }
- /**
- * ipa3_ipv6ct_init_cmd() - Post IP_V6_CONN_TRACK_INIT command to IPA HW
- * @init: [in] initialization command attributes
- *
- * Called by NAT client driver to post IP_V6_CONN_TRACK_INIT command to IPA HW
- *
- * Returns: 0 on success, negative on failure
- */
- int ipa3_ipv6ct_init_cmd(
- struct ipa_ioc_ipv6ct_init *init)
- {
- struct ipa3_nat_ipv6ct_common_mem *dev = &ipa3_ctx->ipv6ct_mem.dev;
- struct ipahal_imm_cmd_ip_v6_ct_init cmd;
- int result;
- IPADBG("In\n");
- memset(&cmd, 0, sizeof(cmd));
- if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
- IPAERR_RL("IPv6 connection tracking isn't supported\n");
- return -EPERM;
- }
- if (!IPA_VALID_TBL_INDEX(init->tbl_index)) {
- IPAERR_RL("Unsupported table index %d\n", init->tbl_index);
- return -EPERM;
- }
- if (init->table_entries == 0) {
- IPAERR_RL("Table entries is zero\n");
- return -EPERM;
- }
- if (!dev->is_mapped) {
- IPAERR_RL("attempt to init %s before mmap\n",
- dev->name);
- return -EPERM;
- }
- result = ipa3_nat_ipv6ct_check_table_params(
- dev, IPA_NAT_MEM_IN_DDR,
- init->base_table_offset,
- init->table_entries + 1,
- IPAHAL_NAT_IPV6CT);
- if (result) {
- IPAERR_RL("Bad params for IPv6CT base table\n");
- return result;
- }
- result = ipa3_nat_ipv6ct_check_table_params(
- dev, IPA_NAT_MEM_IN_DDR,
- init->expn_table_offset,
- init->expn_table_entries,
- IPAHAL_NAT_IPV6CT);
- if (result) {
- IPAERR_RL("Bad params for IPv6CT expansion table\n");
- return result;
- }
- IPADBG("Will install v6 NAT in: %s\n",
- ipa3_nat_mem_in_as_str(IPA_NAT_MEM_IN_DDR));
- ipa3_nat_ipv6ct_create_init_cmd(
- &cmd.table_init,
- false,
- dev->dma_handle,
- init->tbl_index,
- init->base_table_offset,
- init->expn_table_offset,
- init->table_entries,
- init->expn_table_entries,
- dev->name);
- IPADBG("posting ip_v6_ct_init imm command\n");
- result = ipa3_ipv6ct_send_init_cmd(&cmd);
- if (result) {
- IPAERR("fail to send IPv6CT init immediate command\n");
- return result;
- }
- ipa3_nat_ipv6ct_init_device_structure(
- dev,
- IPA_NAT_MEM_IN_DDR,
- init->base_table_offset,
- init->expn_table_offset,
- init->table_entries,
- init->expn_table_entries,
- 0, 0, 0);
- dev->is_hw_init = true;
- IPADBG("Out\n");
- return 0;
- }
- /**
- * ipa3_nat_mdfy_pdn() - Modify a PDN entry in PDN config table in IPA SRAM
- * @mdfy_pdn: [in] PDN info to be written to SRAM
- *
- * Called by NAT client driver to modify an entry in the PDN config table
- *
- * Returns: 0 on success, negative on failure
- */
- int ipa3_nat_mdfy_pdn(
- struct ipa_ioc_nat_pdn_entry *mdfy_pdn)
- {
- struct ipa3_nat_ipv6ct_common_mem *dev = &ipa3_ctx->nat_mem.dev;
- struct ipa3_nat_mem *nm_ptr = (struct ipa3_nat_mem *) dev;
- struct ipa_mem_buffer *pdn_mem_ptr = &nm_ptr->pdn_mem;
- struct ipahal_imm_cmd_dma_shared_mem mem_cmd = { 0 };
- struct ipahal_nat_pdn_entry pdn_fields = { 0 };
- struct ipa3_desc desc = { 0 };
- struct ipahal_imm_cmd_pyld *cmd_pyld;
- size_t entry_size;
- int result = 0;
- IPADBG("In\n");
- mutex_lock(&dev->lock);
- if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
- IPAERR_RL("IPA HW does not support multi PDN\n");
- result = -EPERM;
- goto bail;
- }
- if (pdn_mem_ptr->base == NULL) {
- IPAERR_RL(
- "Attempt to modify a PDN entry before the PDN table memory allocation\n");
- result = -EPERM;
- goto bail;
- }
- if (mdfy_pdn->pdn_index > (IPA_MAX_PDN_NUM - 1)) {
- IPAERR_RL("pdn index out of range %d\n", mdfy_pdn->pdn_index);
- result = -EPERM;
- goto bail;
- }
- /*
- * Store ip in pdn entry cache array
- */
- pdn_fields.public_ip = mdfy_pdn->public_ip;
- pdn_fields.dst_metadata = mdfy_pdn->dst_metadata;
- pdn_fields.src_metadata = mdfy_pdn->src_metadata;
- /*
- * Mark tethering bit for remote modem
- */
- if (ipa3_ctx->ipa_hw_type == IPA_HW_v4_1) {
- pdn_fields.src_metadata |= IPA_QMAP_TETH_BIT;
- }
- /*
- * Get size of the entry
- */
- result = ipahal_nat_entry_size(
- IPAHAL_NAT_IPV4_PDN,
- &entry_size);
- if (result) {
- IPAERR("Failed to retrieve pdn entry size\n");
- goto bail;
- }
- result = ipahal_nat_construct_entry(
- IPAHAL_NAT_IPV4_PDN,
- &pdn_fields,
- (pdn_mem_ptr->base + (mdfy_pdn->pdn_index)*(entry_size)));
- if (result) {
- IPAERR("Fail to construct NAT pdn entry\n");
- goto bail;
- }
- IPADBG("Modify PDN in index: %d Public ip address:%pI4h\n",
- mdfy_pdn->pdn_index,
- &pdn_fields.public_ip);
- IPADBG("Modify PDN dst metadata: 0x%x src metadata: 0x%x\n",
- pdn_fields.dst_metadata,
- pdn_fields.src_metadata);
- /*
- * Copy the PDN config table to SRAM
- */
- ipa3_nat_create_modify_pdn_cmd(&mem_cmd, false);
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_SHARED_MEM, &mem_cmd, false);
- if (!cmd_pyld) {
- IPAERR(
- "fail construct dma_shared_mem cmd: for pdn table\n");
- result = -ENOMEM;
- goto bail;
- }
- ipa3_init_imm_cmd_desc(&desc, cmd_pyld);
- IPADBG("sending PDN table copy cmd\n");
- result = ipa3_send_cmd(1, &desc);
- if (result)
- IPAERR("Fail to send PDN table copy immediate command\n");
- ipahal_destroy_imm_cmd(cmd_pyld);
- bail:
- mutex_unlock(&dev->lock);
- IPADBG("Out\n");
- return result;
- }
- static uint32_t ipa3_nat_ipv6ct_calculate_table_size(
- enum ipa3_nat_mem_in nmi,
- uint8_t base_addr)
- {
- size_t entry_size;
- u32 num_entries;
- enum ipahal_nat_type nat_type;
- struct ipa3_nat_mem_loc_data *mld_ptr = &ipa3_ctx->nat_mem.mem_loc[nmi];
- switch (base_addr) {
- case IPA_NAT_BASE_TBL:
- num_entries = mld_ptr->table_entries + 1;
- nat_type = IPAHAL_NAT_IPV4;
- break;
- case IPA_NAT_EXPN_TBL:
- num_entries = mld_ptr->expn_table_entries;
- nat_type = IPAHAL_NAT_IPV4;
- break;
- case IPA_NAT_INDX_TBL:
- num_entries = mld_ptr->table_entries + 1;
- nat_type = IPAHAL_NAT_IPV4_INDEX;
- break;
- case IPA_NAT_INDEX_EXPN_TBL:
- num_entries = mld_ptr->expn_table_entries;
- nat_type = IPAHAL_NAT_IPV4_INDEX;
- break;
- case IPA_IPV6CT_BASE_TBL:
- num_entries = ipa3_ctx->ipv6ct_mem.dev.table_entries + 1;
- nat_type = IPAHAL_NAT_IPV6CT;
- break;
- case IPA_IPV6CT_EXPN_TBL:
- num_entries = ipa3_ctx->ipv6ct_mem.dev.expn_table_entries;
- nat_type = IPAHAL_NAT_IPV6CT;
- break;
- default:
- IPAERR_RL("Invalid base_addr %d for table DMA command\n",
- base_addr);
- return 0;
- }
- ipahal_nat_entry_size(nat_type, &entry_size);
- return entry_size * num_entries;
- }
- static int ipa3_table_validate_table_dma_one(
- enum ipa3_nat_mem_in nmi,
- struct ipa_ioc_nat_dma_one *param)
- {
- uint32_t table_size;
- if (param->table_index >= 1) {
- IPAERR_RL("Unsupported table index %u\n", param->table_index);
- return -EPERM;
- }
- switch (param->base_addr) {
- case IPA_NAT_BASE_TBL:
- case IPA_NAT_EXPN_TBL:
- case IPA_NAT_INDX_TBL:
- case IPA_NAT_INDEX_EXPN_TBL:
- if (!ipa3_ctx->nat_mem.dev.is_hw_init) {
- IPAERR_RL("attempt to write to %s before HW int\n",
- ipa3_ctx->nat_mem.dev.name);
- return -EPERM;
- }
- IPADBG("nmi(%s)\n", ipa3_nat_mem_in_as_str(nmi));
- break;
- case IPA_IPV6CT_BASE_TBL:
- case IPA_IPV6CT_EXPN_TBL:
- if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
- IPAERR_RL("IPv6 connection tracking isn't supported\n");
- return -EPERM;
- }
- if (!ipa3_ctx->ipv6ct_mem.dev.is_hw_init) {
- IPAERR_RL("attempt to write to %s before HW int\n",
- ipa3_ctx->ipv6ct_mem.dev.name);
- return -EPERM;
- }
- break;
- default:
- IPAERR_RL("Invalid base_addr %d for table DMA command\n",
- param->base_addr);
- return -EPERM;
- }
- table_size = ipa3_nat_ipv6ct_calculate_table_size(
- nmi,
- param->base_addr);
- if (!table_size) {
- IPAERR_RL("Failed to calculate table size for base_addr %d\n",
- param->base_addr);
- return -EPERM;
- }
- if (param->offset >= table_size) {
- IPAERR_RL("Invalid offset %d for table DMA command\n",
- param->offset);
- IPAERR_RL("table_index %d base addr %d size %d\n",
- param->table_index, param->base_addr, table_size);
- return -EPERM;
- }
- return 0;
- }
- /**
- * ipa3_table_dma_cmd() - Post TABLE_DMA command to IPA HW
- * @dma: [in] initialization command attributes
- *
- * Called by NAT/IPv6CT clients to post TABLE_DMA command to IPA HW
- *
- * Returns: 0 on success, negative on failure
- */
- int ipa3_table_dma_cmd(
- struct ipa_ioc_nat_dma_cmd *dma)
- {
- struct ipa3_nat_ipv6ct_common_mem *dev = &ipa3_ctx->nat_mem.dev;
- enum ipahal_imm_cmd_name cmd_name = IPA_IMM_CMD_NAT_DMA;
- struct ipahal_imm_cmd_table_dma cmd;
- struct ipahal_imm_cmd_pyld *cmd_pyld[IPA_MAX_NUM_OF_TABLE_DMA_CMD_DESC];
- struct ipa3_desc desc[IPA_MAX_NUM_OF_TABLE_DMA_CMD_DESC];
- uint8_t cnt, num_cmd = 0;
- int result = 0;
- int i;
- struct ipahal_reg_valmask valmask;
- struct ipahal_imm_cmd_register_write reg_write_coal_close;
- int max_dma_table_cmds = IPA_MAX_NUM_OF_TABLE_DMA_CMD_DESC;
- IPADBG("In\n");
- if (!sram_compatible)
- dma->mem_type = 0;
- if (!dev->is_dev_init) {
- IPAERR_RL("NAT hasn't been initialized\n");
- result = -EPERM;
- goto bail;
- }
- if (!IPA_VALID_NAT_MEM_IN(dma->mem_type)) {
- IPAERR_RL("Invalid ipa3_nat_mem_in type (%u)\n",
- dma->mem_type);
- result = -EPERM;
- goto bail;
- }
- IPADBG("nmi(%s)\n", ipa3_nat_mem_in_as_str(dma->mem_type));
- memset(&cmd, 0, sizeof(cmd));
- memset(cmd_pyld, 0, sizeof(cmd_pyld));
- memset(desc, 0, sizeof(desc));
- /**
- * We use a descriptor for closing coalsceing endpoint
- * by immediate command. So, DMA entries should be less than
- * IPA_MAX_NUM_OF_TABLE_DMA_CMD_DESC - 1 to overcome
- * buffer overflow of ipa3_desc array.
- */
- if (ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS) != -1)
- max_dma_table_cmds -= 1;
- if (!dma->entries || dma->entries > (max_dma_table_cmds - 1)) {
- IPAERR_RL("Invalid number of entries %d\n",
- dma->entries);
- result = -EPERM;
- goto bail;
- }
- for (cnt = 0; cnt < dma->entries; ++cnt) {
- result = ipa3_table_validate_table_dma_one(
- dma->mem_type, &dma->dma[cnt]);
- if (result) {
- IPAERR_RL("Table DMA command parameter %d is invalid\n",
- cnt);
- goto bail;
- }
- }
- /* IC to close the coal frame before HPS Clear if coal is enabled */
- if (ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS) != -1) {
- i = ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_COAL_CONS);
- reg_write_coal_close.skip_pipeline_clear = false;
- reg_write_coal_close.pipeline_clear_options = IPAHAL_HPS_CLEAR;
- reg_write_coal_close.offset = ipahal_get_reg_ofst(
- IPA_AGGR_FORCE_CLOSE);
- ipahal_get_aggr_force_close_valmask(i, &valmask);
- reg_write_coal_close.value = valmask.val;
- reg_write_coal_close.value_mask = valmask.mask;
- cmd_pyld[num_cmd] = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_REGISTER_WRITE,
- ®_write_coal_close, false);
- if (!cmd_pyld[num_cmd]) {
- IPAERR("failed to construct coal close IC\n");
- result = -ENOMEM;
- goto destroy_imm_cmd;
- }
- ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
- ++num_cmd;
- }
- /*
- * NO-OP IC for ensuring that IPA pipeline is empty
- */
- cmd_pyld[num_cmd] =
- ipahal_construct_nop_imm_cmd(false, IPAHAL_HPS_CLEAR, false);
- if (!cmd_pyld[num_cmd]) {
- IPAERR("Failed to construct NOP imm cmd\n");
- result = -ENOMEM;
- goto destroy_imm_cmd;
- }
- ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
- ++num_cmd;
- /*
- * NAT_DMA was renamed to TABLE_DMA starting from IPAv4
- */
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
- cmd_name = IPA_IMM_CMD_TABLE_DMA;
- for (cnt = 0; cnt < dma->entries; ++cnt) {
- cmd.table_index = dma->dma[cnt].table_index;
- cmd.base_addr = dma->dma[cnt].base_addr;
- cmd.offset = dma->dma[cnt].offset;
- cmd.data = dma->dma[cnt].data;
- cmd_pyld[num_cmd] =
- ipahal_construct_imm_cmd(cmd_name, &cmd, false);
- if (!cmd_pyld[num_cmd]) {
- IPAERR_RL("Fail to construct table_dma imm cmd\n");
- result = -ENOMEM;
- goto destroy_imm_cmd;
- }
- ipa3_init_imm_cmd_desc(&desc[num_cmd], cmd_pyld[num_cmd]);
- ++num_cmd;
- }
- result = ipa3_send_cmd(num_cmd, desc);
- if (result)
- IPAERR("Fail to send table_dma immediate command\n");
- destroy_imm_cmd:
- for (cnt = 0; cnt < num_cmd; ++cnt)
- ipahal_destroy_imm_cmd(cmd_pyld[cnt]);
- bail:
- IPADBG("Out\n");
- return result;
- }
- /**
- * ipa3_nat_dma_cmd() - Post NAT_DMA command to IPA HW
- * @dma: [in] initialization command attributes
- *
- * Called by NAT client driver to post NAT_DMA command to IPA HW
- *
- * Returns: 0 on success, negative on failure
- */
- int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma)
- {
- return ipa3_table_dma_cmd(dma);
- }
- static void ipa3_nat_ipv6ct_free_mem(
- struct ipa3_nat_ipv6ct_common_mem *dev)
- {
- struct ipa3_nat_mem *nm_ptr;
- struct ipa3_nat_mem_loc_data *mld_ptr;
- if (dev->is_ipv6ct_mem) {
- IPADBG("In: v6\n");
- if (dev->vaddr) {
- IPADBG("Freeing dma memory for %s\n", dev->name);
- dma_free_coherent(
- ipa3_ctx->pdev,
- dev->table_alloc_size,
- dev->vaddr,
- dev->dma_handle);
- }
- dev->vaddr = NULL;
- dev->dma_handle = 0;
- dev->table_alloc_size = 0;
- dev->base_table_addr = NULL;
- dev->expansion_table_addr = NULL;
- dev->table_entries = 0;
- dev->expn_table_entries = 0;
- dev->is_hw_init = false;
- dev->is_mapped = false;
- } else {
- if (dev->is_nat_mem) {
- IPADBG("In: v4\n");
- nm_ptr = (struct ipa3_nat_mem *) dev;
- if (nm_ptr->ddr_in_use) {
- nm_ptr->ddr_in_use = false;
- mld_ptr = &nm_ptr->mem_loc[IPA_NAT_MEM_IN_DDR];
- if (mld_ptr->vaddr) {
- IPADBG("Freeing dma memory for %s\n",
- dev->name);
- dma_free_coherent(
- ipa3_ctx->pdev,
- mld_ptr->table_alloc_size,
- mld_ptr->vaddr,
- mld_ptr->dma_handle);
- }
- mld_ptr->vaddr = NULL;
- mld_ptr->dma_handle = 0;
- mld_ptr->table_alloc_size = 0;
- mld_ptr->table_entries = 0;
- mld_ptr->expn_table_entries = 0;
- mld_ptr->base_table_addr = NULL;
- mld_ptr->expansion_table_addr = NULL;
- mld_ptr->index_table_addr = NULL;
- mld_ptr->index_table_expansion_addr = NULL;
- }
- if (nm_ptr->sram_in_use) {
- nm_ptr->sram_in_use = false;
- mld_ptr = &nm_ptr->mem_loc[IPA_NAT_MEM_IN_SRAM];
- if (mld_ptr->io_vaddr) {
- IPADBG("Unmappung sram memory for %s\n",
- dev->name);
- iounmap(mld_ptr->io_vaddr);
- }
- mld_ptr->io_vaddr = NULL;
- mld_ptr->vaddr = NULL;
- mld_ptr->dma_handle = 0;
- mld_ptr->table_alloc_size = 0;
- mld_ptr->table_entries = 0;
- mld_ptr->expn_table_entries = 0;
- mld_ptr->base_table_addr = NULL;
- mld_ptr->expansion_table_addr = NULL;
- mld_ptr->index_table_addr = NULL;
- mld_ptr->index_table_expansion_addr = NULL;
- }
- memset(nm_ptr->mem_loc, 0, sizeof(nm_ptr->mem_loc));
- }
- }
- IPADBG("Out\n");
- }
- static int ipa3_nat_ipv6ct_create_del_table_cmd(
- uint8_t tbl_index,
- u32 base_addr,
- struct ipa3_nat_ipv6ct_common_mem *dev,
- struct ipahal_imm_cmd_nat_ipv6ct_init_common *table_init_cmd)
- {
- bool mem_type_shared = true;
- IPADBG("In: tbl_index(%u) base_addr(%u) v4(%u) v6(%u)\n",
- tbl_index,
- base_addr,
- dev->is_nat_mem,
- dev->is_ipv6ct_mem);
- if (!IPA_VALID_TBL_INDEX(tbl_index)) {
- IPAERR_RL("Unsupported table index %d\n", tbl_index);
- return -EPERM;
- }
- if (dev->tmp_mem) {
- IPADBG("using temp memory during %s del\n", dev->name);
- mem_type_shared = false;
- base_addr = dev->tmp_mem->dma_handle;
- }
- table_init_cmd->table_index = tbl_index;
- table_init_cmd->base_table_addr = base_addr;
- table_init_cmd->base_table_addr_shared = mem_type_shared;
- table_init_cmd->expansion_table_addr = base_addr;
- table_init_cmd->expansion_table_addr_shared = mem_type_shared;
- table_init_cmd->size_base_table = 0;
- table_init_cmd->size_expansion_table = 0;
- IPADBG("Out\n");
- return 0;
- }
- static int ipa3_nat_send_del_table_cmd(
- uint8_t tbl_index)
- {
- struct ipahal_imm_cmd_ip_v4_nat_init cmd;
- int result = 0;
- IPADBG("In\n");
- result =
- ipa3_nat_ipv6ct_create_del_table_cmd(
- tbl_index,
- IPA_NAT_PHYS_MEM_OFFSET,
- &ipa3_ctx->nat_mem.dev,
- &cmd.table_init);
- if (result) {
- IPAERR(
- "Fail to create immediate command to delete NAT table\n");
- goto bail;
- }
- cmd.index_table_addr =
- cmd.table_init.base_table_addr;
- cmd.index_table_addr_shared =
- cmd.table_init.base_table_addr_shared;
- cmd.index_table_expansion_addr =
- cmd.index_table_addr;
- cmd.index_table_expansion_addr_shared =
- cmd.index_table_addr_shared;
- cmd.public_addr_info = 0;
- IPADBG("Posting NAT delete command\n");
- result = ipa3_nat_send_init_cmd(&cmd, true);
- if (result) {
- IPAERR("Fail to send NAT delete immediate command\n");
- goto bail;
- }
- bail:
- IPADBG("Out\n");
- return result;
- }
- static int ipa3_ipv6ct_send_del_table_cmd(uint8_t tbl_index)
- {
- struct ipahal_imm_cmd_ip_v6_ct_init cmd;
- int result;
- IPADBG("\n");
- result = ipa3_nat_ipv6ct_create_del_table_cmd(
- tbl_index,
- IPA_IPV6CT_PHYS_MEM_OFFSET,
- &ipa3_ctx->ipv6ct_mem.dev,
- &cmd.table_init);
- if (result) {
- IPAERR(
- "Fail to create immediate command to delete IPv6CT table\n");
- return result;
- }
- IPADBG("posting IPv6CT delete command\n");
- result = ipa3_ipv6ct_send_init_cmd(&cmd);
- if (result) {
- IPAERR("Fail to send IPv6CT delete immediate command\n");
- return result;
- }
- IPADBG("return\n");
- return 0;
- }
- /**
- * ipa3_nat_del_cmd() - Delete a NAT table
- * @del: [in] delete table table table parameters
- *
- * Called by NAT client driver to delete the nat table
- *
- * Returns: 0 on success, negative on failure
- */
- int ipa3_nat_del_cmd(struct ipa_ioc_v4_nat_del *del)
- {
- struct ipa_ioc_nat_ipv6ct_table_del tmp;
- tmp.table_index = del->table_index;
- return ipa3_del_nat_table(&tmp);
- }
- /**
- * ipa3_del_nat_table() - Delete the NAT table
- * @del: [in] delete table parameters
- *
- * Called by NAT client to delete the table
- *
- * Returns: 0 on success, negative on failure
- */
- int ipa3_del_nat_table(
- struct ipa_ioc_nat_ipv6ct_table_del *del)
- {
- struct ipa3_nat_ipv6ct_common_mem *dev = &ipa3_ctx->nat_mem.dev;
- struct ipa3_nat_mem *nm_ptr = (struct ipa3_nat_mem *) dev;
- struct ipa3_nat_mem_loc_data *mld_ptr;
- enum ipa3_nat_mem_in nmi;
- int result = 0;
- IPADBG("In\n");
- if (!sram_compatible)
- del->mem_type = 0;
- nmi = del->mem_type;
- if (!dev->is_dev_init) {
- IPAERR("NAT hasn't been initialized\n");
- result = -EPERM;
- goto bail;
- }
- if (!IPA_VALID_TBL_INDEX(del->table_index)) {
- IPAERR_RL("Unsupported table index %d\n",
- del->table_index);
- result = -EPERM;
- goto bail;
- }
- if (!IPA_VALID_NAT_MEM_IN(nmi)) {
- IPAERR_RL("Bad ipa3_nat_mem_in type\n");
- result = -EPERM;
- goto bail;
- }
- IPADBG("nmi(%s)\n", ipa3_nat_mem_in_as_str(nmi));
- mld_ptr = &nm_ptr->mem_loc[nmi];
- mutex_lock(&dev->lock);
- if (dev->is_hw_init) {
- result = ipa3_nat_send_del_table_cmd(del->table_index);
- if (result) {
- IPAERR(
- "Fail to send immediate command to delete NAT table\n");
- goto unlock;
- }
- }
- nm_ptr->public_ip_addr = 0;
- mld_ptr->index_table_addr = NULL;
- mld_ptr->index_table_expansion_addr = NULL;
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0
- &&
- nm_ptr->pdn_mem.base) {
- struct ipa_mem_buffer *pdn_mem_ptr = &nm_ptr->pdn_mem;
- IPADBG("Freeing the PDN memory\n");
- dma_free_coherent(
- ipa3_ctx->pdev,
- pdn_mem_ptr->size,
- pdn_mem_ptr->base,
- pdn_mem_ptr->phys_base);
- pdn_mem_ptr->base = NULL;
- }
- ipa3_nat_ipv6ct_free_mem(dev);
- unlock:
- mutex_unlock(&dev->lock);
- bail:
- IPADBG("Out\n");
- return result;
- }
- /**
- * ipa3_del_ipv6ct_table() - Delete the IPv6CT table
- * @del: [in] delete table parameters
- *
- * Called by IPv6CT client to delete the table
- *
- * Returns: 0 on success, negative on failure
- */
- int ipa3_del_ipv6ct_table(
- struct ipa_ioc_nat_ipv6ct_table_del *del)
- {
- struct ipa3_nat_ipv6ct_common_mem *dev = &ipa3_ctx->ipv6ct_mem.dev;
- int result = 0;
- IPADBG("In\n");
- if (!sram_compatible)
- del->mem_type = 0;
- if (!dev->is_dev_init) {
- IPAERR("IPv6 connection tracking hasn't been initialized\n");
- result = -EPERM;
- goto bail;
- }
- if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
- IPAERR_RL("IPv6 connection tracking isn't supported\n");
- result = -EPERM;
- goto bail;
- }
- mutex_lock(&dev->lock);
- if (dev->is_hw_init) {
- result = ipa3_ipv6ct_send_del_table_cmd(del->table_index);
- if (result) {
- IPAERR("ipa3_ipv6ct_send_del_table_cmd() fail\n");
- goto unlock;
- }
- }
- ipa3_nat_ipv6ct_free_mem(&ipa3_ctx->ipv6ct_mem.dev);
- unlock:
- mutex_unlock(&dev->lock);
- bail:
- IPADBG("Out\n");
- return result;
- }
- int ipa3_nat_get_sram_info(
- struct ipa_nat_in_sram_info *info_ptr)
- {
- struct ipa3_nat_ipv6ct_common_mem *dev = &ipa3_ctx->nat_mem.dev;
- int ret = 0;
- IPADBG("In\n");
- if (!info_ptr) {
- IPAERR("Bad argument passed\n");
- ret = -EINVAL;
- goto bail;
- }
- if (!dev->is_dev_init) {
- IPAERR_RL("NAT hasn't been initialized\n");
- ret = -EPERM;
- goto bail;
- }
- sram_compatible = true;
- memset(info_ptr,
- 0,
- sizeof(struct ipa_nat_in_sram_info));
- /*
- * Size of SRAM set aside for the NAT table.
- */
- info_ptr->sram_mem_available_for_nat = IPA_RAM_NAT_SIZE;
- /*
- * If table's phys addr in SRAM is not page aligned, it will be
- * offset into the mmap'd VM by the amount calculated below. This
- * value can be used by the app, so that it can know where the
- * table actually lives in the mmap'd VM...
- */
- info_ptr->nat_table_offset_into_mmap =
- (ipa3_ctx->ipa_wrapper_base +
- ipa3_ctx->ctrl->ipa_reg_base_ofst +
- ipahal_get_reg_n_ofst(
- IPA_SW_AREA_RAM_DIRECT_ACCESS_n,
- 0) +
- IPA_RAM_NAT_OFST) & ~PAGE_MASK;
- /*
- * If the offset above plus the size of the NAT table causes the
- * table to extend beyond the next page boundary, the app needs to
- * know it, so that it can increase the size used in the mmap
- * request...
- */
- info_ptr->best_nat_in_sram_size_rqst =
- roundup(
- info_ptr->nat_table_offset_into_mmap +
- IPA_RAM_NAT_SIZE,
- PAGE_SIZE);
- bail:
- IPADBG("Out\n");
- return ret;
- }
|