From e588172442093fe22374dc1bfc88a7da751d6b30 Mon Sep 17 00:00:00 2001 From: Bogdan Hamciuc Date: Tue, 15 Sep 2015 10:14:16 -0500 Subject: [PATCH 201/226] staging: dpaa2-eth: initial commit of dpaa2-eth driver commit 3106ece5d96784b63a4eabb26661baaefedd164f [context adjustment] This is a commit of a squash of the cumulative dpaa2-eth patches in the sdk 2.0 kernel as of 3/7/2016. flib,dpaa2-eth: flib header update (Rebasing onto kernel 3.19, MC 0.6) this patch was moved from 4.0 branch Signed-off-by: Bogdan Hamciuc [Stuart: split into multiple patches] Signed-off-by: Stuart Yoder Integrated-by: Jilong Guo flib,dpaa2-eth: updated Eth (was: Rebasing onto kernel 3.19, MC 0.6) updated Ethernet driver from 4.0 branch Signed-off-by: Bogdan Hamciuc [Stuart: cherry-picked patch from 4.0 and split it up] Signed-off-by: Stuart Yoder Conflicts: drivers/staging/Makefile Signed-off-by: Stuart Yoder dpaa2-eth: Adjust 'options' size The 'options' field of various MC configuration structures has changed from u64 to u32 as of MC firmware version 7.0. Signed-off-by: Bogdan Hamciuc Change-Id: I9ba0c19fc22f745e6be6cc40862afa18fa3ac3db Reviewed-on: http://git.am.freescale.net:8181/35579 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Selectively disable preemption Temporary workaround for a MC Bus API quirk which only allows us to specify exclusively, either a spinlock-protected MC Portal, or a mutex-protected one, but then tries to match the runtime context in order to enforce their usage. Te Be Reverted. Signed-off-by: Bogdan Hamciuc Change-Id: Ida2ec1fdbdebfd2e427f96ddad7582880146fda9 Reviewed-on: http://git.am.freescale.net:8181/35580 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Fix ethtool bug We were writing beyond the end of the allocated data area for ethtool statistics. Signed-off-by: Ioana Radulescu Change-Id: I6b77498a78dad06970508ebbed7144be73854f7f Reviewed-on: http://git.am.freescale.net:8181/35583 Reviewed-by: Bogdan Hamciuc Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Retry read if store unexpectedly empty After we place a volatile dequeue command, we might get to inquire the store before the DMA has actually completed. In such cases, we must retry, lest we'll have the store overwritten by the next legitimate volatile dequeue. Signed-off-by: Bogdan Hamciuc Change-Id: I314fbb8b4d9f589715e42d35fc6677d726b8f5ba Reviewed-on: http://git.am.freescale.net:8181/35584 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder flib: Fix "missing braces around initializer" warning Gcc does not support (yet?) the ={0} initializer in the case of an array of structs. Fixing the Flib in order to make the warning go away. Signed-off-by: Bogdan Hamciuc Change-Id: I8782ecb714c032cfeeecf4c8323cf9dbb702b10f Reviewed-on: http://git.am.freescale.net:8181/35586 Reviewed-by: Stuart Yoder Tested-by: Stuart Yoder Revert "dpaa2-eth: Selectively disable preemption" This reverts commit e1455823c33b8dd48b5d2d50a7e8a11d3934cc0d. dpaa2-eth: Fix memory leak A buffer kmalloc'ed at probe time was not freed after it was no longer needed. Signed-off-by: Ioana Radulescu Change-Id: Iba197209e9203ed306449729c6dcd23ec95f094d Reviewed-on: http://git.am.freescale.net:8181/35756 Reviewed-by: Bogdan Hamciuc Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Remove unused field in ldpaa_eth_priv structure Signed-off-by: Ioana Radulescu Change-Id: I124c3e4589b6420b1ea5cc05a03a51ea938b2bea Reviewed-on: http://git.am.freescale.net:8181/35757 Reviewed-by: Bogdan Hamciuc Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Fix "NOHZ: local_softirq_pending" warning Explicitly run softirqs after we enable NAPI. This in particular gets us rid of the "NOHZ: local_softirq_pending" warnings, but it also solves a couple of other problems, among which fluctuating performance and high ping latencies. Notes: - This will prevent us from timely processing notifications and other "non-frame events" coming into the software portal. So far, though, we only expect Dequeue Available Notifications, so this patch is good enough for now. - A degradation in console responsiveness is expected, especially in cases where the bottom-half runs on the same CPU as the console. Signed-off-by: Bogdan Hamciuc Signed-off-by: Ioana Radulescu Change-Id: Ia6f11da433024e80ee59e821c9eabfa5068df5e5 Reviewed-on: http://git.am.freescale.net:8181/35830 Reviewed-by: Alexandru Marginean Reviewed-by: Stuart Yoder Tested-by: Stuart Yoder dpaa2-eth: Add polling mode for link state changes Add the Kconfigurable option of using a thread for polling on the link state instead of relying on interrupts from the MC. Signed-off-by: Ioana Radulescu Change-Id: If2fe66fc5c0fbee2568d7afa15d43ea33f92e8e2 Reviewed-on: http://git.am.freescale.net:8181/35967 Tested-by: Review Code-CDREVIEW Reviewed-by: Bogdan Hamciuc Reviewed-by: Stuart Yoder dpaa2-eth: Update copyright years. Signed-off-by: Bogdan Hamciuc Change-Id: I7e00eecfc5569027c908124726edaf06be357c02 Reviewed-on: http://git.am.freescale.net:8181/37666 Tested-by: Review Code-CDREVIEW Reviewed-by: Ruxandra Ioana Radulescu Reviewed-by: Stuart Yoder dpaa2-eth: Drain bpools when netdev is down In a data path layout with potentially a dozen interfaces, not all of them may be up at the same time, yet they may consume a fair amount of buffer space. Drain the buffer pool upon ifdown and re-seed it at ifup. Signed-off-by: Bogdan Hamciuc Change-Id: I24a379b643c8b5161a33b966c3314cf91024ed4a Reviewed-on: http://git.am.freescale.net:8181/37667 Tested-by: Review Code-CDREVIEW Reviewed-by: Ruxandra Ioana Radulescu Reviewed-by: Stuart Yoder dpaa2-eth: Interrupts cleanup Add the code for cleaning up interrupts on driver removal. This was lost during transition from kernel 3.16 to 3.19. Also, there's no need to call devm_free_irq() if probe fails as the kernel will release all driver resources. Signed-off-by: Ioana Radulescu Change-Id: Ifd404bbf399d5ba62e2896371076719c1d6b4214 Reviewed-on: http://git.am.freescale.net:8181/36199 Tested-by: Review Code-CDREVIEW Reviewed-by: Bogdan Hamciuc Reviewed-by: Bharat Bhushan Reviewed-by: Stuart Yoder Reviewed-on: http://git.am.freescale.net:8181/37690 dpaa2-eth: Ethtool support for hashing Only one set of header fields is supported for all protocols, the driver silently replaces previous configuration regardless of user selected protocol. Following fields are supported: L2DA VLAN tag L3 proto IP SA IP DA L4 bytes 0 & 1 [TCP/UDP src port] L4 bytes 2 & 3 [TCP/UDP dst port] Signed-off-by: Alex Marginean Change-Id: I97c9dac1b842fe6bc7115e40c08c42f67dee8c9c Reviewed-on: http://git.am.freescale.net:8181/37260 Tested-by: Review Code-CDREVIEW Reviewed-by: Bogdan Hamciuc Reviewed-by: Stuart Yoder dpaa2-eth: Fix maximum number of FQs The maximum number of Rx/Tx conf FQs associated to a DPNI was not updated when the implementation changed. It just happened to work by accident. Signed-off-by: Ioana Radulescu Reviewed-by: Bogdan Hamciuc Change-Id: I03e30e0121a40d0d15fcdc4bee1fb98caa17c0ef Reviewed-on: http://git.am.freescale.net:8181/37668 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Fix Rx buffer address alignment We need to align the start address of the Rx buffers to LDPAA_ETH_BUF_ALIGN bytes. We were using SMP_CACHE_BYTES instead. It happened to work because both defines have the value of 64, but this may change at some point. Signed-off-by: Ioana Radulescu Reviewed-by: Bogdan Hamciuc Change-Id: I08a0f3f18f82c5581c491bd395e3ad066b25bcf5 Reviewed-on: http://git.am.freescale.net:8181/37669 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Add buffer count to ethtool statistics Print the number of buffers available in the pool for a certain DPNI along with the rest of the ethtool -S stats. Signed-off-by: Ioana Radulescu Reviewed-by: Bogdan Hamciuc Change-Id: Ia1f5cf341c8414ae2058a73f6bc81490ef134592 Reviewed-on: http://git.am.freescale.net:8181/37671 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Add Rx error queue Add a Kconfigurable option that allows Rx error frames to be enqueued on an error FQ. By default error frames are discarded, but for debug purposes we may want to process them at driver level. Note: Checkpatch issues a false positive about complex macros that should be parenthesized. Signed-off-by: Ioana Radulescu Reviewed-by: Bogdan Hamciuc Change-Id: I7d19d00b5d5445514ebd112c886ce8ccdbb1f0da Reviewed-on: http://git.am.freescale.net:8181/37672 Reviewed-by: Stuart Yoder Tested-by: Stuart Yoder staging: fsl-dpaa2: FLib headers cleanup Going with the flow of moving fsl-dpaa2 headers into the drivers' location rather than keeping them all in one place. Signed-off-by: Bogdan Hamciuc Change-Id: Ia2870cd019a4934c7835d38752a46b2a0045f30e Reviewed-on: http://git.am.freescale.net:8181/37674 Reviewed-by: Ruxandra Ioana Radulescu Reviewed-by: Stuart Yoder Tested-by: Stuart Yoder dpaa2-eth: Klocwork fixes Fix several issues reported by Klocwork. Signed-off-by: Ioana Radulescu Reviewed-by: Bogdan Hamciuc Change-Id: I1e23365765f3b0ff9b6474d8207df7c1f2433ccd Reviewed-on: http://git.am.freescale.net:8181/37675 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Probe devices with no hash support Don't fail at probe if the DPNI doesn't have the hash distribution option enabled. Instead, initialize a single Rx frame queue and use it for all incoming traffic. Rx flow hashing configuration through ethtool will not work in this case. Signed-off-by: Ioana Radulescu Reviewed-by: Bogdan Hamciuc Change-Id: Iaf17e05b15946e6901c39a21b5344b89e9f1d797 Reviewed-on: http://git.am.freescale.net:8181/37676 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Process frames in IRQ context Stop using threaded IRQs and move back to hardirq top-halves. This is the first patch of a small series adapting the DPIO and Ethernet code to these changes. Signed-off-by: Roy Pledge Tested-by: Ioana Radulescu Tested-by: Bogdan Hamciuc Reviewed-by: Bogdan Hamciuc Reviewed-by: Stuart Yoder [Stuart: split dpio and eth into separate patches, updated subject] Signed-off-by: Stuart Yoder dpaa2-eth: Fix bug in NAPI poll We incorrectly rearmed FQDAN notifications at the end of a NAPI cycle, regardless of whether the NAPI budget was consumed or not. We only need to rearm notifications if the NAPI cycle cleaned less frames than its budget, otherwise a new NAPI poll will be scheduled anyway. Signed-off-by: Ioana Radulescu Reviewed-by: Bogdan Hamciuc Change-Id: Ib55497bdbd769047420b3150668f2e2aef3c93f6 Reviewed-on: http://git.am.freescale.net:8181/38317 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Use dma_map_sg on Tx Use the simpler dma_map_sg() along with the scatterlist API if the egress frame is scatter-gather, at the cost of keeping some extra information in the frame's software annotation area. Signed-off-by: Bogdan Hamciuc Change-Id: If293aeabbd58d031f21456704357d4ff7e53c559 Reviewed-on: http://git.am.freescale.net:8181/37681 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Reduce retries if Tx portal busy Too many retries due to Tx portal contention led to a significant cycle waste and reduction in performance. Reducing the number of enqueue retries and dropping frame if eventually unsuccessful. Signed-off-by: Bogdan Hamciuc Change-Id: Ib111ec61cd4294a7632348c25fa3d7f4002be0c0 Reviewed-on: http://git.am.freescale.net:8181/37682 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Add sysfs support for TxConf affinity change This adds support in sysfs for affining Tx Confirmation queues to GPPs, via the affine DPIO objects. The user can specify a cpu list in /sys/class/net/ni/txconf_affinity to which the Ethernet driver will affine the TxConf FQs, in round-robin fashion. This is naturally a bit coarse, because there is no "official" mapping of the transmitting CPUs to Tx Confirmation queues. Signed-off-by: Bogdan Hamciuc Change-Id: I4b3da632e202ceeb22986c842d746aafe2a87a81 Reviewed-on: http://git.am.freescale.net:8181/37684 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Implement ndo_select_queue Use a very simple selection function for the egress FQ. The purpose behind this is to more evenly distribute Tx Confirmation traffic, especially in the case of multiple egress flows, when bundling it all on CPU 0 would make that CPU a bottleneck. Signed-off-by: Bogdan Hamciuc Change-Id: Ibfe8aad7ad5c719cc95d7817d7de6d2094f0f7ed Reviewed-on: http://git.am.freescale.net:8181/37685 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Reduce TxConf NAPI weight back to 64 It turns out that not only the kernel frowned upon the old budget of 256, but the measured values were well below that anyway. Signed-off-by: Bogdan Hamciuc Change-Id: I62ddd3ea1dbfd8b51e2bcb2286e0d5eb10ac7f27 Reviewed-on: http://git.am.freescale.net:8181/37688 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Try refilling the buffer pool less often We used to check if the buffer pool needs refilling at each Rx frame. Instead, do that check (and the actual buffer release if needed) only after a pull dequeue. Signed-off-by: Ioana Radulescu Change-Id: Id52fab83873c40a711b8cadfcf909eb7e2e210f3 Reviewed-on: http://git.am.freescale.net:8181/38318 Tested-by: Review Code-CDREVIEW Reviewed-by: Bogdan Hamciuc Reviewed-by: Stuart Yoder dpaa2-eth: Stay in NAPI if exact budget is met An off-by-one bug would cause premature exiting from the NAPI cycle. Performance degradation is particularly severe in IPFWD cases. Signed-off-by: Ioana Radulescu Tested-by: Bogdan Hamciuc Change-Id: I9de2580c7ff8e46cbca9613890b03737add35e26 Reviewed-on: http://git.am.freescale.net:8181/37908 Tested-by: Review Code-CDREVIEW Reviewed-by: Bogdan Hamciuc Reviewed-by: Stuart Yoder dpaa2-eth: Minor changes to FQ stats Signed-off-by: Ioana Radulescu Change-Id: I0ced0e7b2eee28599cdea79094336c0d44f0d32b Reviewed-on: http://git.am.freescale.net:8181/38319 Tested-by: Review Code-CDREVIEW Reviewed-by: Bogdan Hamciuc Reviewed-by: Stuart Yoder dpaa2-eth: Support fewer DPIOs than CPUs The previous DPIO functions would transparently choose a (perhaps non-affine) CPU if the required CPU was not available. Now that their API contract is enforced, we must make an explicit request for *any* DPIO if the request for an *affine* DPIO has failed. Signed-off-by: Bogdan Hamciuc Change-Id: Ib08047ffa33518993b1ffa4671d0d4f36d6793d0 Reviewed-on: http://git.am.freescale.net:8181/38320 Tested-by: Review Code-CDREVIEW Reviewed-by: Roy Pledge Reviewed-by: Stuart Yoder dpaa2-eth: cosmetic changes in hashing code Signed-off-by: Alex Marginean Change-Id: I79e21a69a6fb68cdbdb8d853c059661f8988dbf9 Reviewed-on: http://git.am.freescale.net:8181/37258 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Prefetch data before initial access Signed-off-by: Ioana Radulescu Change-Id: Ie8f0163651aea7e3e197a408f89ca98d296d4b8b Reviewed-on: http://git.am.freescale.net:8181/38753 Reviewed-by: Bogdan Hamciuc Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Use netif_receive_skb netif_rx() is a leftover since our pre-NAPI codebase. Signed-off-by: Ioana Radulescu Change-Id: I02ff0a059862964df1bf81b247853193994c2dfe Reviewed-on: http://git.am.freescale.net:8181/38754 Reviewed-by: Bogdan Hamciuc Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Use napi_alloc_frag() on Rx. A bit better-suited than netdev_alloc_frag(). Signed-off-by: Ioana Radulescu Change-Id: I8863a783502db963e5dc968f049534c36ad484e2 Reviewed-on: http://git.am.freescale.net:8181/38755 Reviewed-by: Bogdan Hamciuc Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Silence skb_realloc_headroom() warning pktgen tests tend to be too noisy because pktgen does not observe the net device's needed_headroom specification and we used to be pretty loud about that. We'll print the warning message just once. Signed-off-by: Bogdan Hamciuc Change-Id: I3c12eba29c79aa9c487307d367f6d9f4dbe447a3 Reviewed-on: http://git.am.freescale.net:8181/38756 Reviewed-by: Ruxandra Ioana Radulescu Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Print message upon device unplugging Give a console notification when a DPNI is unplugged. This is useful for automated tests to know the operation (which is not instantaneous) has finished. Signed-off-by: Bogdan Hamciuc Change-Id: If33033201fcee7671ad91c2b56badf3fb56a9e3e Reviewed-on: http://git.am.freescale.net:8181/38757 Reviewed-by: Ruxandra Ioana Radulescu Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Add debugfs support Add debugfs entries for showing detailed per-CPU and per-FQ counters for each network interface. Also add a knob for resetting these stats. The agregated interface statistics were already available through ethtool -S. Signed-off-by: Ioana Radulescu Reviewed-by: Bogdan Hamciuc Change-Id: I55f5bfe07a15b0d1bf0c6175d8829654163a4318 Reviewed-on: http://git.am.freescale.net:8181/38758 Reviewed-by: Stuart Yoder Tested-by: Stuart Yoder dpaa2-eth: limited support for flow steering Steering is supported on a sub-set of fields, including DMAC, IP SRC and DST, L4 ports. Steering and hashing configurations depend on each other, that makes the whole thing tricky to configure. Currently FS can be configured using only the fields selected for hashing and all the hashing fields must be included in the match key - masking doesn't work yet. Signed-off-by: Alex Marginean Change-Id: I9fa3199f7818a9a5f9d69d3483ffd839056cc468 Reviewed-on: http://git.am.freescale.net:8181/38759 Reviewed-by: Bogdan Hamciuc Tested-by: Review Code-CDREVIEW Reviewed-by: Ruxandra Ioana Radulescu Reviewed-by: Stuart Yoder dpaa2-eth: Rename files into the dpaa2 nomenclature Signed-off-by: Bogdan Hamciuc Change-Id: I1c3d62e2f19a59d4b65727234fd7df2dfd8683d9 Reviewed-on: http://git.am.freescale.net:8181/38965 Reviewed-by: Alexandru Marginean Reviewed-by: Ruxandra Ioana Radulescu Reviewed-by: Stuart Yoder Tested-by: Stuart Yoder staging: dpaa2-eth: migrated remaining flibs for MC fw 8.0.0 Signed-off-by: J. German Rivera [Stuart: split eth part into separate patch, updated subject] Signed-off-by: Stuart Yoder dpaa2-eth: Clear 'backup_pool' attribute New MC-0.7 firmware allows specifying an alternate buffer pool, but we are momentarily not using that feature. Signed-off-by: Bogdan Hamciuc Change-Id: I0a6e6626512b7bbddfef732c71f1400b67f3e619 Reviewed-on: http://git.am.freescale.net:8181/39149 Tested-by: Review Code-CDREVIEW Reviewed-by: Stuart Yoder dpaa2-eth: Do programing of MSIs in devm_request_threaded_irq() With the new dprc_set_obj_irq() we can now program MSIS in the device in the callback invoked from devm_request_threaded_irq(). Since this callback is invoked with interrupts disabled, we need to use an atomic portal, instead of the root DPRC's built-in portal which is non-atomic. Signed-off-by: Itai Katz Signed-off-by: J. German Rivera [Stuart: split original patch into multiple patches] Signed-off-by: Stuart Yoder dpaa2-eth: Do not map beyond skb tail On Tx do dma_map only until skb->tail, rather than skb->end. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Declare NETIF_F_LLTX as a capability We are effectively doing lock-less Tx. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Avoid bitcopy of 'backpointers' struct Make 'struct ldpaa_eth_swa bps' a pointer and void copying it on both Tx and TxConf. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Use CDANs instead of FQDANs Use Channel Dequeue Available Notifications (CDANs) instead of Frame Queue notifications. We allocate a QMan channel (or DPCON object) for each available cpu and assign to it the Rx and Tx conf queues associated with that cpu. We usually want to have affine DPIOs and DPCONs (one for each core). If this is not possible due to insufficient resources, we distribute all ingress traffic on the cores with affine DPIOs. NAPI instances are now one per channel instead of one per FQ, as the interrupt source changes. Statistics counters change accordingly. Note that after this commit is applied, one needs to provide sufficient DPCON objects (either through DPL on restool) in order for the Ethernet interfaces to work. Signed-off-by: Ioana Radulescu Signed-off-by: Bogdan Hamciuc dpaa2-eth: Cleanup debugfs statistics Several minor changes to statistics reporting: * Fix print alignment of statistics counters * Fix a naming ambiguity in the cpu_stats debugfs ops * Add Rx/Tx error counters; these were already used, but not reported in the per-CPU stats Signed-off-by: Ioana Radulescu dpaa2-eth: Add tx shaping configuration in sysfs Egress traffic can be shaped via a per-DPNI SysFS entry: echo M N > /sys/class/net/ni/tx_shaping where: M is the maximum throughput, expressed in Mbps. N is the maximum burst size, expressed in bytes, at most 64000. To remove shaping, use M=0, N=0. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Fix "Tx busy" counter Under heavy egress load, when a large number of the transmitted packets cannot be sent because of high portal contention, the "Tx busy" counter was not properly incremented. Signed-off-by: Ioana Radulescu dpaa2-eth: Fix memory cleanup in case of Tx congestion The error path of ldpaa_eth_tx() was not properly freeing the SGT buffer if the enqueue had failed because of congestion. DMA unmapping was missing, too. Factor the code originally inside the TxConf callback out into a separate function that would be called on both TxConf and Tx paths. Signed-off-by: Bogdan Hamciuc Signed-off-by: Ioana Radulescu dpaa2-eth: Use napi_gro_receive() Call napi_gro_receive(), effectively enabling GRO. NOTE: We could further optimize this by looking ahead in the parse results received from hardware and only using GRO when the L3+L4 combination is appropriate. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Fix compilation of Rx Error FQ code Conditionally-compiled code slipped between cracks when FLibs were updated. Signed-off-by: Ioana Radulescu fsl-dpaa2: Add Kconfig dependency on DEBUG_FS The driver's debugfs support depends on the generic CONFIG_DEBUG_FS. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Fix interface down/up bug If a networking interface was brought down while still receiving ingress traffic, the delay between DPNI disable and NAPI disable was not enough to ensure all in-flight frames got processed. Instead, some frames were left pending in the Rx queues. If the net device was then removed (i.e. restool unbind/unplug), the call to dpni_reset() silently failed and the kernel crashed on device replugging. Fix this by increasing the FQ drain time. Also, at ifconfig up we enable NAPI before starting the DPNI, to make sure we don't miss any early CDANs. Signed-off-by: Ioana Radulescu dpaa2-eth: Iterate only through initialized channels The number of DPIO objects available to a DPNI may be fewer than the number of online cores. A typical example would be a DPNI with a distribution size smaller than 8. Since we only initialize as many channels (DPCONs) as there are DPIOs, iterating through all online cpus would produce a nasty oops when retrieving ethtool stats. Signed-off-by: Bogdan Hamciuc net: pktgen: Observe needed_headroom of the device Allocate enough space so as not to force the outgoing net device to do skb_realloc_headroom(). Signed-off-by: Bogdan Hamciuc Signed-off-by: David S. Miller dpaa2-eth: Trace buffer pool seeding Add ftrace support for buffer pool seeding. Individual buffers are described by virtual and dma addresses and sizes, as well as by bpid. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Explicitly set carrier off at ifconfig up If we don't, netif_carrier_ok() will still return true even if the link state is marked as LINKWATCH_PENDING, which in a dpni-2-dpni case may last indefinitely long. This will cause "ifconfig up" followed by "ip link show" to report LOWER_UP when the peer DPNI is still down (and in fact before we've even received any link notification at all). Signed-off-by: Bogdan Hamciuc dpaa2-eth: Fix FQ type in stats print Fix a bug where the type of the Rx error queue was printed incorrectly in the debugfs statistics Signed-off-by: Ioana Radulescu dpaa2-eth: Don't build debugfs support as a separate module Instead have module init and exit functions declared explicitly for the Ethernet driver and initialize/destroy the debugfs directory there. Signed-off-by: Ioana Radulescu dpaa2-eth: Remove debugfs #ifdefs from dpaa2-eth.c Instead of conditionally compiling the calls to debugfs init functions in dpaa2-eth.c, define no-op stubs for these functions in case the debugfs Kconfig option is not enabled. This makes the code more readable. Signed-off-by: Ioana Radulescu Signed-off-by: Bogdan Hamciuc dpaa2-eth: Use napi_complete_done() Replace napi_complete() with napi_complete_done(). Together with setting /sys/class/net/ethX/gro_flush_timeout, this allows us to take better advantage of GRO coalescing and improves throughput and cpu load in TCP termination tests. Signed-off-by: Ioana Radulescu dpaa2-eth: Fix error path in probe NAPI delete was called at the wrong place when exiting probe function on an error path Signed-off-by: Ioana Radulescu dpaa2-eth: Allocate channels based on queue count Limit the number of channels allocated per DPNI to the maximum between the number of Rx queues per traffic class (distribution size) and Tx confirmation queues (number of tx flows). If this happens to be larger than the number of available cores, only allocate one channel for each core and distribute the frame queues on the cores/channels in a round robin fashion. Signed-off-by: Ioana Radulescu Signed-off-by: Bogdan Hamciuc dpaa2-eth: Use DPNI setting for number of Tx flows Instead of creating one Tx flow for each online cpu, use the DPNI attributes for deciding how many senders we have. Signed-off-by: Ioana Radulescu dpaa2-eth: Renounce sentinel in enum dpni_counter Bring back the Flib header dpni.h to its initial content by removing the sentinel value in enum dpni_counter. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Fix Rx queue count We were missing a roundup to the next power of 2 in order to be in sync with the MC implementation. Actually, moved that logic in a separate function which we'll remove once the MC API is updated. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Unmap the S/G table outside ldpaa_eth_free_rx_fd The Scatter-Gather table is already unmapped outside ldpaa_eth_free_rx_fd so no need to try to unmap it once more. Signed-off-by: Cristian Sovaiala dpaa2-eth: Use napi_schedule_irqoff() At the time we schedule NAPI, the Dequeue Available Notifications (which are the de facto triggers of NAPI processing) are already disabled. Signed-off-by: Ioana Radulescu Signed-off-by: Bogdan Hamciuc net: Fix ethernet Kconfig Re-add missing 'source' directive. This exists on the integration branch, but was mistakenly removed by an earlier dpaa2-eth rebase. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Manually update link state at ifup The DPMAC may have handled the link state notification before the DPNI is up. A new PHY state transision may not subsequently occur, so the DPNI must initiate a read of the DPMAC state. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Stop carrier upon ifdown Signed-off-by: Bogdan Hamciuc dpaa2-eth: Fix print messages in link state handling code Avoid an "(uninitialized)" message during DPNI probe by replacing netdev_info() with its corresponding dev_info(). Purge some related comments and add some netdev messages to assist link state debugging. Remove an excessively defensive assertion. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Do not allow ethtool settings change while the NI is up Due to a MC limitation, link state changes while the DPNI is enabled will fail. For now, we'll just prevent the call from going down to the MC if we know it will fail. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Reduce ethtool messages verbosity Transform a couple of netdev_info() calls into netdev_dbg(). Signed-off-by: Bogdan Hamciuc dpaa2-eth: Only unmask IRQs that we actually handle Signed-off-by: Bogdan Hamciuc dpaa2-eth: Produce fewer boot log messages No longer print one line for each all-zero hwaddr that was replaced with a random MAC address; just inform the user once that this has occurred. And reduce redundancy of some printouts in the bootlog. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Fix big endian issue We were not doing any endianness conversions on the scatter gather table entries, which caused problems on big endian kernels. For frame descriptors the QMan driver takes care of this transparently, but in the case of SG entries we need to do it ourselves. Signed-off-by: Ioana Radulescu dpaa2-eth: Force atomic context for lazy bpool seeding We use the same ldpaa_bp_add_7() function for initial buffer pool seeding (from .ndo_open) and for hotpath pool replenishing. The function is using napi_alloc_frag() as an optimization for the Rx datapath, but that turns out to require atomic execution because of a this_cpu_ptr() call down its stack. This patch temporarily disables preemption around the initial seeding of the Rx buffer pool. Signed-off-by: Bogdan Hamciuc dpaa-eth: Integrate Flib version 0.7.1.2 Although API-compatible with 0.7.1.1, there are some ABI changes that warrant a new integration. Signed-off-by: Bogdan Hamciuc dpaa2-eth: No longer adjust max_dist_per_tc The MC firmware until version 0.7.1.1/8.0.2 requires that max_dist_per_tc have the value expected by the hardware, which would be different from what the user expects. MC firmware 0.7.1.2/8.0.5 fixes that, so we remove our transparent conversion. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Enforce 256-byte Rx alignment Hardware erratum enforced by MC requires that Rx buffer lengths and addresses be 265-byte aligned. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Rename Tx buf alignment macro The existing "BUF_ALIGN" macro remained confined to Tx usage, after separate alignment was introduced for Rx. Renaming accordingly. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Fix hashing distribution size Commit be3fb62623e4338e60fb60019f134b6055cbc127 Author: Bogdan Hamciuc Date: Fri Oct 23 18:26:44 2015 +0300 dpaa2-eth: No longer adjust max_dist_per_tc missed one usage of the ldpaa_queue_count() function, making distribution size inadvertenly lower. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Remove ndo_select_queue Our implementation of ndo_select_queue would lead to questions regarding our support for qdiscs. Until we find an optimal way to select the txq without breaking future qdisc integration, just remove the ndo_select_queue callback entirely and leave the stack figure out the flow. This incurs a ~2-3% penalty on some performance tests. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Select TxConf FQ based on processor id Use smp_processor_id instead of skb queue mapping to determine the tx flow id and implicitly the confirmation queue. Signed-off-by: Bogdan Hamciuc dpaa2-eth: Reduce number of buffers in bpool Reduce the maximum number of buffers in each buffer pool associated with a DPNI. This in turn reduces the number of memory allocations performed in a single batch when buffers fall below a certain threshold. Provides a significant performance boost (~5-10% increase) on both termination and forwarding scenarios, while also reducing the driver memory footprint. Signed-off-by: Ioana Radulescu dpaa2-eth: Replace "ldpaa" with "dpaa2" Replace all instances of "ldpaa"/"LDPAA" in the Ethernet driver (names of functions, structures, macros, etc), with "dpaa2"/"DPAA2", except for DPIO API function calls. Signed-off-by: Ioana Radulescu dpaa2-eth: rename ldpaa to dpaa2 Signed-off-by: Haiying Wang (Stuart: this patch was split out from the origin global rename patch) Signed-off-by: Stuart Yoder dpaa2-eth: Rename dpaa_io_query_fq_count to dpaa2_io_query_fq_count Signed-off-by: Cristian Sovaiala fsl-dpio: rename dpaa_* structure to dpaa2_* Signed-off-by: Haiying Wang dpaa2-eth, dpni, fsl-mc: Updates for MC0.8.0 Several changes need to be performed in sync for supporting the newest MC version: * Update mc-cmd.h * Update the dpni binary interface to v6.0 * Update the DPAA2 Eth driver to account for several API changes Signed-off-by: Ioana Radulescu staging: fsl-dpaa2: ethernet: add support for hardware timestamping Signed-off-by: Yangbo Lu fsl-dpaa2: eth: Do not set bpid in egress fd We don't do FD recycling on egress, BPID is therefore not necessary. Signed-off-by: Bogdan Hamciuc fsl-dpaa2: eth: Amend buffer refill comment A change request has been pending for placing an upper bound to the buffer replenish logic on Rx. However, short of practical alternatives, resort to amending the relevant comment and rely on ksoftirqd to guarantee interactivity. Signed-off-by: Bogdan Hamciuc fsl-dpaa2: eth: Configure a taildrop threshold for each Rx frame queue. The selected value allows for Rx jumbo (10K) frames processing while at the same time helps balance the system in the case of IP forwarding. Also compute the number of buffers in the pool based on the TD threshold to avoid starving some of the ingress queues in small frames, high throughput scenarios. Signed-off-by: Ioana Radulescu fsl-dpaa2: eth: Check objects' FLIB version Make sure we support the DPNI, DPCON and DPBP version, otherwise abort probing early on and provide an error message. Signed-off-by: Ioana Radulescu fsl-dpaa2: eth: Remove likely/unlikely from cold paths Signed-off-by: Cristian Sovaiala Signed-off-by: Bogdan Hamciuc fsl-dpaa2: eth: Remove __cold attribute Signed-off-by: Cristian Sovaiala fsl-dpaa2: eth: Replace netdev_XXX with dev_XXX before register_netdevice() Signed-off-by: Cristian Sovaiala Signed-off-by: Bogdan Hamciuc fsl-dpaa2: eth: Fix coccinelle issue drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c:687:1-36: WARNING: Assignment of bool to 0/1 Signed-off-by: Cristian Sovaiala fsl-dpaa2: eth: Fix minor spelling issue Signed-off-by: Cristian Sovaiala fsl-dpaa2: eth: Add a couple of 'unlikely' on hot path Signed-off-by: Cristian Sovaiala Signed-off-by: Bogdan Hamciuc fsl-dpaa2: eth: Fix a bunch of minor issues found by static analysis tools As found by Klocworks and Checkpatch: - Unused variables - Integer type replacements - Unchecked memory allocations - Whitespace, alignment and newlining Signed-off-by: Cristian Sovaiala Signed-off-by: Bogdan Hamciuc fsl-dpaa2: eth: Remove "inline" keyword from static functions Signed-off-by: Cristian Sovaiala fsl-dpaa2: eth: Remove BUG/BUG_ONs Signed-off-by: Cristian Sovaiala Signed-off-by: Bogdan Hamciuc fsl-dpaa2: eth: Use NAPI_POLL_WEIGHT No need to define our own macro as long as we're using the default value of 64. Signed-off-by: Ioana Radulescu dpaa2-eth: Move dpaa2_eth_swa structure to header file It was the only structure defined inside dpaa2-eth.c Signed-off-by: Ioana Radulescu fsl-dpaa2: eth: Replace uintX_t with uX Signed-off-by: Ioana Radulescu Signed-off-by: Bogdan Hamciuc fsl-dpaa2: eth: Minor fixes & cosmetics - Make driver log level an int, because this is what netif_msg_init expects. - Remove driver description macro as it was used only once, immediately after being defined - Remove include comment Signed-off-by: Ioana Radulescu dpaa2-eth: Move bcast address setup to dpaa2_eth_netdev_init It seems to fit better there than directly in probe. Signed-off-by: Ioana Radulescu dpaa2-eth: Fix DMA mapping bug During hashing/flow steering configuration via ethtool, we were doing a DMA unmap from the wrong address. Fix the issue by using the DMA address that was initially mapped. Signed-off-by: Ioana Radulescu dpaa2-eth: Associate buffer counting to queues instead of cpu Move the buffer counters from being percpu variables to being associated with QMan channels. This is more natural as we need to dimension the buffer pool count based on distribution size rather than number of online cores. Signed-off-by: Ioana Radulescu fsl-dpaa2: eth: Provide driver and fw version to ethtool Read fw version from the MC and interpret DPNI FLib major.minor as the driver's version. Report these in 'ethool -i'. Signed-off-by: Bogdan Hamciuc fsl-dpaa2: eth: Remove dependency on GCOV_KERNEL Signed-off-by: Cristian Sovaiala fsl-dpaa2: eth: Remove FIXME/TODO comments from the code Some of the concerns had already been addressed, a couple are being fixed in place. Left a few TODOs related to the flow-steering code, which needs to be revisited before upstreaming anyway. Signed-off-by: Ioana Radulescu fsl-dpaa2: eth: Remove forward declarations Instead move the functions such that they are defined prior to being used. Signed-off-by: Ioana Radulescu fsl-dpaa2: eth: Remove dead code in IRQ handler If any of those conditions were met, it is unlikely we'd ever be there in the first place. Signed-off-by: Bogdan Hamciuc fsl-dpaa2: eth: Remove dpaa2_dpbp_drain() Its sole caller was __dpaa2_dpbp_free(), so move its content and get rid of one function call. Signed-off-by: Bogdan Hamciuc fsl-dpaa2: eth: Remove duplicate define We somehow ended up with two defines for the maximum number of tx queues. Signed-off-by: Ioana Radulescu fsl-dpaa2: eth: Move header comment to .c file Signed-off-by: Bogdan Hamciuc fsl-dpaa2: eth: Make DPCON allocation failure produce a benign message Number of DPCONs may be smaller than the number of CPUs in a number of valid scenarios. One such scenario is when the DPNI's distribution width is smaller than the number of cores and we just don't want to over-allocate DPCONs. Make the DPCON allocation failure less menacing by changing the logged message. While at it, remove a unused parameter in function prototype. Signed-off-by: Bogdan Hamciuc dpaa2 eth: irq update Signed-off-by: Stuart Yoder Conflicts: drivers/staging/Kconfig drivers/staging/Makefile --- MAINTAINERS | 15 + drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/fsl-dpaa2/Kconfig | 11 + drivers/staging/fsl-dpaa2/Makefile | 5 + drivers/staging/fsl-dpaa2/ethernet/Kconfig | 42 + drivers/staging/fsl-dpaa2/ethernet/Makefile | 21 + .../staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.c | 319 +++ .../staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.h | 61 + .../staging/fsl-dpaa2/ethernet/dpaa2-eth-trace.h | 185 ++ drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c | 2793 ++++++++++++++++++++ drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h | 366 +++ drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c | 882 +++++++ drivers/staging/fsl-dpaa2/ethernet/dpkg.h | 175 ++ drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h | 1058 ++++++++ drivers/staging/fsl-dpaa2/ethernet/dpni.c | 1907 +++++++++++++ drivers/staging/fsl-dpaa2/ethernet/dpni.h | 2581 ++++++++++++++++++ drivers/staging/fsl-mc/include/mc-cmd.h | 5 +- drivers/staging/fsl-mc/include/net.h | 481 ++++ net/core/pktgen.c | 1 + 20 files changed, 10910 insertions(+), 1 deletion(-) create mode 100644 drivers/staging/fsl-dpaa2/Kconfig create mode 100644 drivers/staging/fsl-dpaa2/Makefile create mode 100644 drivers/staging/fsl-dpaa2/ethernet/Kconfig create mode 100644 drivers/staging/fsl-dpaa2/ethernet/Makefile create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.c create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.h create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-trace.h create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpkg.h create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpni.c create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpni.h create mode 100644 drivers/staging/fsl-mc/include/net.h --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4539,6 +4539,21 @@ L: linux-kernel@vger.kernel.org S: Maintained F: drivers/staging/fsl-mc/ +FREESCALE DPAA2 ETH DRIVER +M: Ioana Radulescu +M: Bogdan Hamciuc +M: Cristian Sovaiala +L: linux-kernel@vger.kernel.org +S: Maintained +F: drivers/staging/fsl-dpaa2/ethernet/ + +FREESCALE QORIQ MANAGEMENT COMPLEX RESTOOL DRIVER +M: Lijun Pan +L: linux-kernel@vger.kernel.org +S: Maintained +F: drivers/staging/fsl-mc/bus/mc-ioctl.h +F: drivers/staging/fsl-mc/bus/mc-restool.c + FREEVXFS FILESYSTEM M: Christoph Hellwig W: ftp://ftp.openlinux.org/pub/people/hch/vxfs --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -114,4 +114,6 @@ source "drivers/staging/most/Kconfig" source "drivers/staging/fsl_ppfe/Kconfig" +source "drivers/staging/fsl-dpaa2/Kconfig" + endif # STAGING --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -49,3 +49,4 @@ obj-$(CONFIG_FSL_DPA) += fsl_q obj-$(CONFIG_WILC1000) += wilc1000/ obj-$(CONFIG_MOST) += most/ obj-$(CONFIG_FSL_PPFE) += fsl_ppfe/ +obj-$(CONFIG_FSL_DPAA2) += fsl-dpaa2/ --- /dev/null +++ b/drivers/staging/fsl-dpaa2/Kconfig @@ -0,0 +1,11 @@ +# +# Freescale device configuration +# + +config FSL_DPAA2 + bool "Freescale DPAA2 devices" + depends on FSL_MC_BUS + ---help--- + Build drivers for Freescale DataPath Acceleration Architecture (DPAA2) family of SoCs. +# TODO move DPIO driver in-here? +source "drivers/staging/fsl-dpaa2/ethernet/Kconfig" --- /dev/null +++ b/drivers/staging/fsl-dpaa2/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Freescale network device drivers. +# + +obj-$(CONFIG_FSL_DPAA2_ETH) += ethernet/ --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethernet/Kconfig @@ -0,0 +1,42 @@ +# +# Freescale DPAA Ethernet driver configuration +# +# Copyright (C) 2014-2015 Freescale Semiconductor, Inc. +# +# This file is released under the GPLv2 +# + +menuconfig FSL_DPAA2_ETH + tristate "Freescale DPAA2 Ethernet" + depends on FSL_DPAA2 && FSL_MC_BUS && FSL_MC_DPIO + select FSL_DPAA2_MAC + default y + ---help--- + Freescale Data Path Acceleration Architecture Ethernet + driver, using the Freescale MC bus driver. + +if FSL_DPAA2_ETH +config FSL_DPAA2_ETH_LINK_POLL + bool "Use polling mode for link state" + default n + ---help--- + Poll for detecting link state changes instead of using + interrupts. + +config FSL_DPAA2_ETH_USE_ERR_QUEUE + bool "Enable Rx error queue" + default n + ---help--- + Allow Rx error frames to be enqueued on an error queue + and processed by the driver (by default they are dropped + in hardware). + This may impact performance, recommended for debugging + purposes only. + +config FSL_DPAA2_ETH_DEBUGFS + depends on DEBUG_FS && FSL_QBMAN_DEBUG + bool "Enable debugfs support" + default n + ---help--- + Enable advanced statistics through debugfs interface. +endif --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethernet/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the Freescale DPAA Ethernet controllers +# +# Copyright (C) 2014-2015 Freescale Semiconductor, Inc. +# +# This file is released under the GPLv2 +# + +ccflags-y += -DVERSION=\"\" + +obj-$(CONFIG_FSL_DPAA2_ETH) += fsl-dpaa2-eth.o + +fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o +fsl-dpaa2-eth-${CONFIG_FSL_DPAA2_ETH_DEBUGFS} += dpaa2-eth-debugfs.o + +#Needed by the tracing framework +CFLAGS_dpaa2-eth.o := -I$(src) + +ifeq ($(CONFIG_FSL_DPAA2_ETH_GCOV),y) + GCOV_PROFILE := y +endif --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.c @@ -0,0 +1,319 @@ + +/* Copyright 2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include +#include "dpaa2-eth.h" +#include "dpaa2-eth-debugfs.h" + +#define DPAA2_ETH_DBG_ROOT "dpaa2-eth" + + +static struct dentry *dpaa2_dbg_root; + +static int dpaa2_dbg_cpu_show(struct seq_file *file, void *offset) +{ + struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)file->private; + struct rtnl_link_stats64 *stats; + struct dpaa2_eth_stats *extras; + int i; + + seq_printf(file, "Per-CPU stats for %s\n", priv->net_dev->name); + seq_printf(file, "%s%16s%16s%16s%16s%16s%16s%16s%16s\n", + "CPU", "Rx", "Rx Err", "Rx SG", "Tx", "Tx Err", "Tx conf", + "Tx SG", "Enq busy"); + + for_each_online_cpu(i) { + stats = per_cpu_ptr(priv->percpu_stats, i); + extras = per_cpu_ptr(priv->percpu_extras, i); + seq_printf(file, "%3d%16llu%16llu%16llu%16llu%16llu%16llu%16llu%16llu\n", + i, + stats->rx_packets, + stats->rx_errors, + extras->rx_sg_frames, + stats->tx_packets, + stats->tx_errors, + extras->tx_conf_frames, + extras->tx_sg_frames, + extras->tx_portal_busy); + } + + return 0; +} + +static int dpaa2_dbg_cpu_open(struct inode *inode, struct file *file) +{ + int err; + struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)inode->i_private; + + err = single_open(file, dpaa2_dbg_cpu_show, priv); + if (err < 0) + netdev_err(priv->net_dev, "single_open() failed\n"); + + return err; +} + +static const struct file_operations dpaa2_dbg_cpu_ops = { + .open = dpaa2_dbg_cpu_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static char *fq_type_to_str(struct dpaa2_eth_fq *fq) +{ + switch (fq->type) { + case DPAA2_RX_FQ: + return "Rx"; + case DPAA2_TX_CONF_FQ: + return "Tx conf"; + case DPAA2_RX_ERR_FQ: + return "Rx err"; + default: + return "N/A"; + } +} + +static int dpaa2_dbg_fqs_show(struct seq_file *file, void *offset) +{ + struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)file->private; + struct dpaa2_eth_fq *fq; + u32 fcnt, bcnt; + int i, err; + + seq_printf(file, "FQ stats for %s:\n", priv->net_dev->name); + seq_printf(file, "%s%16s%16s%16s%16s\n", + "VFQID", "CPU", "Type", "Frames", "Pending frames"); + + for (i = 0; i < priv->num_fqs; i++) { + fq = &priv->fq[i]; + err = dpaa2_io_query_fq_count(NULL, fq->fqid, &fcnt, &bcnt); + if (err) + fcnt = 0; + + seq_printf(file, "%5d%16d%16s%16llu%16u\n", + fq->fqid, + fq->target_cpu, + fq_type_to_str(fq), + fq->stats.frames, + fcnt); + } + + return 0; +} + +static int dpaa2_dbg_fqs_open(struct inode *inode, struct file *file) +{ + int err; + struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)inode->i_private; + + err = single_open(file, dpaa2_dbg_fqs_show, priv); + if (err < 0) + netdev_err(priv->net_dev, "single_open() failed\n"); + + return err; +} + +static const struct file_operations dpaa2_dbg_fq_ops = { + .open = dpaa2_dbg_fqs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int dpaa2_dbg_ch_show(struct seq_file *file, void *offset) +{ + struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)file->private; + struct dpaa2_eth_channel *ch; + int i; + + seq_printf(file, "Channel stats for %s:\n", priv->net_dev->name); + seq_printf(file, "%s%16s%16s%16s%16s%16s\n", + "CHID", "CPU", "Deq busy", "Frames", "CDANs", + "Avg frm/CDAN"); + + for (i = 0; i < priv->num_channels; i++) { + ch = priv->channel[i]; + seq_printf(file, "%4d%16d%16llu%16llu%16llu%16llu\n", + ch->ch_id, + ch->nctx.desired_cpu, + ch->stats.dequeue_portal_busy, + ch->stats.frames, + ch->stats.cdan, + ch->stats.frames / ch->stats.cdan); + } + + return 0; +} + +static int dpaa2_dbg_ch_open(struct inode *inode, struct file *file) +{ + int err; + struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)inode->i_private; + + err = single_open(file, dpaa2_dbg_ch_show, priv); + if (err < 0) + netdev_err(priv->net_dev, "single_open() failed\n"); + + return err; +} + +static const struct file_operations dpaa2_dbg_ch_ops = { + .open = dpaa2_dbg_ch_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static ssize_t dpaa2_dbg_reset_write(struct file *file, const char __user *buf, + size_t count, loff_t *offset) +{ + struct dpaa2_eth_priv *priv = file->private_data; + struct rtnl_link_stats64 *percpu_stats; + struct dpaa2_eth_stats *percpu_extras; + struct dpaa2_eth_fq *fq; + struct dpaa2_eth_channel *ch; + int i; + + for_each_online_cpu(i) { + percpu_stats = per_cpu_ptr(priv->percpu_stats, i); + memset(percpu_stats, 0, sizeof(*percpu_stats)); + + percpu_extras = per_cpu_ptr(priv->percpu_extras, i); + memset(percpu_extras, 0, sizeof(*percpu_extras)); + } + + for (i = 0; i < priv->num_fqs; i++) { + fq = &priv->fq[i]; + memset(&fq->stats, 0, sizeof(fq->stats)); + } + + for_each_cpu(i, &priv->dpio_cpumask) { + ch = priv->channel[i]; + memset(&ch->stats, 0, sizeof(ch->stats)); + } + + return count; +} + +static const struct file_operations dpaa2_dbg_reset_ops = { + .open = simple_open, + .write = dpaa2_dbg_reset_write, +}; + +void dpaa2_dbg_add(struct dpaa2_eth_priv *priv) +{ + if (!dpaa2_dbg_root) + return; + + /* Create a directory for the interface */ + priv->dbg.dir = debugfs_create_dir(priv->net_dev->name, + dpaa2_dbg_root); + if (!priv->dbg.dir) { + netdev_err(priv->net_dev, "debugfs_create_dir() failed\n"); + return; + } + + /* per-cpu stats file */ + priv->dbg.cpu_stats = debugfs_create_file("cpu_stats", S_IRUGO, + priv->dbg.dir, priv, + &dpaa2_dbg_cpu_ops); + if (!priv->dbg.cpu_stats) { + netdev_err(priv->net_dev, "debugfs_create_file() failed\n"); + goto err_cpu_stats; + } + + /* per-fq stats file */ + priv->dbg.fq_stats = debugfs_create_file("fq_stats", S_IRUGO, + priv->dbg.dir, priv, + &dpaa2_dbg_fq_ops); + if (!priv->dbg.fq_stats) { + netdev_err(priv->net_dev, "debugfs_create_file() failed\n"); + goto err_fq_stats; + } + + /* per-fq stats file */ + priv->dbg.ch_stats = debugfs_create_file("ch_stats", S_IRUGO, + priv->dbg.dir, priv, + &dpaa2_dbg_ch_ops); + if (!priv->dbg.fq_stats) { + netdev_err(priv->net_dev, "debugfs_create_file() failed\n"); + goto err_ch_stats; + } + + /* reset stats */ + priv->dbg.reset_stats = debugfs_create_file("reset_stats", S_IWUSR, + priv->dbg.dir, priv, + &dpaa2_dbg_reset_ops); + if (!priv->dbg.reset_stats) { + netdev_err(priv->net_dev, "debugfs_create_file() failed\n"); + goto err_reset_stats; + } + + return; + +err_reset_stats: + debugfs_remove(priv->dbg.ch_stats); +err_ch_stats: + debugfs_remove(priv->dbg.fq_stats); +err_fq_stats: + debugfs_remove(priv->dbg.cpu_stats); +err_cpu_stats: + debugfs_remove(priv->dbg.dir); +} + +void dpaa2_dbg_remove(struct dpaa2_eth_priv *priv) +{ + debugfs_remove(priv->dbg.reset_stats); + debugfs_remove(priv->dbg.fq_stats); + debugfs_remove(priv->dbg.ch_stats); + debugfs_remove(priv->dbg.cpu_stats); + debugfs_remove(priv->dbg.dir); +} + +void dpaa2_eth_dbg_init(void) +{ + dpaa2_dbg_root = debugfs_create_dir(DPAA2_ETH_DBG_ROOT, NULL); + if (!dpaa2_dbg_root) { + pr_err("DPAA2-ETH: debugfs create failed\n"); + return; + } + + pr_info("DPAA2-ETH: debugfs created\n"); +} + +void __exit dpaa2_eth_dbg_exit(void) +{ + debugfs_remove(dpaa2_dbg_root); +} + --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.h @@ -0,0 +1,61 @@ +/* Copyright 2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DPAA2_ETH_DEBUGFS_H +#define DPAA2_ETH_DEBUGFS_H + +#include +#include "dpaa2-eth.h" + +extern struct dpaa2_eth_priv *priv; + +struct dpaa2_debugfs { + struct dentry *dir; + struct dentry *fq_stats; + struct dentry *ch_stats; + struct dentry *cpu_stats; + struct dentry *reset_stats; +}; + +#ifdef CONFIG_FSL_DPAA2_ETH_DEBUGFS +void dpaa2_eth_dbg_init(void); +void dpaa2_eth_dbg_exit(void); +void dpaa2_dbg_add(struct dpaa2_eth_priv *priv); +void dpaa2_dbg_remove(struct dpaa2_eth_priv *priv); +#else +static inline void dpaa2_eth_dbg_init(void) {} +static inline void dpaa2_eth_dbg_exit(void) {} +static inline void dpaa2_dbg_add(struct dpaa2_eth_priv *priv) {} +static inline void dpaa2_dbg_remove(struct dpaa2_eth_priv *priv) {} +#endif /* CONFIG_FSL_DPAA2_ETH_DEBUGFS */ + +#endif /* DPAA2_ETH_DEBUGFS_H */ + --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-trace.h @@ -0,0 +1,185 @@ +/* Copyright 2014-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM dpaa2_eth + +#if !defined(_DPAA2_ETH_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _DPAA2_ETH_TRACE_H + +#include +#include +#include "dpaa2-eth.h" +#include + +#define TR_FMT "[%s] fd: addr=0x%llx, len=%u, off=%u" +/* trace_printk format for raw buffer event class */ +#define TR_BUF_FMT "[%s] vaddr=%p size=%zu dma_addr=%pad map_size=%zu bpid=%d" + +/* This is used to declare a class of events. + * individual events of this type will be defined below. + */ + +/* Store details about a frame descriptor */ +DECLARE_EVENT_CLASS(dpaa2_eth_fd, + /* Trace function prototype */ + TP_PROTO(struct net_device *netdev, + const struct dpaa2_fd *fd), + + /* Repeat argument list here */ + TP_ARGS(netdev, fd), + + /* A structure containing the relevant information we want + * to record. Declare name and type for each normal element, + * name, type and size for arrays. Use __string for variable + * length strings. + */ + TP_STRUCT__entry( + __field(u64, fd_addr) + __field(u32, fd_len) + __field(u16, fd_offset) + __string(name, netdev->name) + ), + + /* The function that assigns values to the above declared + * fields + */ + TP_fast_assign( + __entry->fd_addr = dpaa2_fd_get_addr(fd); + __entry->fd_len = dpaa2_fd_get_len(fd); + __entry->fd_offset = dpaa2_fd_get_offset(fd); + __assign_str(name, netdev->name); + ), + + /* This is what gets printed when the trace event is + * triggered. + */ + TP_printk(TR_FMT, + __get_str(name), + __entry->fd_addr, + __entry->fd_len, + __entry->fd_offset) +); + +/* Now declare events of the above type. Format is: + * DEFINE_EVENT(class, name, proto, args), with proto and args same as for class + */ + +/* Tx (egress) fd */ +DEFINE_EVENT(dpaa2_eth_fd, dpaa2_tx_fd, + TP_PROTO(struct net_device *netdev, + const struct dpaa2_fd *fd), + + TP_ARGS(netdev, fd) +); + +/* Rx fd */ +DEFINE_EVENT(dpaa2_eth_fd, dpaa2_rx_fd, + TP_PROTO(struct net_device *netdev, + const struct dpaa2_fd *fd), + + TP_ARGS(netdev, fd) +); + +/* Tx confirmation fd */ +DEFINE_EVENT(dpaa2_eth_fd, dpaa2_tx_conf_fd, + TP_PROTO(struct net_device *netdev, + const struct dpaa2_fd *fd), + + TP_ARGS(netdev, fd) +); + +/* Log data about raw buffers. Useful for tracing DPBP content. */ +TRACE_EVENT(dpaa2_eth_buf_seed, + /* Trace function prototype */ + TP_PROTO(struct net_device *netdev, + /* virtual address and size */ + void *vaddr, + size_t size, + /* dma map address and size */ + dma_addr_t dma_addr, + size_t map_size, + /* buffer pool id, if relevant */ + u16 bpid), + + /* Repeat argument list here */ + TP_ARGS(netdev, vaddr, size, dma_addr, map_size, bpid), + + /* A structure containing the relevant information we want + * to record. Declare name and type for each normal element, + * name, type and size for arrays. Use __string for variable + * length strings. + */ + TP_STRUCT__entry( + __field(void *, vaddr) + __field(size_t, size) + __field(dma_addr_t, dma_addr) + __field(size_t, map_size) + __field(u16, bpid) + __string(name, netdev->name) + ), + + /* The function that assigns values to the above declared + * fields + */ + TP_fast_assign( + __entry->vaddr = vaddr; + __entry->size = size; + __entry->dma_addr = dma_addr; + __entry->map_size = map_size; + __entry->bpid = bpid; + __assign_str(name, netdev->name); + ), + + /* This is what gets printed when the trace event is + * triggered. + */ + TP_printk(TR_BUF_FMT, + __get_str(name), + __entry->vaddr, + __entry->size, + &__entry->dma_addr, + __entry->map_size, + __entry->bpid) +); + +/* If only one event of a certain type needs to be declared, use TRACE_EVENT(). + * The syntax is the same as for DECLARE_EVENT_CLASS(). + */ + +#endif /* _DPAA2_ETH_TRACE_H */ + +/* This must be outside ifdef _DPAA2_ETH_TRACE_H */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE dpaa2-eth-trace +#include --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c @@ -0,0 +1,2793 @@ +/* Copyright 2014-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../fsl-mc/include/mc.h" +#include "../../fsl-mc/include/mc-sys.h" +#include "dpaa2-eth.h" + +/* CREATE_TRACE_POINTS only needs to be defined once. Other dpa files + * using trace events only need to #include + */ +#define CREATE_TRACE_POINTS +#include "dpaa2-eth-trace.h" + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Freescale Semiconductor, Inc"); +MODULE_DESCRIPTION("Freescale DPAA2 Ethernet Driver"); + +static int debug = -1; +module_param(debug, int, S_IRUGO); +MODULE_PARM_DESC(debug, "Module/Driver verbosity level"); + +/* Oldest DPAA2 objects version we are compatible with */ +#define DPAA2_SUPPORTED_DPNI_VERSION 6 +#define DPAA2_SUPPORTED_DPBP_VERSION 2 +#define DPAA2_SUPPORTED_DPCON_VERSION 2 + +/* Iterate through the cpumask in a round-robin fashion. */ +#define cpumask_rr(cpu, maskptr) \ +do { \ + (cpu) = cpumask_next((cpu), (maskptr)); \ + if ((cpu) >= nr_cpu_ids) \ + (cpu) = cpumask_first((maskptr)); \ +} while (0) + +static void dpaa2_eth_rx_csum(struct dpaa2_eth_priv *priv, + u32 fd_status, + struct sk_buff *skb) +{ + skb_checksum_none_assert(skb); + + /* HW checksum validation is disabled, nothing to do here */ + if (!(priv->net_dev->features & NETIF_F_RXCSUM)) + return; + + /* Read checksum validation bits */ + if (!((fd_status & DPAA2_ETH_FAS_L3CV) && + (fd_status & DPAA2_ETH_FAS_L4CV))) + return; + + /* Inform the stack there's no need to compute L3/L4 csum anymore */ + skb->ip_summed = CHECKSUM_UNNECESSARY; +} + +/* Free a received FD. + * Not to be used for Tx conf FDs or on any other paths. + */ +static void dpaa2_eth_free_rx_fd(struct dpaa2_eth_priv *priv, + const struct dpaa2_fd *fd, + void *vaddr) +{ + struct device *dev = priv->net_dev->dev.parent; + dma_addr_t addr = dpaa2_fd_get_addr(fd); + u8 fd_format = dpaa2_fd_get_format(fd); + + if (fd_format == dpaa2_fd_sg) { + struct dpaa2_sg_entry *sgt = vaddr + dpaa2_fd_get_offset(fd); + void *sg_vaddr; + int i; + + for (i = 0; i < DPAA2_ETH_MAX_SG_ENTRIES; i++) { + dpaa2_sg_le_to_cpu(&sgt[i]); + + addr = dpaa2_sg_get_addr(&sgt[i]); + dma_unmap_single(dev, addr, DPAA2_ETH_RX_BUFFER_SIZE, + DMA_FROM_DEVICE); + + sg_vaddr = phys_to_virt(addr); + put_page(virt_to_head_page(sg_vaddr)); + + if (dpaa2_sg_is_final(&sgt[i])) + break; + } + } + + put_page(virt_to_head_page(vaddr)); +} + +/* Build a linear skb based on a single-buffer frame descriptor */ +static struct sk_buff *dpaa2_eth_build_linear_skb(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, + void *fd_vaddr) +{ + struct sk_buff *skb = NULL; + u16 fd_offset = dpaa2_fd_get_offset(fd); + u32 fd_length = dpaa2_fd_get_len(fd); + + skb = build_skb(fd_vaddr, DPAA2_ETH_RX_BUFFER_SIZE + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); + if (unlikely(!skb)) { + netdev_err(priv->net_dev, "build_skb() failed\n"); + return NULL; + } + + skb_reserve(skb, fd_offset); + skb_put(skb, fd_length); + + ch->buf_count--; + + return skb; +} + +/* Build a non linear (fragmented) skb based on a S/G table */ +static struct sk_buff *dpaa2_eth_build_frag_skb(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + struct dpaa2_sg_entry *sgt) +{ + struct sk_buff *skb = NULL; + struct device *dev = priv->net_dev->dev.parent; + void *sg_vaddr; + dma_addr_t sg_addr; + u16 sg_offset; + u32 sg_length; + struct page *page, *head_page; + int page_offset; + int i; + + for (i = 0; i < DPAA2_ETH_MAX_SG_ENTRIES; i++) { + struct dpaa2_sg_entry *sge = &sgt[i]; + + dpaa2_sg_le_to_cpu(sge); + + /* We don't support anything else yet! */ + if (unlikely(dpaa2_sg_get_format(sge) != dpaa2_sg_single)) { + dev_warn_once(dev, "Unsupported S/G entry format: %d\n", + dpaa2_sg_get_format(sge)); + return NULL; + } + + /* Get the address, offset and length from the S/G entry */ + sg_addr = dpaa2_sg_get_addr(sge); + dma_unmap_single(dev, sg_addr, DPAA2_ETH_RX_BUFFER_SIZE, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(dev, sg_addr))) { + netdev_err(priv->net_dev, "DMA unmap failed\n"); + return NULL; + } + sg_vaddr = phys_to_virt(sg_addr); + sg_length = dpaa2_sg_get_len(sge); + + if (i == 0) { + /* We build the skb around the first data buffer */ + skb = build_skb(sg_vaddr, DPAA2_ETH_RX_BUFFER_SIZE + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); + if (unlikely(!skb)) { + netdev_err(priv->net_dev, "build_skb failed\n"); + return NULL; + } + sg_offset = dpaa2_sg_get_offset(sge); + skb_reserve(skb, sg_offset); + skb_put(skb, sg_length); + } else { + /* Subsequent data in SGEntries are stored at + * offset 0 in their buffers, we don't need to + * compute sg_offset. + */ + WARN_ONCE(dpaa2_sg_get_offset(sge) != 0, + "Non-zero offset in SGE[%d]!\n", i); + + /* Rest of the data buffers are stored as skb frags */ + page = virt_to_page(sg_vaddr); + head_page = virt_to_head_page(sg_vaddr); + + /* Offset in page (which may be compound) */ + page_offset = ((unsigned long)sg_vaddr & + (PAGE_SIZE - 1)) + + (page_address(page) - page_address(head_page)); + + skb_add_rx_frag(skb, i - 1, head_page, page_offset, + sg_length, DPAA2_ETH_RX_BUFFER_SIZE); + } + + if (dpaa2_sg_is_final(sge)) + break; + } + + /* Count all data buffers + sgt buffer */ + ch->buf_count -= i + 2; + + return skb; +} + +static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, + struct napi_struct *napi) +{ + dma_addr_t addr = dpaa2_fd_get_addr(fd); + u8 fd_format = dpaa2_fd_get_format(fd); + void *vaddr; + struct sk_buff *skb; + struct rtnl_link_stats64 *percpu_stats; + struct dpaa2_eth_stats *percpu_extras; + struct device *dev = priv->net_dev->dev.parent; + struct dpaa2_fas *fas; + u32 status = 0; + + /* Tracing point */ + trace_dpaa2_rx_fd(priv->net_dev, fd); + + dma_unmap_single(dev, addr, DPAA2_ETH_RX_BUFFER_SIZE, DMA_FROM_DEVICE); + vaddr = phys_to_virt(addr); + + prefetch(vaddr + priv->buf_layout.private_data_size); + prefetch(vaddr + dpaa2_fd_get_offset(fd)); + + percpu_stats = this_cpu_ptr(priv->percpu_stats); + percpu_extras = this_cpu_ptr(priv->percpu_extras); + + if (fd_format == dpaa2_fd_single) { + skb = dpaa2_eth_build_linear_skb(priv, ch, fd, vaddr); + } else if (fd_format == dpaa2_fd_sg) { + struct dpaa2_sg_entry *sgt = + vaddr + dpaa2_fd_get_offset(fd); + skb = dpaa2_eth_build_frag_skb(priv, ch, sgt); + put_page(virt_to_head_page(vaddr)); + percpu_extras->rx_sg_frames++; + percpu_extras->rx_sg_bytes += dpaa2_fd_get_len(fd); + } else { + /* We don't support any other format */ + netdev_err(priv->net_dev, "Received invalid frame format\n"); + goto err_frame_format; + } + + if (unlikely(!skb)) { + dev_err_once(dev, "error building skb\n"); + goto err_build_skb; + } + + prefetch(skb->data); + + if (priv->ts_rx_en) { + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); + u64 *ns = (u64 *) (vaddr + + priv->buf_layout.private_data_size + + sizeof(struct dpaa2_fas)); + + *ns = DPAA2_PTP_NOMINAL_FREQ_PERIOD_NS * (*ns); + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + shhwtstamps->hwtstamp = ns_to_ktime(*ns); + } + + /* Check if we need to validate the L4 csum */ + if (likely(fd->simple.frc & DPAA2_FD_FRC_FASV)) { + fas = (struct dpaa2_fas *) + (vaddr + priv->buf_layout.private_data_size); + status = le32_to_cpu(fas->status); + dpaa2_eth_rx_csum(priv, status, skb); + } + + skb->protocol = eth_type_trans(skb, priv->net_dev); + + percpu_stats->rx_packets++; + percpu_stats->rx_bytes += skb->len; + + if (priv->net_dev->features & NETIF_F_GRO) + napi_gro_receive(napi, skb); + else + netif_receive_skb(skb); + + return; +err_frame_format: +err_build_skb: + dpaa2_eth_free_rx_fd(priv, fd, vaddr); + percpu_stats->rx_dropped++; +} + +#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE +static void dpaa2_eth_rx_err(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, + struct napi_struct *napi __always_unused) +{ + struct device *dev = priv->net_dev->dev.parent; + dma_addr_t addr = dpaa2_fd_get_addr(fd); + void *vaddr; + struct rtnl_link_stats64 *percpu_stats; + struct dpaa2_fas *fas; + u32 status = 0; + + dma_unmap_single(dev, addr, DPAA2_ETH_RX_BUFFER_SIZE, DMA_FROM_DEVICE); + vaddr = phys_to_virt(addr); + + if (fd->simple.frc & DPAA2_FD_FRC_FASV) { + fas = (struct dpaa2_fas *) + (vaddr + priv->buf_layout.private_data_size); + status = le32_to_cpu(fas->status); + + /* All frames received on this queue should have at least + * one of the Rx error bits set */ + WARN_ON_ONCE((status & DPAA2_ETH_RX_ERR_MASK) == 0); + netdev_dbg(priv->net_dev, "Rx frame error: 0x%08x\n", + status & DPAA2_ETH_RX_ERR_MASK); + } + dpaa2_eth_free_rx_fd(priv, fd, vaddr); + + percpu_stats = this_cpu_ptr(priv->percpu_stats); + percpu_stats->rx_errors++; +} +#endif + +/* Consume all frames pull-dequeued into the store. This is the simplest way to + * make sure we don't accidentally issue another volatile dequeue which would + * overwrite (leak) frames already in the store. + * + * Observance of NAPI budget is not our concern, leaving that to the caller. + */ +static int dpaa2_eth_store_consume(struct dpaa2_eth_channel *ch) +{ + struct dpaa2_eth_priv *priv = ch->priv; + struct dpaa2_eth_fq *fq; + struct dpaa2_dq *dq; + const struct dpaa2_fd *fd; + int cleaned = 0; + int is_last; + + do { + dq = dpaa2_io_store_next(ch->store, &is_last); + if (unlikely(!dq)) { + if (unlikely(!is_last)) { + netdev_dbg(priv->net_dev, + "Channel %d reqturned no valid frames\n", + ch->ch_id); + /* MUST retry until we get some sort of + * valid response token (be it "empty dequeue" + * or a valid frame). + */ + continue; + } + break; + } + + /* Obtain FD and process it */ + fd = dpaa2_dq_fd(dq); + fq = (struct dpaa2_eth_fq *)dpaa2_dq_fqd_ctx(dq); + fq->stats.frames++; + + fq->consume(priv, ch, fd, &ch->napi); + cleaned++; + } while (!is_last); + + return cleaned; +} + +static int dpaa2_eth_build_sg_fd(struct dpaa2_eth_priv *priv, + struct sk_buff *skb, + struct dpaa2_fd *fd) +{ + struct device *dev = priv->net_dev->dev.parent; + void *sgt_buf = NULL; + dma_addr_t addr; + int nr_frags = skb_shinfo(skb)->nr_frags; + struct dpaa2_sg_entry *sgt; + int i, j, err; + int sgt_buf_size; + struct scatterlist *scl, *crt_scl; + int num_sg; + int num_dma_bufs; + struct dpaa2_eth_swa *bps; + + /* Create and map scatterlist. + * We don't advertise NETIF_F_FRAGLIST, so skb_to_sgvec() will not have + * to go beyond nr_frags+1. + * Note: We don't support chained scatterlists + */ + WARN_ON(PAGE_SIZE / sizeof(struct scatterlist) < nr_frags + 1); + scl = kcalloc(nr_frags + 1, sizeof(struct scatterlist), GFP_ATOMIC); + if (unlikely(!scl)) + return -ENOMEM; + + sg_init_table(scl, nr_frags + 1); + num_sg = skb_to_sgvec(skb, scl, 0, skb->len); + num_dma_bufs = dma_map_sg(dev, scl, num_sg, DMA_TO_DEVICE); + if (unlikely(!num_dma_bufs)) { + netdev_err(priv->net_dev, "dma_map_sg() error\n"); + err = -ENOMEM; + goto dma_map_sg_failed; + } + + /* Prepare the HW SGT structure */ + sgt_buf_size = priv->tx_data_offset + + sizeof(struct dpaa2_sg_entry) * (1 + num_dma_bufs); + sgt_buf = kzalloc(sgt_buf_size + DPAA2_ETH_TX_BUF_ALIGN, GFP_ATOMIC); + if (unlikely(!sgt_buf)) { + netdev_err(priv->net_dev, "failed to allocate SGT buffer\n"); + err = -ENOMEM; + goto sgt_buf_alloc_failed; + } + sgt_buf = PTR_ALIGN(sgt_buf, DPAA2_ETH_TX_BUF_ALIGN); + + /* PTA from egress side is passed as is to the confirmation side so + * we need to clear some fields here in order to find consistent values + * on TX confirmation. We are clearing FAS (Frame Annotation Status) + * field here. + */ + memset(sgt_buf + priv->buf_layout.private_data_size, 0, 8); + + sgt = (struct dpaa2_sg_entry *)(sgt_buf + priv->tx_data_offset); + + /* Fill in the HW SGT structure. + * + * sgt_buf is zeroed out, so the following fields are implicit + * in all sgt entries: + * - offset is 0 + * - format is 'dpaa2_sg_single' + */ + for_each_sg(scl, crt_scl, num_dma_bufs, i) { + dpaa2_sg_set_addr(&sgt[i], sg_dma_address(crt_scl)); + dpaa2_sg_set_len(&sgt[i], sg_dma_len(crt_scl)); + } + dpaa2_sg_set_final(&sgt[i - 1], true); + + /* Store the skb backpointer in the SGT buffer. + * Fit the scatterlist and the number of buffers alongside the + * skb backpointer in the SWA. We'll need all of them on Tx Conf. + */ + bps = (struct dpaa2_eth_swa *)sgt_buf; + bps->skb = skb; + bps->scl = scl; + bps->num_sg = num_sg; + bps->num_dma_bufs = num_dma_bufs; + + for (j = 0; j < i; j++) + dpaa2_sg_cpu_to_le(&sgt[j]); + + /* Separately map the SGT buffer */ + addr = dma_map_single(dev, sgt_buf, sgt_buf_size, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(dev, addr))) { + netdev_err(priv->net_dev, "dma_map_single() failed\n"); + err = -ENOMEM; + goto dma_map_single_failed; + } + dpaa2_fd_set_offset(fd, priv->tx_data_offset); + dpaa2_fd_set_format(fd, dpaa2_fd_sg); + dpaa2_fd_set_addr(fd, addr); + dpaa2_fd_set_len(fd, skb->len); + + fd->simple.ctrl = DPAA2_FD_CTRL_ASAL | DPAA2_FD_CTRL_PTA | + DPAA2_FD_CTRL_PTV1; + + return 0; + +dma_map_single_failed: + kfree(sgt_buf); +sgt_buf_alloc_failed: + dma_unmap_sg(dev, scl, num_sg, DMA_TO_DEVICE); +dma_map_sg_failed: + kfree(scl); + return err; +} + +static int dpaa2_eth_build_single_fd(struct dpaa2_eth_priv *priv, + struct sk_buff *skb, + struct dpaa2_fd *fd) +{ + struct device *dev = priv->net_dev->dev.parent; + u8 *buffer_start; + struct sk_buff **skbh; + dma_addr_t addr; + + buffer_start = PTR_ALIGN(skb->data - priv->tx_data_offset - + DPAA2_ETH_TX_BUF_ALIGN, + DPAA2_ETH_TX_BUF_ALIGN); + + /* PTA from egress side is passed as is to the confirmation side so + * we need to clear some fields here in order to find consistent values + * on TX confirmation. We are clearing FAS (Frame Annotation Status) + * field here. + */ + memset(buffer_start + priv->buf_layout.private_data_size, 0, 8); + + /* Store a backpointer to the skb at the beginning of the buffer + * (in the private data area) such that we can release it + * on Tx confirm + */ + skbh = (struct sk_buff **)buffer_start; + *skbh = skb; + + addr = dma_map_single(dev, + buffer_start, + skb_tail_pointer(skb) - buffer_start, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(dev, addr))) { + dev_err(dev, "dma_map_single() failed\n"); + return -EINVAL; + } + + dpaa2_fd_set_addr(fd, addr); + dpaa2_fd_set_offset(fd, (u16)(skb->data - buffer_start)); + dpaa2_fd_set_len(fd, skb->len); + dpaa2_fd_set_format(fd, dpaa2_fd_single); + + fd->simple.ctrl = DPAA2_FD_CTRL_ASAL | DPAA2_FD_CTRL_PTA | + DPAA2_FD_CTRL_PTV1; + + return 0; +} + +/* DMA-unmap and free FD and possibly SGT buffer allocated on Tx. The skb + * back-pointed to is also freed. + * This can be called either from dpaa2_eth_tx_conf() or on the error path of + * dpaa2_eth_tx(). + * Optionally, return the frame annotation status word (FAS), which needs + * to be checked if we're on the confirmation path. + */ +static void dpaa2_eth_free_fd(const struct dpaa2_eth_priv *priv, + const struct dpaa2_fd *fd, + u32 *status) +{ + struct device *dev = priv->net_dev->dev.parent; + dma_addr_t fd_addr; + struct sk_buff **skbh, *skb; + unsigned char *buffer_start; + int unmap_size; + struct scatterlist *scl; + int num_sg, num_dma_bufs; + struct dpaa2_eth_swa *bps; + bool fd_single; + struct dpaa2_fas *fas; + + fd_addr = dpaa2_fd_get_addr(fd); + skbh = phys_to_virt(fd_addr); + fd_single = (dpaa2_fd_get_format(fd) == dpaa2_fd_single); + + if (fd_single) { + skb = *skbh; + buffer_start = (unsigned char *)skbh; + /* Accessing the skb buffer is safe before dma unmap, because + * we didn't map the actual skb shell. + */ + dma_unmap_single(dev, fd_addr, + skb_tail_pointer(skb) - buffer_start, + DMA_TO_DEVICE); + } else { + bps = (struct dpaa2_eth_swa *)skbh; + skb = bps->skb; + scl = bps->scl; + num_sg = bps->num_sg; + num_dma_bufs = bps->num_dma_bufs; + + /* Unmap the scatterlist */ + dma_unmap_sg(dev, scl, num_sg, DMA_TO_DEVICE); + kfree(scl); + + /* Unmap the SGT buffer */ + unmap_size = priv->tx_data_offset + + sizeof(struct dpaa2_sg_entry) * (1 + num_dma_bufs); + dma_unmap_single(dev, fd_addr, unmap_size, DMA_TO_DEVICE); + } + + if (priv->ts_tx_en && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { + struct skb_shared_hwtstamps shhwtstamps; + u64 *ns; + + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + + ns = (u64 *)((void *)skbh + + priv->buf_layout.private_data_size + + sizeof(struct dpaa2_fas)); + *ns = DPAA2_PTP_NOMINAL_FREQ_PERIOD_NS * (*ns); + shhwtstamps.hwtstamp = ns_to_ktime(*ns); + skb_tstamp_tx(skb, &shhwtstamps); + } + + /* Check the status from the Frame Annotation after we unmap the first + * buffer but before we free it. + */ + if (status && (fd->simple.frc & DPAA2_FD_FRC_FASV)) { + fas = (struct dpaa2_fas *) + ((void *)skbh + priv->buf_layout.private_data_size); + *status = le32_to_cpu(fas->status); + } + + /* Free SGT buffer kmalloc'ed on tx */ + if (!fd_single) + kfree(skbh); + + /* Move on with skb release */ + dev_kfree_skb(skb); +} + +static int dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + struct dpaa2_fd fd; + struct rtnl_link_stats64 *percpu_stats; + struct dpaa2_eth_stats *percpu_extras; + int err, i; + /* TxConf FQ selection primarily based on cpu affinity; this is + * non-migratable context, so it's safe to call smp_processor_id(). + */ + u16 queue_mapping = smp_processor_id() % priv->dpni_attrs.max_senders; + + percpu_stats = this_cpu_ptr(priv->percpu_stats); + percpu_extras = this_cpu_ptr(priv->percpu_extras); + + /* Setup the FD fields */ + memset(&fd, 0, sizeof(fd)); + + if (unlikely(skb_headroom(skb) < DPAA2_ETH_NEEDED_HEADROOM(priv))) { + struct sk_buff *ns; + + dev_info_once(net_dev->dev.parent, + "skb headroom too small, must realloc.\n"); + ns = skb_realloc_headroom(skb, DPAA2_ETH_NEEDED_HEADROOM(priv)); + if (unlikely(!ns)) { + percpu_stats->tx_dropped++; + goto err_alloc_headroom; + } + dev_kfree_skb(skb); + skb = ns; + } + + /* We'll be holding a back-reference to the skb until Tx Confirmation; + * we don't want that overwritten by a concurrent Tx with a cloned skb. + */ + skb = skb_unshare(skb, GFP_ATOMIC); + if (unlikely(!skb)) { + netdev_err(net_dev, "Out of memory for skb_unshare()"); + /* skb_unshare() has already freed the skb */ + percpu_stats->tx_dropped++; + return NETDEV_TX_OK; + } + + if (skb_is_nonlinear(skb)) { + err = dpaa2_eth_build_sg_fd(priv, skb, &fd); + percpu_extras->tx_sg_frames++; + percpu_extras->tx_sg_bytes += skb->len; + } else { + err = dpaa2_eth_build_single_fd(priv, skb, &fd); + } + + if (unlikely(err)) { + percpu_stats->tx_dropped++; + goto err_build_fd; + } + + /* Tracing point */ + trace_dpaa2_tx_fd(net_dev, &fd); + + for (i = 0; i < (DPAA2_ETH_MAX_TX_QUEUES << 1); i++) { + err = dpaa2_io_service_enqueue_qd(NULL, priv->tx_qdid, 0, + priv->fq[queue_mapping].flowid, + &fd); + if (err != -EBUSY) + break; + } + percpu_extras->tx_portal_busy += i; + if (unlikely(err < 0)) { + netdev_dbg(net_dev, "error enqueueing Tx frame\n"); + percpu_stats->tx_errors++; + /* Clean up everything, including freeing the skb */ + dpaa2_eth_free_fd(priv, &fd, NULL); + } else { + percpu_stats->tx_packets++; + percpu_stats->tx_bytes += skb->len; + } + + return NETDEV_TX_OK; + +err_build_fd: +err_alloc_headroom: + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + +static void dpaa2_eth_tx_conf(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + const struct dpaa2_fd *fd, + struct napi_struct *napi __always_unused) +{ + struct rtnl_link_stats64 *percpu_stats; + struct dpaa2_eth_stats *percpu_extras; + u32 status = 0; + + /* Tracing point */ + trace_dpaa2_tx_conf_fd(priv->net_dev, fd); + + percpu_extras = this_cpu_ptr(priv->percpu_extras); + percpu_extras->tx_conf_frames++; + percpu_extras->tx_conf_bytes += dpaa2_fd_get_len(fd); + + dpaa2_eth_free_fd(priv, fd, &status); + + if (unlikely(status & DPAA2_ETH_TXCONF_ERR_MASK)) { + netdev_err(priv->net_dev, "TxConf frame error(s): 0x%08x\n", + status & DPAA2_ETH_TXCONF_ERR_MASK); + percpu_stats = this_cpu_ptr(priv->percpu_stats); + /* Tx-conf logically pertains to the egress path. */ + percpu_stats->tx_errors++; + } +} + +static int dpaa2_eth_set_rx_csum(struct dpaa2_eth_priv *priv, bool enable) +{ + int err; + + err = dpni_set_l3_chksum_validation(priv->mc_io, 0, priv->mc_token, + enable); + if (err) { + netdev_err(priv->net_dev, + "dpni_set_l3_chksum_validation() failed\n"); + return err; + } + + err = dpni_set_l4_chksum_validation(priv->mc_io, 0, priv->mc_token, + enable); + if (err) { + netdev_err(priv->net_dev, + "dpni_set_l4_chksum_validation failed\n"); + return err; + } + + return 0; +} + +static int dpaa2_eth_set_tx_csum(struct dpaa2_eth_priv *priv, bool enable) +{ + struct dpaa2_eth_fq *fq; + struct dpni_tx_flow_cfg tx_flow_cfg; + int err; + int i; + + memset(&tx_flow_cfg, 0, sizeof(tx_flow_cfg)); + tx_flow_cfg.options = DPNI_TX_FLOW_OPT_L3_CHKSUM_GEN | + DPNI_TX_FLOW_OPT_L4_CHKSUM_GEN; + tx_flow_cfg.l3_chksum_gen = enable; + tx_flow_cfg.l4_chksum_gen = enable; + + for (i = 0; i < priv->num_fqs; i++) { + fq = &priv->fq[i]; + if (fq->type != DPAA2_TX_CONF_FQ) + continue; + + /* The Tx flowid is kept in the corresponding TxConf FQ. */ + err = dpni_set_tx_flow(priv->mc_io, 0, priv->mc_token, + &fq->flowid, &tx_flow_cfg); + if (err) { + netdev_err(priv->net_dev, "dpni_set_tx_flow failed\n"); + return err; + } + } + + return 0; +} + +static int dpaa2_bp_add_7(struct dpaa2_eth_priv *priv, u16 bpid) +{ + struct device *dev = priv->net_dev->dev.parent; + u64 buf_array[7]; + void *buf; + dma_addr_t addr; + int i; + + for (i = 0; i < 7; i++) { + /* Allocate buffer visible to WRIOP + skb shared info + + * alignment padding + */ + buf = napi_alloc_frag(DPAA2_ETH_BUF_RAW_SIZE); + if (unlikely(!buf)) { + dev_err(dev, "buffer allocation failed\n"); + goto err_alloc; + } + buf = PTR_ALIGN(buf, DPAA2_ETH_RX_BUF_ALIGN); + + addr = dma_map_single(dev, buf, DPAA2_ETH_RX_BUFFER_SIZE, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(dev, addr))) { + dev_err(dev, "dma_map_single() failed\n"); + goto err_map; + } + buf_array[i] = addr; + + /* tracing point */ + trace_dpaa2_eth_buf_seed(priv->net_dev, + buf, DPAA2_ETH_BUF_RAW_SIZE, + addr, DPAA2_ETH_RX_BUFFER_SIZE, + bpid); + } + +release_bufs: + /* In case the portal is busy, retry until successful. + * The buffer release function would only fail if the QBMan portal + * was busy, which implies portal contention (i.e. more CPUs than + * portals, i.e. GPPs w/o affine DPIOs). For all practical purposes, + * there is little we can realistically do, short of giving up - + * in which case we'd risk depleting the buffer pool and never again + * receiving the Rx interrupt which would kick-start the refill logic. + * So just keep retrying, at the risk of being moved to ksoftirqd. + */ + while (dpaa2_io_service_release(NULL, bpid, buf_array, i)) + cpu_relax(); + return i; + +err_map: + put_page(virt_to_head_page(buf)); +err_alloc: + if (i) + goto release_bufs; + + return 0; +} + +static int dpaa2_dpbp_seed(struct dpaa2_eth_priv *priv, u16 bpid) +{ + int i, j; + int new_count; + + /* This is the lazy seeding of Rx buffer pools. + * dpaa2_bp_add_7() is also used on the Rx hotpath and calls + * napi_alloc_frag(). The trouble with that is that it in turn ends up + * calling this_cpu_ptr(), which mandates execution in atomic context. + * Rather than splitting up the code, do a one-off preempt disable. + */ + preempt_disable(); + for (j = 0; j < priv->num_channels; j++) { + for (i = 0; i < DPAA2_ETH_NUM_BUFS; i += 7) { + new_count = dpaa2_bp_add_7(priv, bpid); + priv->channel[j]->buf_count += new_count; + + if (new_count < 7) { + preempt_enable(); + goto out_of_memory; + } + } + } + preempt_enable(); + + return 0; + +out_of_memory: + return -ENOMEM; +} + +/** + * Drain the specified number of buffers from the DPNI's private buffer pool. + * @count must not exceeed 7 + */ +static void dpaa2_dpbp_drain_cnt(struct dpaa2_eth_priv *priv, int count) +{ + struct device *dev = priv->net_dev->dev.parent; + u64 buf_array[7]; + void *vaddr; + int ret, i; + + do { + ret = dpaa2_io_service_acquire(NULL, priv->dpbp_attrs.bpid, + buf_array, count); + if (ret < 0) { + pr_err("dpaa2_io_service_acquire() failed\n"); + return; + } + for (i = 0; i < ret; i++) { + /* Same logic as on regular Rx path */ + dma_unmap_single(dev, buf_array[i], + DPAA2_ETH_RX_BUFFER_SIZE, + DMA_FROM_DEVICE); + vaddr = phys_to_virt(buf_array[i]); + put_page(virt_to_head_page(vaddr)); + } + } while (ret); +} + +static void __dpaa2_dpbp_free(struct dpaa2_eth_priv *priv) +{ + int i; + + dpaa2_dpbp_drain_cnt(priv, 7); + dpaa2_dpbp_drain_cnt(priv, 1); + + for (i = 0; i < priv->num_channels; i++) + priv->channel[i]->buf_count = 0; +} + +/* Function is called from softirq context only, so we don't need to guard + * the access to percpu count + */ +static int dpaa2_dpbp_refill(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *ch, + u16 bpid) +{ + int new_count; + int err = 0; + + if (unlikely(ch->buf_count < DPAA2_ETH_REFILL_THRESH)) { + do { + new_count = dpaa2_bp_add_7(priv, bpid); + if (unlikely(!new_count)) { + /* Out of memory; abort for now, we'll + * try later on + */ + break; + } + ch->buf_count += new_count; + } while (ch->buf_count < DPAA2_ETH_NUM_BUFS); + + if (unlikely(ch->buf_count < DPAA2_ETH_NUM_BUFS)) + err = -ENOMEM; + } + + return err; +} + +static int __dpaa2_eth_pull_channel(struct dpaa2_eth_channel *ch) +{ + int err; + int dequeues = -1; + struct dpaa2_eth_priv *priv = ch->priv; + + /* Retry while portal is busy */ + do { + err = dpaa2_io_service_pull_channel(NULL, ch->ch_id, ch->store); + dequeues++; + } while (err == -EBUSY); + if (unlikely(err)) + netdev_err(priv->net_dev, "dpaa2_io_service_pull err %d", err); + + ch->stats.dequeue_portal_busy += dequeues; + return err; +} + +static int dpaa2_eth_poll(struct napi_struct *napi, int budget) +{ + struct dpaa2_eth_channel *ch; + int cleaned = 0, store_cleaned; + struct dpaa2_eth_priv *priv; + int err; + + ch = container_of(napi, struct dpaa2_eth_channel, napi); + priv = ch->priv; + + __dpaa2_eth_pull_channel(ch); + + do { + /* Refill pool if appropriate */ + dpaa2_dpbp_refill(priv, ch, priv->dpbp_attrs.bpid); + + store_cleaned = dpaa2_eth_store_consume(ch); + cleaned += store_cleaned; + + if (store_cleaned == 0 || + cleaned > budget - DPAA2_ETH_STORE_SIZE) + break; + + /* Try to dequeue some more */ + err = __dpaa2_eth_pull_channel(ch); + if (unlikely(err)) + break; + } while (1); + + if (cleaned < budget) { + napi_complete_done(napi, cleaned); + err = dpaa2_io_service_rearm(NULL, &ch->nctx); + if (unlikely(err)) + netdev_err(priv->net_dev, + "Notif rearm failed for channel %d\n", + ch->ch_id); + } + + ch->stats.frames += cleaned; + + return cleaned; +} + +static void dpaa2_eth_napi_enable(struct dpaa2_eth_priv *priv) +{ + struct dpaa2_eth_channel *ch; + int i; + + for (i = 0; i < priv->num_channels; i++) { + ch = priv->channel[i]; + napi_enable(&ch->napi); + } +} + +static void dpaa2_eth_napi_disable(struct dpaa2_eth_priv *priv) +{ + struct dpaa2_eth_channel *ch; + int i; + + for (i = 0; i < priv->num_channels; i++) { + ch = priv->channel[i]; + napi_disable(&ch->napi); + } +} + +static int dpaa2_link_state_update(struct dpaa2_eth_priv *priv) +{ + struct dpni_link_state state; + int err; + + err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state); + if (unlikely(err)) { + netdev_err(priv->net_dev, + "dpni_get_link_state() failed\n"); + return err; + } + + /* Chech link state; speed / duplex changes are not treated yet */ + if (priv->link_state.up == state.up) + return 0; + + priv->link_state = state; + if (state.up) { + netif_carrier_on(priv->net_dev); + netif_tx_start_all_queues(priv->net_dev); + } else { + netif_tx_stop_all_queues(priv->net_dev); + netif_carrier_off(priv->net_dev); + } + + netdev_info(priv->net_dev, "Link Event: state %s", + state.up ? "up" : "down"); + + return 0; +} + +static int dpaa2_eth_open(struct net_device *net_dev) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + int err; + + err = dpaa2_dpbp_seed(priv, priv->dpbp_attrs.bpid); + if (err) { + /* Not much to do; the buffer pool, though not filled up, + * may still contain some buffers which would enable us + * to limp on. + */ + netdev_err(net_dev, "Buffer seeding failed for DPBP %d (bpid=%d)\n", + priv->dpbp_dev->obj_desc.id, priv->dpbp_attrs.bpid); + } + + /* We'll only start the txqs when the link is actually ready; make sure + * we don't race against the link up notification, which may come + * immediately after dpni_enable(); + */ + netif_tx_stop_all_queues(net_dev); + dpaa2_eth_napi_enable(priv); + /* Also, explicitly set carrier off, otherwise netif_carrier_ok() will + * return true and cause 'ip link show' to report the LOWER_UP flag, + * even though the link notification wasn't even received. + */ + netif_carrier_off(net_dev); + + err = dpni_enable(priv->mc_io, 0, priv->mc_token); + if (err < 0) { + dev_err(net_dev->dev.parent, "dpni_enable() failed\n"); + goto enable_err; + } + + /* If the DPMAC object has already processed the link up interrupt, + * we have to learn the link state ourselves. + */ + err = dpaa2_link_state_update(priv); + if (err < 0) { + dev_err(net_dev->dev.parent, "Can't update link state\n"); + goto link_state_err; + } + + return 0; + +link_state_err: +enable_err: + dpaa2_eth_napi_disable(priv); + __dpaa2_dpbp_free(priv); + return err; +} + +static int dpaa2_eth_stop(struct net_device *net_dev) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + + /* Stop Tx and Rx traffic */ + netif_tx_stop_all_queues(net_dev); + netif_carrier_off(net_dev); + dpni_disable(priv->mc_io, 0, priv->mc_token); + + msleep(500); + + dpaa2_eth_napi_disable(priv); + msleep(100); + + __dpaa2_dpbp_free(priv); + + return 0; +} + +static int dpaa2_eth_init(struct net_device *net_dev) +{ + u64 supported = 0; + u64 not_supported = 0; + const struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + u32 options = priv->dpni_attrs.options; + + /* Capabilities listing */ + supported |= IFF_LIVE_ADDR_CHANGE | IFF_PROMISC | IFF_ALLMULTI; + + if (options & DPNI_OPT_UNICAST_FILTER) + supported |= IFF_UNICAST_FLT; + else + not_supported |= IFF_UNICAST_FLT; + + if (options & DPNI_OPT_MULTICAST_FILTER) + supported |= IFF_MULTICAST; + else + not_supported |= IFF_MULTICAST; + + net_dev->priv_flags |= supported; + net_dev->priv_flags &= ~not_supported; + + /* Features */ + net_dev->features = NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_SG | NETIF_F_HIGHDMA | + NETIF_F_LLTX; + net_dev->hw_features = net_dev->features; + + return 0; +} + +static int dpaa2_eth_set_addr(struct net_device *net_dev, void *addr) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + struct device *dev = net_dev->dev.parent; + int err; + + err = eth_mac_addr(net_dev, addr); + if (err < 0) { + dev_err(dev, "eth_mac_addr() failed with error %d\n", err); + return err; + } + + err = dpni_set_primary_mac_addr(priv->mc_io, 0, priv->mc_token, + net_dev->dev_addr); + if (err) { + dev_err(dev, "dpni_set_primary_mac_addr() failed (%d)\n", err); + return err; + } + + return 0; +} + +/** Fill in counters maintained by the GPP driver. These may be different from + * the hardware counters obtained by ethtool. + */ +static struct rtnl_link_stats64 +*dpaa2_eth_get_stats(struct net_device *net_dev, + struct rtnl_link_stats64 *stats) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + struct rtnl_link_stats64 *percpu_stats; + u64 *cpustats; + u64 *netstats = (u64 *)stats; + int i, j; + int num = sizeof(struct rtnl_link_stats64) / sizeof(u64); + + for_each_possible_cpu(i) { + percpu_stats = per_cpu_ptr(priv->percpu_stats, i); + cpustats = (u64 *)percpu_stats; + for (j = 0; j < num; j++) + netstats[j] += cpustats[j]; + } + + return stats; +} + +static int dpaa2_eth_change_mtu(struct net_device *net_dev, int mtu) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + int err; + + if (mtu < 68 || mtu > DPAA2_ETH_MAX_MTU) { + netdev_err(net_dev, "Invalid MTU %d. Valid range is: 68..%d\n", + mtu, DPAA2_ETH_MAX_MTU); + return -EINVAL; + } + + /* Set the maximum Rx frame length to match the transmit side; + * account for L2 headers when computing the MFL + */ + err = dpni_set_max_frame_length(priv->mc_io, 0, priv->mc_token, + (u16)DPAA2_ETH_L2_MAX_FRM(mtu)); + if (err) { + netdev_err(net_dev, "dpni_set_mfl() failed\n"); + return err; + } + + net_dev->mtu = mtu; + return 0; +} + +/* Convenience macro to make code littered with error checking more readable */ +#define DPAA2_ETH_WARN_IF_ERR(err, netdevp, format, ...) \ +do { \ + if (err) \ + netdev_warn(netdevp, format, ##__VA_ARGS__); \ +} while (0) + +/* Copy mac unicast addresses from @net_dev to @priv. + * Its sole purpose is to make dpaa2_eth_set_rx_mode() more readable. + */ +static void _dpaa2_eth_hw_add_uc_addr(const struct net_device *net_dev, + struct dpaa2_eth_priv *priv) +{ + struct netdev_hw_addr *ha; + int err; + + netdev_for_each_uc_addr(ha, net_dev) { + err = dpni_add_mac_addr(priv->mc_io, 0, priv->mc_token, + ha->addr); + DPAA2_ETH_WARN_IF_ERR(err, priv->net_dev, + "Could not add ucast MAC %pM to the filtering table (err %d)\n", + ha->addr, err); + } +} + +/* Copy mac multicast addresses from @net_dev to @priv + * Its sole purpose is to make dpaa2_eth_set_rx_mode() more readable. + */ +static void _dpaa2_eth_hw_add_mc_addr(const struct net_device *net_dev, + struct dpaa2_eth_priv *priv) +{ + struct netdev_hw_addr *ha; + int err; + + netdev_for_each_mc_addr(ha, net_dev) { + err = dpni_add_mac_addr(priv->mc_io, 0, priv->mc_token, + ha->addr); + DPAA2_ETH_WARN_IF_ERR(err, priv->net_dev, + "Could not add mcast MAC %pM to the filtering table (err %d)\n", + ha->addr, err); + } +} + +static void dpaa2_eth_set_rx_mode(struct net_device *net_dev) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + int uc_count = netdev_uc_count(net_dev); + int mc_count = netdev_mc_count(net_dev); + u8 max_uc = priv->dpni_attrs.max_unicast_filters; + u8 max_mc = priv->dpni_attrs.max_multicast_filters; + u32 options = priv->dpni_attrs.options; + u16 mc_token = priv->mc_token; + struct fsl_mc_io *mc_io = priv->mc_io; + int err; + + /* Basic sanity checks; these probably indicate a misconfiguration */ + if (!(options & DPNI_OPT_UNICAST_FILTER) && max_uc != 0) + netdev_info(net_dev, + "max_unicast_filters=%d, you must have DPNI_OPT_UNICAST_FILTER in the DPL\n", + max_uc); + if (!(options & DPNI_OPT_MULTICAST_FILTER) && max_mc != 0) + netdev_info(net_dev, + "max_multicast_filters=%d, you must have DPNI_OPT_MULTICAST_FILTER in the DPL\n", + max_mc); + + /* Force promiscuous if the uc or mc counts exceed our capabilities. */ + if (uc_count > max_uc) { + netdev_info(net_dev, + "Unicast addr count reached %d, max allowed is %d; forcing promisc\n", + uc_count, max_uc); + goto force_promisc; + } + if (mc_count > max_mc) { + netdev_info(net_dev, + "Multicast addr count reached %d, max allowed is %d; forcing promisc\n", + mc_count, max_mc); + goto force_mc_promisc; + } + + /* Adjust promisc settings due to flag combinations */ + if (net_dev->flags & IFF_PROMISC) { + goto force_promisc; + } else if (net_dev->flags & IFF_ALLMULTI) { + /* First, rebuild unicast filtering table. This should be done + * in promisc mode, in order to avoid frame loss while we + * progressively add entries to the table. + * We don't know whether we had been in promisc already, and + * making an MC call to find it is expensive; so set uc promisc + * nonetheless. + */ + err = dpni_set_unicast_promisc(mc_io, 0, mc_token, 1); + DPAA2_ETH_WARN_IF_ERR(err, net_dev, "Can't set uc promisc\n"); + + /* Actual uc table reconstruction. */ + err = dpni_clear_mac_filters(mc_io, 0, mc_token, 1, 0); + DPAA2_ETH_WARN_IF_ERR(err, net_dev, "Can't clear uc filters\n"); + _dpaa2_eth_hw_add_uc_addr(net_dev, priv); + + /* Finally, clear uc promisc and set mc promisc as requested. */ + err = dpni_set_unicast_promisc(mc_io, 0, mc_token, 0); + DPAA2_ETH_WARN_IF_ERR(err, net_dev, "Can't clear uc promisc\n"); + goto force_mc_promisc; + } + + /* Neither unicast, nor multicast promisc will be on... eventually. + * For now, rebuild mac filtering tables while forcing both of them on. + */ + err = dpni_set_unicast_promisc(mc_io, 0, mc_token, 1); + DPAA2_ETH_WARN_IF_ERR(err, net_dev, "Can't set uc promisc (%d)\n", err); + err = dpni_set_multicast_promisc(mc_io, 0, mc_token, 1); + DPAA2_ETH_WARN_IF_ERR(err, net_dev, "Can't set mc promisc (%d)\n", err); + + /* Actual mac filtering tables reconstruction */ + err = dpni_clear_mac_filters(mc_io, 0, mc_token, 1, 1); + DPAA2_ETH_WARN_IF_ERR(err, net_dev, "Can't clear mac filters\n"); + _dpaa2_eth_hw_add_mc_addr(net_dev, priv); + _dpaa2_eth_hw_add_uc_addr(net_dev, priv); + + /* Now we can clear both ucast and mcast promisc, without risking + * to drop legitimate frames anymore. + */ + err = dpni_set_unicast_promisc(mc_io, 0, mc_token, 0); + DPAA2_ETH_WARN_IF_ERR(err, net_dev, "Can't clear ucast promisc\n"); + err = dpni_set_multicast_promisc(mc_io, 0, mc_token, 0); + DPAA2_ETH_WARN_IF_ERR(err, net_dev, "Can't clear mcast promisc\n"); + + return; + +force_promisc: + err = dpni_set_unicast_promisc(mc_io, 0, mc_token, 1); + DPAA2_ETH_WARN_IF_ERR(err, net_dev, "Can't set ucast promisc\n"); +force_mc_promisc: + err = dpni_set_multicast_promisc(mc_io, 0, mc_token, 1); + DPAA2_ETH_WARN_IF_ERR(err, net_dev, "Can't set mcast promisc\n"); +} + +static int dpaa2_eth_set_features(struct net_device *net_dev, + netdev_features_t features) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + netdev_features_t changed = features ^ net_dev->features; + int err; + + if (changed & NETIF_F_RXCSUM) { + bool enable = !!(features & NETIF_F_RXCSUM); + + err = dpaa2_eth_set_rx_csum(priv, enable); + if (err) + return err; + } + + if (changed & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) { + bool enable = !!(features & + (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)); + err = dpaa2_eth_set_tx_csum(priv, enable); + if (err) + return err; + } + + return 0; +} + +static int dpaa2_eth_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct dpaa2_eth_priv *priv = netdev_priv(dev); + struct hwtstamp_config config; + + if (copy_from_user(&config, rq->ifr_data, sizeof(config))) + return -EFAULT; + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + priv->ts_tx_en = false; + break; + case HWTSTAMP_TX_ON: + priv->ts_tx_en = true; + break; + default: + return -ERANGE; + } + + if (config.rx_filter == HWTSTAMP_FILTER_NONE) + priv->ts_rx_en = false; + else { + priv->ts_rx_en = true; + /* TS is set for all frame types, not only those requested */ + config.rx_filter = HWTSTAMP_FILTER_ALL; + } + + return copy_to_user(rq->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + +static int dpaa2_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + if (cmd == SIOCSHWTSTAMP) + return dpaa2_eth_ts_ioctl(dev, rq, cmd); + else + return -EINVAL; +} + +static const struct net_device_ops dpaa2_eth_ops = { + .ndo_open = dpaa2_eth_open, + .ndo_start_xmit = dpaa2_eth_tx, + .ndo_stop = dpaa2_eth_stop, + .ndo_init = dpaa2_eth_init, + .ndo_set_mac_address = dpaa2_eth_set_addr, + .ndo_get_stats64 = dpaa2_eth_get_stats, + .ndo_change_mtu = dpaa2_eth_change_mtu, + .ndo_set_rx_mode = dpaa2_eth_set_rx_mode, + .ndo_set_features = dpaa2_eth_set_features, + .ndo_do_ioctl = dpaa2_eth_ioctl, +}; + +static void dpaa2_eth_cdan_cb(struct dpaa2_io_notification_ctx *ctx) +{ + struct dpaa2_eth_channel *ch; + + ch = container_of(ctx, struct dpaa2_eth_channel, nctx); + + /* Update NAPI statistics */ + ch->stats.cdan++; + + napi_schedule_irqoff(&ch->napi); +} + +static void dpaa2_eth_setup_fqs(struct dpaa2_eth_priv *priv) +{ + int i; + + /* We have one TxConf FQ per Tx flow */ + for (i = 0; i < priv->dpni_attrs.max_senders; i++) { + priv->fq[priv->num_fqs].netdev_priv = priv; + priv->fq[priv->num_fqs].type = DPAA2_TX_CONF_FQ; + priv->fq[priv->num_fqs].consume = dpaa2_eth_tx_conf; + priv->fq[priv->num_fqs++].flowid = DPNI_NEW_FLOW_ID; + } + + /* The number of Rx queues (Rx distribution width) may be different from + * the number of cores. + * We only support one traffic class for now. + */ + for (i = 0; i < dpaa2_queue_count(priv); i++) { + priv->fq[priv->num_fqs].netdev_priv = priv; + priv->fq[priv->num_fqs].type = DPAA2_RX_FQ; + priv->fq[priv->num_fqs].consume = dpaa2_eth_rx; + priv->fq[priv->num_fqs++].flowid = (u16)i; + } + +#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE + /* We have exactly one Rx error queue per DPNI */ + priv->fq[priv->num_fqs].netdev_priv = priv; + priv->fq[priv->num_fqs].type = DPAA2_RX_ERR_FQ; + priv->fq[priv->num_fqs++].consume = dpaa2_eth_rx_err; +#endif +} + +static int check_obj_version(struct fsl_mc_device *ls_dev, u16 mc_version) +{ + char *name = ls_dev->obj_desc.type; + struct device *dev = &ls_dev->dev; + u16 supported_version, flib_version; + + if (strcmp(name, "dpni") == 0) { + flib_version = DPNI_VER_MAJOR; + supported_version = DPAA2_SUPPORTED_DPNI_VERSION; + } else if (strcmp(name, "dpbp") == 0) { + flib_version = DPBP_VER_MAJOR; + supported_version = DPAA2_SUPPORTED_DPBP_VERSION; + } else if (strcmp(name, "dpcon") == 0) { + flib_version = DPCON_VER_MAJOR; + supported_version = DPAA2_SUPPORTED_DPCON_VERSION; + } else { + dev_err(dev, "invalid object type (%s)\n", name); + return -EINVAL; + } + + /* Check that the FLIB-defined version matches the one reported by MC */ + if (mc_version != flib_version) { + dev_err(dev, + "%s FLIB version mismatch: MC reports %d, we have %d\n", + name, mc_version, flib_version); + return -EINVAL; + } + + /* ... and that we actually support it */ + if (mc_version < supported_version) { + dev_err(dev, "Unsupported %s FLIB version (%d)\n", + name, mc_version); + return -EINVAL; + } + dev_dbg(dev, "Using %s FLIB version %d\n", name, mc_version); + + return 0; +} + +static struct fsl_mc_device *dpaa2_dpcon_setup(struct dpaa2_eth_priv *priv) +{ + struct fsl_mc_device *dpcon; + struct device *dev = priv->net_dev->dev.parent; + struct dpcon_attr attrs; + int err; + + err = fsl_mc_object_allocate(to_fsl_mc_device(dev), + FSL_MC_POOL_DPCON, &dpcon); + if (err) { + dev_info(dev, "Not enough DPCONs, will go on as-is\n"); + return NULL; + } + + err = dpcon_open(priv->mc_io, 0, dpcon->obj_desc.id, &dpcon->mc_handle); + if (err) { + dev_err(dev, "dpcon_open() failed\n"); + goto err_open; + } + + err = dpcon_get_attributes(priv->mc_io, 0, dpcon->mc_handle, &attrs); + if (err) { + dev_err(dev, "dpcon_get_attributes() failed\n"); + goto err_get_attr; + } + + err = check_obj_version(dpcon, attrs.version.major); + if (err) + goto err_dpcon_ver; + + err = dpcon_enable(priv->mc_io, 0, dpcon->mc_handle); + if (err) { + dev_err(dev, "dpcon_enable() failed\n"); + goto err_enable; + } + + return dpcon; + +err_enable: +err_dpcon_ver: +err_get_attr: + dpcon_close(priv->mc_io, 0, dpcon->mc_handle); +err_open: + fsl_mc_object_free(dpcon); + + return NULL; +} + +static void dpaa2_dpcon_free(struct dpaa2_eth_priv *priv, + struct fsl_mc_device *dpcon) +{ + dpcon_disable(priv->mc_io, 0, dpcon->mc_handle); + dpcon_close(priv->mc_io, 0, dpcon->mc_handle); + fsl_mc_object_free(dpcon); +} + +static struct dpaa2_eth_channel * +dpaa2_alloc_channel(struct dpaa2_eth_priv *priv) +{ + struct dpaa2_eth_channel *channel; + struct dpcon_attr attr; + struct device *dev = priv->net_dev->dev.parent; + int err; + + channel = kzalloc(sizeof(*channel), GFP_ATOMIC); + if (!channel) { + dev_err(dev, "Memory allocation failed\n"); + return NULL; + } + + channel->dpcon = dpaa2_dpcon_setup(priv); + if (!channel->dpcon) + goto err_setup; + + err = dpcon_get_attributes(priv->mc_io, 0, channel->dpcon->mc_handle, + &attr); + if (err) { + dev_err(dev, "dpcon_get_attributes() failed\n"); + goto err_get_attr; + } + + channel->dpcon_id = attr.id; + channel->ch_id = attr.qbman_ch_id; + channel->priv = priv; + + return channel; + +err_get_attr: + dpaa2_dpcon_free(priv, channel->dpcon); +err_setup: + kfree(channel); + return NULL; +} + +static void dpaa2_free_channel(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_channel *channel) +{ + dpaa2_dpcon_free(priv, channel->dpcon); + kfree(channel); +} + +static int dpaa2_dpio_setup(struct dpaa2_eth_priv *priv) +{ + struct dpaa2_io_notification_ctx *nctx; + struct dpaa2_eth_channel *channel; + struct dpcon_notification_cfg dpcon_notif_cfg; + struct device *dev = priv->net_dev->dev.parent; + int i, err; + + /* Don't allocate more channels than strictly necessary and assign + * them to cores starting from the first one available in + * cpu_online_mask. + * If the number of channels is lower than the number of cores, + * there will be no rx/tx conf processing on the last cores in the mask. + */ + cpumask_clear(&priv->dpio_cpumask); + for_each_online_cpu(i) { + /* Try to allocate a channel */ + channel = dpaa2_alloc_channel(priv); + if (!channel) + goto err_alloc_ch; + + priv->channel[priv->num_channels] = channel; + + nctx = &channel->nctx; + nctx->is_cdan = 1; + nctx->cb = dpaa2_eth_cdan_cb; + nctx->id = channel->ch_id; + nctx->desired_cpu = i; + + /* Register the new context */ + err = dpaa2_io_service_register(NULL, nctx); + if (err) { + dev_info(dev, "No affine DPIO for core %d\n", i); + /* This core doesn't have an affine DPIO, but there's + * a chance another one does, so keep trying + */ + dpaa2_free_channel(priv, channel); + continue; + } + + /* Register DPCON notification with MC */ + dpcon_notif_cfg.dpio_id = nctx->dpio_id; + dpcon_notif_cfg.priority = 0; + dpcon_notif_cfg.user_ctx = nctx->qman64; + err = dpcon_set_notification(priv->mc_io, 0, + channel->dpcon->mc_handle, + &dpcon_notif_cfg); + if (err) { + dev_err(dev, "dpcon_set_notification failed()\n"); + goto err_set_cdan; + } + + /* If we managed to allocate a channel and also found an affine + * DPIO for this core, add it to the final mask + */ + cpumask_set_cpu(i, &priv->dpio_cpumask); + priv->num_channels++; + + if (priv->num_channels == dpaa2_max_channels(priv)) + break; + } + + /* Tx confirmation queues can only be serviced by cpus + * with an affine DPIO/channel + */ + cpumask_copy(&priv->txconf_cpumask, &priv->dpio_cpumask); + + return 0; + +err_set_cdan: + dpaa2_io_service_deregister(NULL, nctx); + dpaa2_free_channel(priv, channel); +err_alloc_ch: + if (cpumask_empty(&priv->dpio_cpumask)) { + dev_err(dev, "No cpu with an affine DPIO/DPCON\n"); + return -ENODEV; + } + cpumask_copy(&priv->txconf_cpumask, &priv->dpio_cpumask); + + return 0; +} + +static void dpaa2_dpio_free(struct dpaa2_eth_priv *priv) +{ + int i; + struct dpaa2_eth_channel *ch; + + /* deregister CDAN notifications and free channels */ + for (i = 0; i < priv->num_channels; i++) { + ch = priv->channel[i]; + dpaa2_io_service_deregister(NULL, &ch->nctx); + dpaa2_free_channel(priv, ch); + } +} + +static struct dpaa2_eth_channel * +dpaa2_get_channel_by_cpu(struct dpaa2_eth_priv *priv, int cpu) +{ + struct device *dev = priv->net_dev->dev.parent; + int i; + + for (i = 0; i < priv->num_channels; i++) + if (priv->channel[i]->nctx.desired_cpu == cpu) + return priv->channel[i]; + + /* We should never get here. Issue a warning and return + * the first channel, because it's still better than nothing + */ + dev_warn(dev, "No affine channel found for cpu %d\n", cpu); + + return priv->channel[0]; +} + +static void dpaa2_set_fq_affinity(struct dpaa2_eth_priv *priv) +{ + struct device *dev = priv->net_dev->dev.parent; + struct dpaa2_eth_fq *fq; + int rx_cpu, txconf_cpu; + int i; + + /* For each FQ, pick one channel/CPU to deliver frames to. + * This may well change at runtime, either through irqbalance or + * through direct user intervention. + */ + rx_cpu = cpumask_first(&priv->dpio_cpumask); + txconf_cpu = cpumask_first(&priv->txconf_cpumask); + + for (i = 0; i < priv->num_fqs; i++) { + fq = &priv->fq[i]; + switch (fq->type) { + case DPAA2_RX_FQ: + case DPAA2_RX_ERR_FQ: + fq->target_cpu = rx_cpu; + cpumask_rr(rx_cpu, &priv->dpio_cpumask); + break; + case DPAA2_TX_CONF_FQ: + fq->target_cpu = txconf_cpu; + cpumask_rr(txconf_cpu, &priv->txconf_cpumask); + break; + default: + dev_err(dev, "Unknown FQ type: %d\n", fq->type); + } + fq->channel = dpaa2_get_channel_by_cpu(priv, fq->target_cpu); + } +} + +static int dpaa2_dpbp_setup(struct dpaa2_eth_priv *priv) +{ + int err; + struct fsl_mc_device *dpbp_dev; + struct device *dev = priv->net_dev->dev.parent; + + err = fsl_mc_object_allocate(to_fsl_mc_device(dev), FSL_MC_POOL_DPBP, + &dpbp_dev); + if (err) { + dev_err(dev, "DPBP device allocation failed\n"); + return err; + } + + priv->dpbp_dev = dpbp_dev; + + err = dpbp_open(priv->mc_io, 0, priv->dpbp_dev->obj_desc.id, + &dpbp_dev->mc_handle); + if (err) { + dev_err(dev, "dpbp_open() failed\n"); + goto err_open; + } + + err = dpbp_enable(priv->mc_io, 0, dpbp_dev->mc_handle); + if (err) { + dev_err(dev, "dpbp_enable() failed\n"); + goto err_enable; + } + + err = dpbp_get_attributes(priv->mc_io, 0, dpbp_dev->mc_handle, + &priv->dpbp_attrs); + if (err) { + dev_err(dev, "dpbp_get_attributes() failed\n"); + goto err_get_attr; + } + + err = check_obj_version(dpbp_dev, priv->dpbp_attrs.version.major); + if (err) + goto err_dpbp_ver; + + return 0; + +err_dpbp_ver: +err_get_attr: + dpbp_disable(priv->mc_io, 0, dpbp_dev->mc_handle); +err_enable: + dpbp_close(priv->mc_io, 0, dpbp_dev->mc_handle); +err_open: + fsl_mc_object_free(dpbp_dev); + + return err; +} + +static void dpaa2_dpbp_free(struct dpaa2_eth_priv *priv) +{ + __dpaa2_dpbp_free(priv); + dpbp_disable(priv->mc_io, 0, priv->dpbp_dev->mc_handle); + dpbp_close(priv->mc_io, 0, priv->dpbp_dev->mc_handle); + fsl_mc_object_free(priv->dpbp_dev); +} + +static int dpaa2_dpni_setup(struct fsl_mc_device *ls_dev) +{ + struct device *dev = &ls_dev->dev; + struct dpaa2_eth_priv *priv; + struct net_device *net_dev; + void *dma_mem; + int err; + + net_dev = dev_get_drvdata(dev); + priv = netdev_priv(net_dev); + + priv->dpni_id = ls_dev->obj_desc.id; + + /* and get a handle for the DPNI this interface is associate with */ + err = dpni_open(priv->mc_io, 0, priv->dpni_id, &priv->mc_token); + if (err) { + dev_err(dev, "dpni_open() failed\n"); + goto err_open; + } + + ls_dev->mc_io = priv->mc_io; + ls_dev->mc_handle = priv->mc_token; + + dma_mem = kzalloc(DPAA2_EXT_CFG_SIZE, GFP_DMA | GFP_KERNEL); + if (!dma_mem) + goto err_alloc; + + priv->dpni_attrs.ext_cfg_iova = dma_map_single(dev, dma_mem, + DPAA2_EXT_CFG_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(dev, priv->dpni_attrs.ext_cfg_iova)) { + dev_err(dev, "dma mapping for dpni_ext_cfg failed\n"); + goto err_dma_map; + } + + err = dpni_get_attributes(priv->mc_io, 0, priv->mc_token, + &priv->dpni_attrs); + if (err) { + dev_err(dev, "dpni_get_attributes() failed (err=%d)\n", err); + dma_unmap_single(dev, priv->dpni_attrs.ext_cfg_iova, + DPAA2_EXT_CFG_SIZE, DMA_FROM_DEVICE); + goto err_get_attr; + } + + err = check_obj_version(ls_dev, priv->dpni_attrs.version.major); + if (err) + goto err_dpni_ver; + + dma_unmap_single(dev, priv->dpni_attrs.ext_cfg_iova, + DPAA2_EXT_CFG_SIZE, DMA_FROM_DEVICE); + + memset(&priv->dpni_ext_cfg, 0, sizeof(priv->dpni_ext_cfg)); + err = dpni_extract_extended_cfg(&priv->dpni_ext_cfg, dma_mem); + if (err) { + dev_err(dev, "dpni_extract_extended_cfg() failed\n"); + goto err_extract; + } + + /* Configure our buffers' layout */ + priv->buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT | + DPNI_BUF_LAYOUT_OPT_FRAME_STATUS | + DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE | + DPNI_BUF_LAYOUT_OPT_DATA_ALIGN; + priv->buf_layout.pass_parser_result = true; + priv->buf_layout.pass_frame_status = true; + priv->buf_layout.private_data_size = DPAA2_ETH_SWA_SIZE; + /* HW erratum mandates data alignment in multiples of 256 */ + priv->buf_layout.data_align = DPAA2_ETH_RX_BUF_ALIGN; + /* ...rx, ... */ + err = dpni_set_rx_buffer_layout(priv->mc_io, 0, priv->mc_token, + &priv->buf_layout); + if (err) { + dev_err(dev, "dpni_set_rx_buffer_layout() failed"); + goto err_buf_layout; + } + /* ... tx, ... */ + /* remove Rx-only options */ + priv->buf_layout.options &= ~(DPNI_BUF_LAYOUT_OPT_DATA_ALIGN | + DPNI_BUF_LAYOUT_OPT_PARSER_RESULT); + err = dpni_set_tx_buffer_layout(priv->mc_io, 0, priv->mc_token, + &priv->buf_layout); + if (err) { + dev_err(dev, "dpni_set_tx_buffer_layout() failed"); + goto err_buf_layout; + } + /* ... tx-confirm. */ + priv->buf_layout.options &= ~DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE; + priv->buf_layout.options |= DPNI_BUF_LAYOUT_OPT_TIMESTAMP; + priv->buf_layout.pass_timestamp = 1; + err = dpni_set_tx_conf_buffer_layout(priv->mc_io, 0, priv->mc_token, + &priv->buf_layout); + if (err) { + dev_err(dev, "dpni_set_tx_conf_buffer_layout() failed"); + goto err_buf_layout; + } + /* Now that we've set our tx buffer layout, retrieve the minimum + * required tx data offset. + */ + err = dpni_get_tx_data_offset(priv->mc_io, 0, priv->mc_token, + &priv->tx_data_offset); + if (err) { + dev_err(dev, "dpni_get_tx_data_offset() failed\n"); + goto err_data_offset; + } + + /* Warn in case TX data offset is not multiple of 64 bytes. */ + WARN_ON(priv->tx_data_offset % 64); + + /* Accommodate SWA space. */ + priv->tx_data_offset += DPAA2_ETH_SWA_SIZE; + + /* allocate classification rule space */ + priv->cls_rule = kzalloc(sizeof(*priv->cls_rule) * + DPAA2_CLASSIFIER_ENTRY_COUNT, GFP_KERNEL); + if (!priv->cls_rule) + goto err_cls_rule; + + kfree(dma_mem); + + return 0; + +err_cls_rule: +err_data_offset: +err_buf_layout: +err_extract: +err_dpni_ver: +err_get_attr: +err_dma_map: + kfree(dma_mem); +err_alloc: + dpni_close(priv->mc_io, 0, priv->mc_token); +err_open: + return err; +} + +static void dpaa2_dpni_free(struct dpaa2_eth_priv *priv) +{ + int err; + + err = dpni_reset(priv->mc_io, 0, priv->mc_token); + if (err) + netdev_warn(priv->net_dev, "dpni_reset() failed (err %d)\n", + err); + + dpni_close(priv->mc_io, 0, priv->mc_token); +} + +static int dpaa2_rx_flow_setup(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_fq *fq) +{ + struct device *dev = priv->net_dev->dev.parent; + struct dpni_queue_attr rx_queue_attr; + struct dpni_queue_cfg queue_cfg; + int err; + + memset(&queue_cfg, 0, sizeof(queue_cfg)); + queue_cfg.options = DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST | + DPNI_QUEUE_OPT_TAILDROP_THRESHOLD; + queue_cfg.dest_cfg.dest_type = DPNI_DEST_DPCON; + queue_cfg.dest_cfg.priority = 1; + queue_cfg.user_ctx = (u64)fq; + queue_cfg.dest_cfg.dest_id = fq->channel->dpcon_id; + queue_cfg.tail_drop_threshold = DPAA2_ETH_TAILDROP_THRESH; + err = dpni_set_rx_flow(priv->mc_io, 0, priv->mc_token, 0, fq->flowid, + &queue_cfg); + if (err) { + dev_err(dev, "dpni_set_rx_flow() failed\n"); + return err; + } + + /* Get the actual FQID that was assigned by MC */ + err = dpni_get_rx_flow(priv->mc_io, 0, priv->mc_token, 0, fq->flowid, + &rx_queue_attr); + if (err) { + dev_err(dev, "dpni_get_rx_flow() failed\n"); + return err; + } + fq->fqid = rx_queue_attr.fqid; + + return 0; +} + +static int dpaa2_tx_flow_setup(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_fq *fq) +{ + struct device *dev = priv->net_dev->dev.parent; + struct dpni_tx_flow_cfg tx_flow_cfg; + struct dpni_tx_conf_cfg tx_conf_cfg; + struct dpni_tx_conf_attr tx_conf_attr; + int err; + + memset(&tx_flow_cfg, 0, sizeof(tx_flow_cfg)); + tx_flow_cfg.options = DPNI_TX_FLOW_OPT_TX_CONF_ERROR; + tx_flow_cfg.use_common_tx_conf_queue = 0; + err = dpni_set_tx_flow(priv->mc_io, 0, priv->mc_token, + &fq->flowid, &tx_flow_cfg); + if (err) { + dev_err(dev, "dpni_set_tx_flow() failed\n"); + return err; + } + + tx_conf_cfg.errors_only = 0; + tx_conf_cfg.queue_cfg.options = DPNI_QUEUE_OPT_USER_CTX | + DPNI_QUEUE_OPT_DEST; + tx_conf_cfg.queue_cfg.user_ctx = (u64)fq; + tx_conf_cfg.queue_cfg.dest_cfg.dest_type = DPNI_DEST_DPCON; + tx_conf_cfg.queue_cfg.dest_cfg.dest_id = fq->channel->dpcon_id; + tx_conf_cfg.queue_cfg.dest_cfg.priority = 0; + + err = dpni_set_tx_conf(priv->mc_io, 0, priv->mc_token, fq->flowid, + &tx_conf_cfg); + if (err) { + dev_err(dev, "dpni_set_tx_conf() failed\n"); + return err; + } + + err = dpni_get_tx_conf(priv->mc_io, 0, priv->mc_token, fq->flowid, + &tx_conf_attr); + if (err) { + dev_err(dev, "dpni_get_tx_conf() failed\n"); + return err; + } + + fq->fqid = tx_conf_attr.queue_attr.fqid; + + return 0; +} + +#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE +static int dpaa2_rx_err_setup(struct dpaa2_eth_priv *priv, + struct dpaa2_eth_fq *fq) +{ + struct dpni_queue_attr queue_attr; + struct dpni_queue_cfg queue_cfg; + int err; + + /* Configure the Rx error queue to generate CDANs, + * just like the Rx queues */ + queue_cfg.options = DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST; + queue_cfg.dest_cfg.dest_type = DPNI_DEST_DPCON; + queue_cfg.dest_cfg.priority = 1; + queue_cfg.user_ctx = (u64)fq; + queue_cfg.dest_cfg.dest_id = fq->channel->dpcon_id; + err = dpni_set_rx_err_queue(priv->mc_io, 0, priv->mc_token, &queue_cfg); + if (err) { + netdev_err(priv->net_dev, "dpni_set_rx_err_queue() failed\n"); + return err; + } + + /* Get the FQID */ + err = dpni_get_rx_err_queue(priv->mc_io, 0, priv->mc_token, &queue_attr); + if (err) { + netdev_err(priv->net_dev, "dpni_get_rx_err_queue() failed\n"); + return err; + } + fq->fqid = queue_attr.fqid; + + return 0; +} +#endif + +static int dpaa2_dpni_bind(struct dpaa2_eth_priv *priv) +{ + struct net_device *net_dev = priv->net_dev; + struct device *dev = net_dev->dev.parent; + struct dpni_pools_cfg pools_params; + struct dpni_error_cfg err_cfg; + int err = 0; + int i; + + pools_params.num_dpbp = 1; + pools_params.pools[0].dpbp_id = priv->dpbp_dev->obj_desc.id; + pools_params.pools[0].backup_pool = 0; + pools_params.pools[0].buffer_size = DPAA2_ETH_RX_BUFFER_SIZE; + err = dpni_set_pools(priv->mc_io, 0, priv->mc_token, &pools_params); + if (err) { + dev_err(dev, "dpni_set_pools() failed\n"); + return err; + } + + dpaa2_cls_check(net_dev); + + /* have the interface implicitly distribute traffic based on supported + * header fields + */ + if (dpaa2_eth_hash_enabled(priv)) { + err = dpaa2_set_hash(net_dev, DPAA2_RXH_SUPPORTED); + if (err) + return err; + } + + /* Configure handling of error frames */ + err_cfg.errors = DPAA2_ETH_RX_ERR_MASK; + err_cfg.set_frame_annotation = 1; +#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE + err_cfg.error_action = DPNI_ERROR_ACTION_SEND_TO_ERROR_QUEUE; +#else + err_cfg.error_action = DPNI_ERROR_ACTION_DISCARD; +#endif + err = dpni_set_errors_behavior(priv->mc_io, 0, priv->mc_token, + &err_cfg); + if (err) { + dev_err(dev, "dpni_set_errors_behavior failed\n"); + return err; + } + + /* Configure Rx and Tx conf queues to generate CDANs */ + for (i = 0; i < priv->num_fqs; i++) { + switch (priv->fq[i].type) { + case DPAA2_RX_FQ: + err = dpaa2_rx_flow_setup(priv, &priv->fq[i]); + break; + case DPAA2_TX_CONF_FQ: + err = dpaa2_tx_flow_setup(priv, &priv->fq[i]); + break; +#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE + case DPAA2_RX_ERR_FQ: + err = dpaa2_rx_err_setup(priv, &priv->fq[i]); + break; +#endif + default: + dev_err(dev, "Invalid FQ type %d\n", priv->fq[i].type); + return -EINVAL; + } + if (err) + return err; + } + + err = dpni_get_qdid(priv->mc_io, 0, priv->mc_token, &priv->tx_qdid); + if (err) { + dev_err(dev, "dpni_get_qdid() failed\n"); + return err; + } + + return 0; +} + +static int dpaa2_eth_alloc_rings(struct dpaa2_eth_priv *priv) +{ + struct net_device *net_dev = priv->net_dev; + struct device *dev = net_dev->dev.parent; + int i; + + for (i = 0; i < priv->num_channels; i++) { + priv->channel[i]->store = + dpaa2_io_store_create(DPAA2_ETH_STORE_SIZE, dev); + if (!priv->channel[i]->store) { + netdev_err(net_dev, "dpaa2_io_store_create() failed\n"); + goto err_ring; + } + } + + return 0; + +err_ring: + for (i = 0; i < priv->num_channels; i++) { + if (!priv->channel[i]->store) + break; + dpaa2_io_store_destroy(priv->channel[i]->store); + } + + return -ENOMEM; +} + +static void dpaa2_eth_free_rings(struct dpaa2_eth_priv *priv) +{ + int i; + + for (i = 0; i < priv->num_channels; i++) + dpaa2_io_store_destroy(priv->channel[i]->store); +} + +static int dpaa2_eth_netdev_init(struct net_device *net_dev) +{ + int err; + struct device *dev = net_dev->dev.parent; + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + u8 mac_addr[ETH_ALEN]; + u8 bcast_addr[ETH_ALEN]; + + net_dev->netdev_ops = &dpaa2_eth_ops; + + /* If the DPL contains all-0 mac_addr, set a random hardware address */ + err = dpni_get_primary_mac_addr(priv->mc_io, 0, priv->mc_token, + mac_addr); + if (err) { + dev_err(dev, "dpni_get_primary_mac_addr() failed (%d)", err); + return err; + } + if (is_zero_ether_addr(mac_addr)) { + /* Fills in net_dev->dev_addr, as required by + * register_netdevice() + */ + eth_hw_addr_random(net_dev); + /* Make the user aware, without cluttering the boot log */ + pr_info_once(KBUILD_MODNAME " device(s) have all-zero hwaddr, replaced with random"); + err = dpni_set_primary_mac_addr(priv->mc_io, 0, priv->mc_token, + net_dev->dev_addr); + if (err) { + dev_err(dev, "dpni_set_primary_mac_addr(): %d\n", err); + return err; + } + /* Override NET_ADDR_RANDOM set by eth_hw_addr_random(); for all + * practical purposes, this will be our "permanent" mac address, + * at least until the next reboot. This move will also permit + * register_netdevice() to properly fill up net_dev->perm_addr. + */ + net_dev->addr_assign_type = NET_ADDR_PERM; + } else { + /* NET_ADDR_PERM is default, all we have to do is + * fill in the device addr. + */ + memcpy(net_dev->dev_addr, mac_addr, net_dev->addr_len); + } + + /* Explicitly add the broadcast address to the MAC filtering table; + * the MC won't do that for us. + */ + eth_broadcast_addr(bcast_addr); + err = dpni_add_mac_addr(priv->mc_io, 0, priv->mc_token, bcast_addr); + if (err) { + dev_warn(dev, "dpni_add_mac_addr() failed (%d)\n", err); + /* Won't return an error; at least, we'd have egress traffic */ + } + + /* Reserve enough space to align buffer as per hardware requirement; + * NOTE: priv->tx_data_offset MUST be initialized at this point. + */ + net_dev->needed_headroom = DPAA2_ETH_NEEDED_HEADROOM(priv); + + /* Our .ndo_init will be called herein */ + err = register_netdev(net_dev); + if (err < 0) { + dev_err(dev, "register_netdev() = %d\n", err); + return err; + } + + return 0; +} + +#ifdef CONFIG_FSL_DPAA2_ETH_LINK_POLL +static int dpaa2_poll_link_state(void *arg) +{ + struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)arg; + int err; + + while (!kthread_should_stop()) { + err = dpaa2_link_state_update(priv); + if (unlikely(err)) + return err; + + msleep(DPAA2_ETH_LINK_STATE_REFRESH); + } + + return 0; +} +#else +static irqreturn_t dpni_irq0_handler(int irq_num, void *arg) +{ + return IRQ_WAKE_THREAD; +} + +static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg) +{ + u8 irq_index = DPNI_IRQ_INDEX; + u32 status, clear = 0; + struct device *dev = (struct device *)arg; + struct fsl_mc_device *dpni_dev = to_fsl_mc_device(dev); + struct net_device *net_dev = dev_get_drvdata(dev); + int err; + + netdev_dbg(net_dev, "IRQ %d received\n", irq_num); + err = dpni_get_irq_status(dpni_dev->mc_io, 0, dpni_dev->mc_handle, + irq_index, &status); + if (unlikely(err)) { + netdev_err(net_dev, "Can't get irq status (err %d)", err); + clear = 0xffffffff; + goto out; + } + + if (status & DPNI_IRQ_EVENT_LINK_CHANGED) { + clear |= DPNI_IRQ_EVENT_LINK_CHANGED; + dpaa2_link_state_update(netdev_priv(net_dev)); + } + +out: + dpni_clear_irq_status(dpni_dev->mc_io, 0, dpni_dev->mc_handle, + irq_index, clear); + return IRQ_HANDLED; +} + +static int dpaa2_eth_setup_irqs(struct fsl_mc_device *ls_dev) +{ + int err = 0; + struct fsl_mc_device_irq *irq; + int irq_count = ls_dev->obj_desc.irq_count; + u8 irq_index = DPNI_IRQ_INDEX; + u32 mask = DPNI_IRQ_EVENT_LINK_CHANGED; + + /* The only interrupt supported now is the link state notification. */ + if (WARN_ON(irq_count != 1)) + return -EINVAL; + + irq = ls_dev->irqs[0]; + err = devm_request_threaded_irq(&ls_dev->dev, irq->msi_desc->irq, + dpni_irq0_handler, + dpni_irq0_handler_thread, + IRQF_NO_SUSPEND | IRQF_ONESHOT, + dev_name(&ls_dev->dev), &ls_dev->dev); + if (err < 0) { + dev_err(&ls_dev->dev, "devm_request_threaded_irq(): %d", err); + return err; + } + + err = dpni_set_irq_mask(ls_dev->mc_io, 0, ls_dev->mc_handle, + irq_index, mask); + if (err < 0) { + dev_err(&ls_dev->dev, "dpni_set_irq_mask(): %d", err); + return err; + } + + err = dpni_set_irq_enable(ls_dev->mc_io, 0, ls_dev->mc_handle, + irq_index, 1); + if (err < 0) { + dev_err(&ls_dev->dev, "dpni_set_irq_enable(): %d", err); + return err; + } + + return 0; +} +#endif + +static void dpaa2_eth_napi_add(struct dpaa2_eth_priv *priv) +{ + int i; + struct dpaa2_eth_channel *ch; + + for (i = 0; i < priv->num_channels; i++) { + ch = priv->channel[i]; + /* NAPI weight *MUST* be a multiple of DPAA2_ETH_STORE_SIZE */ + netif_napi_add(priv->net_dev, &ch->napi, dpaa2_eth_poll, + NAPI_POLL_WEIGHT); + } +} + +static void dpaa2_eth_napi_del(struct dpaa2_eth_priv *priv) +{ + int i; + struct dpaa2_eth_channel *ch; + + for (i = 0; i < priv->num_channels; i++) { + ch = priv->channel[i]; + netif_napi_del(&ch->napi); + } +} + +/* SysFS support */ + +static ssize_t dpaa2_eth_show_tx_shaping(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev)); + /* No MC API for getting the shaping config. We're stateful. */ + struct dpni_tx_shaping_cfg *scfg = &priv->shaping_cfg; + + return sprintf(buf, "%u %hu\n", scfg->rate_limit, scfg->max_burst_size); +} + +static ssize_t dpaa2_eth_write_tx_shaping(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int err, items; + struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev)); + struct dpni_tx_shaping_cfg scfg; + + items = sscanf(buf, "%u %hu", &scfg.rate_limit, &scfg.max_burst_size); + if (items != 2) { + pr_err("Expected format: \"rate_limit(Mbps) max_burst_size(bytes)\"\n"); + return -EINVAL; + } + /* Size restriction as per MC API documentation */ + if (scfg.max_burst_size > 64000) { + pr_err("max_burst_size must be <= 64000, thanks.\n"); + return -EINVAL; + } + + err = dpni_set_tx_shaping(priv->mc_io, 0, priv->mc_token, &scfg); + if (err) { + dev_err(dev, "dpni_set_tx_shaping() failed\n"); + return -EPERM; + } + /* If successful, save the current configuration for future inquiries */ + priv->shaping_cfg = scfg; + + return count; +} + +static ssize_t dpaa2_eth_show_txconf_cpumask(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev)); + + return cpumap_print_to_pagebuf(1, buf, &priv->txconf_cpumask); +} + +static ssize_t dpaa2_eth_write_txconf_cpumask(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev)); + struct dpaa2_eth_fq *fq; + bool running = netif_running(priv->net_dev); + int i, err; + + err = cpulist_parse(buf, &priv->txconf_cpumask); + if (err) + return err; + + /* Only accept CPUs that have an affine DPIO */ + if (!cpumask_subset(&priv->txconf_cpumask, &priv->dpio_cpumask)) { + netdev_info(priv->net_dev, + "cpumask must be a subset of 0x%lx\n", + *cpumask_bits(&priv->dpio_cpumask)); + cpumask_and(&priv->txconf_cpumask, &priv->dpio_cpumask, + &priv->txconf_cpumask); + } + + /* Rewiring the TxConf FQs requires interface shutdown. + */ + if (running) { + err = dpaa2_eth_stop(priv->net_dev); + if (err) + return -ENODEV; + } + + /* Set the new TxConf FQ affinities */ + dpaa2_set_fq_affinity(priv); + +#ifdef CONFIG_FSL_DPAA2_ETH_LINK_POLL + /* dpaa2_eth_open() below will *stop* the Tx queues until an explicit + * link up notification is received. Give the polling thread enough time + * to detect the link state change, or else we'll end up with the + * transmission side forever shut down. + */ + msleep(2 * DPAA2_ETH_LINK_STATE_REFRESH); +#endif + + for (i = 0; i < priv->num_fqs; i++) { + fq = &priv->fq[i]; + if (fq->type != DPAA2_TX_CONF_FQ) + continue; + dpaa2_tx_flow_setup(priv, fq); + } + + if (running) { + err = dpaa2_eth_open(priv->net_dev); + if (err) + return -ENODEV; + } + + return count; +} + +static struct device_attribute dpaa2_eth_attrs[] = { + __ATTR(txconf_cpumask, + S_IRUSR | S_IWUSR, + dpaa2_eth_show_txconf_cpumask, + dpaa2_eth_write_txconf_cpumask), + + __ATTR(tx_shaping, + S_IRUSR | S_IWUSR, + dpaa2_eth_show_tx_shaping, + dpaa2_eth_write_tx_shaping), +}; + +void dpaa2_eth_sysfs_init(struct device *dev) +{ + int i, err; + + for (i = 0; i < ARRAY_SIZE(dpaa2_eth_attrs); i++) { + err = device_create_file(dev, &dpaa2_eth_attrs[i]); + if (err) { + dev_err(dev, "ERROR creating sysfs file\n"); + goto undo; + } + } + return; + +undo: + while (i > 0) + device_remove_file(dev, &dpaa2_eth_attrs[--i]); +} + +void dpaa2_eth_sysfs_remove(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dpaa2_eth_attrs); i++) + device_remove_file(dev, &dpaa2_eth_attrs[i]); +} + +static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) +{ + struct device *dev; + struct net_device *net_dev = NULL; + struct dpaa2_eth_priv *priv = NULL; + int err = 0; + + dev = &dpni_dev->dev; + + /* Net device */ + net_dev = alloc_etherdev_mq(sizeof(*priv), DPAA2_ETH_MAX_TX_QUEUES); + if (!net_dev) { + dev_err(dev, "alloc_etherdev_mq() failed\n"); + return -ENOMEM; + } + + SET_NETDEV_DEV(net_dev, dev); + dev_set_drvdata(dev, net_dev); + + priv = netdev_priv(net_dev); + priv->net_dev = net_dev; + priv->msg_enable = netif_msg_init(debug, -1); + + /* Obtain a MC portal */ + err = fsl_mc_portal_allocate(dpni_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, + &priv->mc_io); + if (err) { + dev_err(dev, "MC portal allocation failed\n"); + goto err_portal_alloc; + } + +#ifndef CONFIG_FSL_DPAA2_ETH_LINK_POLL + err = fsl_mc_allocate_irqs(dpni_dev); + if (err) { + dev_err(dev, "MC irqs allocation failed\n"); + goto err_irqs_alloc; + } +#endif + + /* DPNI initialization */ + err = dpaa2_dpni_setup(dpni_dev); + if (err < 0) + goto err_dpni_setup; + + /* DPIO */ + err = dpaa2_dpio_setup(priv); + if (err) + goto err_dpio_setup; + + /* FQs */ + dpaa2_eth_setup_fqs(priv); + dpaa2_set_fq_affinity(priv); + + /* DPBP */ + err = dpaa2_dpbp_setup(priv); + if (err) + goto err_dpbp_setup; + + /* DPNI binding to DPIO and DPBPs */ + err = dpaa2_dpni_bind(priv); + if (err) + goto err_bind; + + dpaa2_eth_napi_add(priv); + + /* Percpu statistics */ + priv->percpu_stats = alloc_percpu(*priv->percpu_stats); + if (!priv->percpu_stats) { + dev_err(dev, "alloc_percpu(percpu_stats) failed\n"); + err = -ENOMEM; + goto err_alloc_percpu_stats; + } + priv->percpu_extras = alloc_percpu(*priv->percpu_extras); + if (!priv->percpu_extras) { + dev_err(dev, "alloc_percpu(percpu_extras) failed\n"); + err = -ENOMEM; + goto err_alloc_percpu_extras; + } + + snprintf(net_dev->name, IFNAMSIZ, "ni%d", dpni_dev->obj_desc.id); + if (!dev_valid_name(net_dev->name)) { + dev_warn(&net_dev->dev, + "netdevice name \"%s\" cannot be used, reverting to default..\n", + net_dev->name); + dev_alloc_name(net_dev, "eth%d"); + dev_warn(&net_dev->dev, "using name \"%s\"\n", net_dev->name); + } + + err = dpaa2_eth_netdev_init(net_dev); + if (err) + goto err_netdev_init; + + /* Configure checksum offload based on current interface flags */ + err = dpaa2_eth_set_rx_csum(priv, + !!(net_dev->features & NETIF_F_RXCSUM)); + if (err) + goto err_csum; + + err = dpaa2_eth_set_tx_csum(priv, + !!(net_dev->features & + (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))); + if (err) + goto err_csum; + + err = dpaa2_eth_alloc_rings(priv); + if (err) + goto err_alloc_rings; + + net_dev->ethtool_ops = &dpaa2_ethtool_ops; + +#ifdef CONFIG_FSL_DPAA2_ETH_LINK_POLL + priv->poll_thread = kthread_run(dpaa2_poll_link_state, priv, + "%s_poll_link", net_dev->name); +#else + err = dpaa2_eth_setup_irqs(dpni_dev); + if (err) { + netdev_err(net_dev, "ERROR %d setting up interrupts", err); + goto err_setup_irqs; + } +#endif + + dpaa2_eth_sysfs_init(&net_dev->dev); + dpaa2_dbg_add(priv); + + dev_info(dev, "Probed interface %s\n", net_dev->name); + return 0; + +#ifndef CONFIG_FSL_DPAA2_ETH_LINK_POLL +err_setup_irqs: +#endif + dpaa2_eth_free_rings(priv); +err_alloc_rings: +err_csum: + unregister_netdev(net_dev); +err_netdev_init: + free_percpu(priv->percpu_extras); +err_alloc_percpu_extras: + free_percpu(priv->percpu_stats); +err_alloc_percpu_stats: + dpaa2_eth_napi_del(priv); +err_bind: + dpaa2_dpbp_free(priv); +err_dpbp_setup: + dpaa2_dpio_free(priv); +err_dpio_setup: + kfree(priv->cls_rule); + dpni_close(priv->mc_io, 0, priv->mc_token); +err_dpni_setup: +#ifndef CONFIG_FSL_DPAA2_ETH_LINK_POLL + fsl_mc_free_irqs(dpni_dev); +err_irqs_alloc: +#endif + fsl_mc_portal_free(priv->mc_io); +err_portal_alloc: + dev_set_drvdata(dev, NULL); + free_netdev(net_dev); + + return err; +} + +static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev) +{ + struct device *dev; + struct net_device *net_dev; + struct dpaa2_eth_priv *priv; + + dev = &ls_dev->dev; + net_dev = dev_get_drvdata(dev); + priv = netdev_priv(net_dev); + + dpaa2_dbg_remove(priv); + dpaa2_eth_sysfs_remove(&net_dev->dev); + + unregister_netdev(net_dev); + dev_info(net_dev->dev.parent, "Removed interface %s\n", net_dev->name); + + dpaa2_dpio_free(priv); + dpaa2_eth_free_rings(priv); + dpaa2_eth_napi_del(priv); + dpaa2_dpbp_free(priv); + dpaa2_dpni_free(priv); + + fsl_mc_portal_free(priv->mc_io); + + free_percpu(priv->percpu_stats); + free_percpu(priv->percpu_extras); + +#ifdef CONFIG_FSL_DPAA2_ETH_LINK_POLL + kthread_stop(priv->poll_thread); +#else + fsl_mc_free_irqs(ls_dev); +#endif + + kfree(priv->cls_rule); + + dev_set_drvdata(dev, NULL); + free_netdev(net_dev); + + return 0; +} + +static const struct fsl_mc_device_match_id dpaa2_eth_match_id_table[] = { + { + .vendor = FSL_MC_VENDOR_FREESCALE, + .obj_type = "dpni", + .ver_major = DPNI_VER_MAJOR, + .ver_minor = DPNI_VER_MINOR + }, + { .vendor = 0x0 } +}; + +static struct fsl_mc_driver dpaa2_eth_driver = { + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + }, + .probe = dpaa2_eth_probe, + .remove = dpaa2_eth_remove, + .match_id_table = dpaa2_eth_match_id_table +}; + +static int __init dpaa2_eth_driver_init(void) +{ + int err; + + dpaa2_eth_dbg_init(); + + err = fsl_mc_driver_register(&dpaa2_eth_driver); + if (err) { + dpaa2_eth_dbg_exit(); + return err; + } + + return 0; +} + +static void __exit dpaa2_eth_driver_exit(void) +{ + fsl_mc_driver_unregister(&dpaa2_eth_driver); + dpaa2_eth_dbg_exit(); +} + +module_init(dpaa2_eth_driver_init); +module_exit(dpaa2_eth_driver_exit); --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h @@ -0,0 +1,366 @@ +/* Copyright 2014-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DPAA2_ETH_H +#define __DPAA2_ETH_H + +#include +#include +#include "../../fsl-mc/include/fsl_dpaa2_io.h" +#include "../../fsl-mc/include/fsl_dpaa2_fd.h" +#include "../../fsl-mc/include/dpbp.h" +#include "../../fsl-mc/include/dpbp-cmd.h" +#include "../../fsl-mc/include/dpcon.h" +#include "../../fsl-mc/include/dpcon-cmd.h" +#include "../../fsl-mc/include/dpmng.h" +#include "dpni.h" +#include "dpni-cmd.h" + +#include "dpaa2-eth-trace.h" +#include "dpaa2-eth-debugfs.h" + +#define DPAA2_ETH_STORE_SIZE 16 + +/* Maximum receive frame size is 64K */ +#define DPAA2_ETH_MAX_SG_ENTRIES ((64 * 1024) / DPAA2_ETH_RX_BUFFER_SIZE) + +/* Maximum acceptable MTU value. It is in direct relation with the MC-enforced + * Max Frame Length (currently 10k). + */ +#define DPAA2_ETH_MFL (10 * 1024) +#define DPAA2_ETH_MAX_MTU (DPAA2_ETH_MFL - VLAN_ETH_HLEN) +/* Convert L3 MTU to L2 MFL */ +#define DPAA2_ETH_L2_MAX_FRM(mtu) (mtu + VLAN_ETH_HLEN) + +/* Set the taildrop threshold (in bytes) to allow the enqueue of several jumbo + * frames in the Rx queues (length of the current frame is not + * taken into account when making the taildrop decision) + */ +#define DPAA2_ETH_TAILDROP_THRESH (64 * 1024) + +/* Buffer quota per queue. Must be large enough such that for minimum sized + * frames taildrop kicks in before the bpool gets depleted, so we compute + * how many 64B frames fit inside the taildrop threshold and add a margin + * to accommodate the buffer refill delay. + */ +#define DPAA2_ETH_MAX_FRAMES_PER_QUEUE (DPAA2_ETH_TAILDROP_THRESH / 64) +#define DPAA2_ETH_NUM_BUFS (DPAA2_ETH_MAX_FRAMES_PER_QUEUE + 256) +#define DPAA2_ETH_REFILL_THRESH DPAA2_ETH_MAX_FRAMES_PER_QUEUE + +/* Hardware requires alignment for ingress/egress buffer addresses + * and ingress buffer lengths. + */ +#define DPAA2_ETH_RX_BUFFER_SIZE 2048 +#define DPAA2_ETH_TX_BUF_ALIGN 64 +#define DPAA2_ETH_RX_BUF_ALIGN 256 +#define DPAA2_ETH_NEEDED_HEADROOM(p_priv) \ + ((p_priv)->tx_data_offset + DPAA2_ETH_TX_BUF_ALIGN) + +#define DPAA2_ETH_BUF_RAW_SIZE \ + (DPAA2_ETH_RX_BUFFER_SIZE + \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) + \ + DPAA2_ETH_RX_BUF_ALIGN) + +/* PTP nominal frequency 1MHz */ +#define DPAA2_PTP_NOMINAL_FREQ_PERIOD_NS 1000 + +/* We are accommodating a skb backpointer and some S/G info + * in the frame's software annotation. The hardware + * options are either 0 or 64, so we choose the latter. + */ +#define DPAA2_ETH_SWA_SIZE 64 + +/* Must keep this struct smaller than DPAA2_ETH_SWA_SIZE */ +struct dpaa2_eth_swa { + struct sk_buff *skb; + struct scatterlist *scl; + int num_sg; + int num_dma_bufs; +}; + +/* Annotation valid bits in FD FRC */ +#define DPAA2_FD_FRC_FASV 0x8000 +#define DPAA2_FD_FRC_FAEADV 0x4000 +#define DPAA2_FD_FRC_FAPRV 0x2000 +#define DPAA2_FD_FRC_FAIADV 0x1000 +#define DPAA2_FD_FRC_FASWOV 0x0800 +#define DPAA2_FD_FRC_FAICFDV 0x0400 + +/* Annotation bits in FD CTRL */ +#define DPAA2_FD_CTRL_ASAL 0x00020000 /* ASAL = 128 */ +#define DPAA2_FD_CTRL_PTA 0x00800000 +#define DPAA2_FD_CTRL_PTV1 0x00400000 + +/* Frame annotation status */ +struct dpaa2_fas { + u8 reserved; + u8 ppid; + __le16 ifpid; + __le32 status; +} __packed; + +/* Debug frame, otherwise supposed to be discarded */ +#define DPAA2_ETH_FAS_DISC 0x80000000 +/* MACSEC frame */ +#define DPAA2_ETH_FAS_MS 0x40000000 +#define DPAA2_ETH_FAS_PTP 0x08000000 +/* Ethernet multicast frame */ +#define DPAA2_ETH_FAS_MC 0x04000000 +/* Ethernet broadcast frame */ +#define DPAA2_ETH_FAS_BC 0x02000000 +#define DPAA2_ETH_FAS_KSE 0x00040000 +#define DPAA2_ETH_FAS_EOFHE 0x00020000 +#define DPAA2_ETH_FAS_MNLE 0x00010000 +#define DPAA2_ETH_FAS_TIDE 0x00008000 +#define DPAA2_ETH_FAS_PIEE 0x00004000 +/* Frame length error */ +#define DPAA2_ETH_FAS_FLE 0x00002000 +/* Frame physical error; our favourite pastime */ +#define DPAA2_ETH_FAS_FPE 0x00001000 +#define DPAA2_ETH_FAS_PTE 0x00000080 +#define DPAA2_ETH_FAS_ISP 0x00000040 +#define DPAA2_ETH_FAS_PHE 0x00000020 +#define DPAA2_ETH_FAS_BLE 0x00000010 +/* L3 csum validation performed */ +#define DPAA2_ETH_FAS_L3CV 0x00000008 +/* L3 csum error */ +#define DPAA2_ETH_FAS_L3CE 0x00000004 +/* L4 csum validation performed */ +#define DPAA2_ETH_FAS_L4CV 0x00000002 +/* L4 csum error */ +#define DPAA2_ETH_FAS_L4CE 0x00000001 +/* These bits always signal errors */ +#define DPAA2_ETH_RX_ERR_MASK (DPAA2_ETH_FAS_KSE | \ + DPAA2_ETH_FAS_EOFHE | \ + DPAA2_ETH_FAS_MNLE | \ + DPAA2_ETH_FAS_TIDE | \ + DPAA2_ETH_FAS_PIEE | \ + DPAA2_ETH_FAS_FLE | \ + DPAA2_ETH_FAS_FPE | \ + DPAA2_ETH_FAS_PTE | \ + DPAA2_ETH_FAS_ISP | \ + DPAA2_ETH_FAS_PHE | \ + DPAA2_ETH_FAS_BLE | \ + DPAA2_ETH_FAS_L3CE | \ + DPAA2_ETH_FAS_L4CE) +/* Unsupported features in the ingress */ +#define DPAA2_ETH_RX_UNSUPP_MASK DPAA2_ETH_FAS_MS +/* Tx errors */ +#define DPAA2_ETH_TXCONF_ERR_MASK (DPAA2_ETH_FAS_KSE | \ + DPAA2_ETH_FAS_EOFHE | \ + DPAA2_ETH_FAS_MNLE | \ + DPAA2_ETH_FAS_TIDE) + +/* Time in milliseconds between link state updates */ +#define DPAA2_ETH_LINK_STATE_REFRESH 1000 + +/* Driver statistics, other than those in struct rtnl_link_stats64. + * These are usually collected per-CPU and aggregated by ethtool. + */ +struct dpaa2_eth_stats { + __u64 tx_conf_frames; + __u64 tx_conf_bytes; + __u64 tx_sg_frames; + __u64 tx_sg_bytes; + __u64 rx_sg_frames; + __u64 rx_sg_bytes; + /* Enqueues retried due to portal busy */ + __u64 tx_portal_busy; +}; + +/* Per-FQ statistics */ +struct dpaa2_eth_fq_stats { + /* Number of frames received on this queue */ + __u64 frames; +}; + +/* Per-channel statistics */ +struct dpaa2_eth_ch_stats { + /* Volatile dequeues retried due to portal busy */ + __u64 dequeue_portal_busy; + /* Number of CDANs; useful to estimate avg NAPI len */ + __u64 cdan; + /* Number of frames received on queues from this channel */ + __u64 frames; +}; + +/* Maximum number of Rx queues associated with a DPNI */ +#define DPAA2_ETH_MAX_RX_QUEUES 16 +#define DPAA2_ETH_MAX_TX_QUEUES NR_CPUS +#define DPAA2_ETH_MAX_RX_ERR_QUEUES 1 +#define DPAA2_ETH_MAX_QUEUES (DPAA2_ETH_MAX_RX_QUEUES + \ + DPAA2_ETH_MAX_TX_QUEUES + \ + DPAA2_ETH_MAX_RX_ERR_QUEUES) + +#define DPAA2_ETH_MAX_DPCONS NR_CPUS + +enum dpaa2_eth_fq_type { + DPAA2_RX_FQ = 0, + DPAA2_TX_CONF_FQ, + DPAA2_RX_ERR_FQ +}; + +struct dpaa2_eth_priv; + +struct dpaa2_eth_fq { + u32 fqid; + u16 flowid; + int target_cpu; + struct dpaa2_eth_channel *channel; + enum dpaa2_eth_fq_type type; + + void (*consume)(struct dpaa2_eth_priv *, + struct dpaa2_eth_channel *, + const struct dpaa2_fd *, + struct napi_struct *); + struct dpaa2_eth_priv *netdev_priv; /* backpointer */ + struct dpaa2_eth_fq_stats stats; +}; + +struct dpaa2_eth_channel { + struct dpaa2_io_notification_ctx nctx; + struct fsl_mc_device *dpcon; + int dpcon_id; + int ch_id; + int dpio_id; + struct napi_struct napi; + struct dpaa2_io_store *store; + struct dpaa2_eth_priv *priv; + int buf_count; + struct dpaa2_eth_ch_stats stats; +}; + +struct dpaa2_cls_rule { + struct ethtool_rx_flow_spec fs; + bool in_use; +}; + +struct dpaa2_eth_priv { + struct net_device *net_dev; + + u8 num_fqs; + /* First queue is tx conf, the rest are rx */ + struct dpaa2_eth_fq fq[DPAA2_ETH_MAX_QUEUES]; + + u8 num_channels; + struct dpaa2_eth_channel *channel[DPAA2_ETH_MAX_DPCONS]; + + int dpni_id; + struct dpni_attr dpni_attrs; + struct dpni_extended_cfg dpni_ext_cfg; + /* Insofar as the MC is concerned, we're using one layout on all 3 types + * of buffers (Rx, Tx, Tx-Conf). + */ + struct dpni_buffer_layout buf_layout; + u16 tx_data_offset; + + struct fsl_mc_device *dpbp_dev; + struct dpbp_attr dpbp_attrs; + + u16 tx_qdid; + struct fsl_mc_io *mc_io; + /* SysFS-controlled affinity mask for TxConf FQs */ + struct cpumask txconf_cpumask; + /* Cores which have an affine DPIO/DPCON. + * This is the cpu set on which Rx frames are processed; + * Tx confirmation frames are processed on a subset of this, + * depending on user settings. + */ + struct cpumask dpio_cpumask; + + /* Standard statistics */ + struct rtnl_link_stats64 __percpu *percpu_stats; + /* Extra stats, in addition to the ones known by the kernel */ + struct dpaa2_eth_stats __percpu *percpu_extras; + u32 msg_enable; /* net_device message level */ + + u16 mc_token; + + struct dpni_link_state link_state; + struct task_struct *poll_thread; + + /* enabled ethtool hashing bits */ + u64 rx_hash_fields; + +#ifdef CONFIG_FSL_DPAA2_ETH_DEBUGFS + struct dpaa2_debugfs dbg; +#endif + + /* array of classification rules */ + struct dpaa2_cls_rule *cls_rule; + + struct dpni_tx_shaping_cfg shaping_cfg; + + bool ts_tx_en; /* Tx timestamping enabled */ + bool ts_rx_en; /* Rx timestamping enabled */ +}; + +/* default Rx hash options, set during probing */ +#define DPAA2_RXH_SUPPORTED (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO \ + | RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 \ + | RXH_L4_B_2_3) + +#define dpaa2_eth_hash_enabled(priv) \ + ((priv)->dpni_attrs.options & DPNI_OPT_DIST_HASH) + +#define dpaa2_eth_fs_enabled(priv) \ + ((priv)->dpni_attrs.options & DPNI_OPT_DIST_FS) + +#define DPAA2_CLASSIFIER_ENTRY_COUNT 16 + +/* Required by struct dpni_attr::ext_cfg_iova */ +#define DPAA2_EXT_CFG_SIZE 256 + +extern const struct ethtool_ops dpaa2_ethtool_ops; + +int dpaa2_set_hash(struct net_device *net_dev, u64 flags); + +static int dpaa2_queue_count(struct dpaa2_eth_priv *priv) +{ + if (!dpaa2_eth_hash_enabled(priv)) + return 1; + + return priv->dpni_ext_cfg.tc_cfg[0].max_dist; +} + +static inline int dpaa2_max_channels(struct dpaa2_eth_priv *priv) +{ + /* Ideally, we want a number of channels large enough + * to accommodate both the Rx distribution size + * and the max number of Tx confirmation queues + */ + return max_t(int, dpaa2_queue_count(priv), + priv->dpni_attrs.max_senders); +} + +void dpaa2_cls_check(struct net_device *); + +#endif /* __DPAA2_H */ --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c @@ -0,0 +1,882 @@ +/* Copyright 2014-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "dpni.h" /* DPNI_LINK_OPT_* */ +#include "dpaa2-eth.h" + +/* size of DMA memory used to pass configuration to classifier, in bytes */ +#define DPAA2_CLASSIFIER_DMA_SIZE 256 + +/* To be kept in sync with 'enum dpni_counter' */ +char dpaa2_ethtool_stats[][ETH_GSTRING_LEN] = { + "rx frames", + "rx bytes", + "rx frames dropped", + "rx err frames", + "rx mcast frames", + "rx mcast bytes", + "rx bcast frames", + "rx bcast bytes", + "tx frames", + "tx bytes", + "tx err frames", +}; + +#define DPAA2_ETH_NUM_STATS ARRAY_SIZE(dpaa2_ethtool_stats) + +/* To be kept in sync with 'struct dpaa2_eth_stats' */ +char dpaa2_ethtool_extras[][ETH_GSTRING_LEN] = { + /* per-cpu stats */ + + "tx conf frames", + "tx conf bytes", + "tx sg frames", + "tx sg bytes", + "rx sg frames", + "rx sg bytes", + /* how many times we had to retry the enqueue command */ + "tx portal busy", + + /* Channel stats */ + + /* How many times we had to retry the volatile dequeue command */ + "portal busy", + /* Number of notifications received */ + "cdan", +#ifdef CONFIG_FSL_QBMAN_DEBUG + /* FQ stats */ + "rx pending frames", + "rx pending bytes", + "tx conf pending frames", + "tx conf pending bytes", + "buffer count" +#endif +}; + +#define DPAA2_ETH_NUM_EXTRA_STATS ARRAY_SIZE(dpaa2_ethtool_extras) + +static void dpaa2_get_drvinfo(struct net_device *net_dev, + struct ethtool_drvinfo *drvinfo) +{ + struct mc_version mc_ver; + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + char fw_version[ETHTOOL_FWVERS_LEN]; + char version[32]; + int err; + + err = mc_get_version(priv->mc_io, 0, &mc_ver); + if (err) { + strlcpy(drvinfo->fw_version, "Error retrieving MC version", + sizeof(drvinfo->fw_version)); + } else { + scnprintf(fw_version, sizeof(fw_version), "%d.%d.%d", + mc_ver.major, mc_ver.minor, mc_ver.revision); + strlcpy(drvinfo->fw_version, fw_version, + sizeof(drvinfo->fw_version)); + } + + scnprintf(version, sizeof(version), "%d.%d", DPNI_VER_MAJOR, + DPNI_VER_MINOR); + strlcpy(drvinfo->version, version, sizeof(drvinfo->version)); + + strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver)); + strlcpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent), + sizeof(drvinfo->bus_info)); +} + +static u32 dpaa2_get_msglevel(struct net_device *net_dev) +{ + return ((struct dpaa2_eth_priv *)netdev_priv(net_dev))->msg_enable; +} + +static void dpaa2_set_msglevel(struct net_device *net_dev, + u32 msg_enable) +{ + ((struct dpaa2_eth_priv *)netdev_priv(net_dev))->msg_enable = + msg_enable; +} + +static int dpaa2_get_settings(struct net_device *net_dev, + struct ethtool_cmd *cmd) +{ + struct dpni_link_state state = {0}; + int err = 0; + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + + err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state); + if (err) { + netdev_err(net_dev, "ERROR %d getting link state", err); + goto out; + } + + /* At the moment, we have no way of interrogating the DPMAC + * from the DPNI side - and for that matter there may exist + * no DPMAC at all. So for now we just don't report anything + * beyond the DPNI attributes. + */ + if (state.options & DPNI_LINK_OPT_AUTONEG) + cmd->autoneg = AUTONEG_ENABLE; + if (!(state.options & DPNI_LINK_OPT_HALF_DUPLEX)) + cmd->duplex = DUPLEX_FULL; + ethtool_cmd_speed_set(cmd, state.rate); + +out: + return err; +} + +static int dpaa2_set_settings(struct net_device *net_dev, + struct ethtool_cmd *cmd) +{ + struct dpni_link_cfg cfg = {0}; + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + int err = 0; + + netdev_dbg(net_dev, "Setting link parameters..."); + + /* Due to a temporary firmware limitation, the DPNI must be down + * in order to be able to change link settings. Taking steps to let + * the user know that. + */ + if (netif_running(net_dev)) { + netdev_info(net_dev, "Sorry, interface must be brought down first.\n"); + return -EACCES; + } + + cfg.rate = ethtool_cmd_speed(cmd); + if (cmd->autoneg == AUTONEG_ENABLE) + cfg.options |= DPNI_LINK_OPT_AUTONEG; + else + cfg.options &= ~DPNI_LINK_OPT_AUTONEG; + if (cmd->duplex == DUPLEX_HALF) + cfg.options |= DPNI_LINK_OPT_HALF_DUPLEX; + else + cfg.options &= ~DPNI_LINK_OPT_HALF_DUPLEX; + + err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg); + if (err) + /* ethtool will be loud enough if we return an error; no point + * in putting our own error message on the console by default + */ + netdev_dbg(net_dev, "ERROR %d setting link cfg", err); + + return err; +} + +static void dpaa2_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < DPAA2_ETH_NUM_STATS; i++) { + strlcpy(p, dpaa2_ethtool_stats[i], ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + for (i = 0; i < DPAA2_ETH_NUM_EXTRA_STATS; i++) { + strlcpy(p, dpaa2_ethtool_extras[i], ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static int dpaa2_get_sset_count(struct net_device *net_dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: /* ethtool_get_stats(), ethtool_get_drvinfo() */ + return DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS; + default: + return -EOPNOTSUPP; + } +} + +/** Fill in hardware counters, as returned by the MC firmware. + */ +static void dpaa2_get_ethtool_stats(struct net_device *net_dev, + struct ethtool_stats *stats, + u64 *data) +{ + int i; /* Current index in the data array */ + int j, k, err; + +#ifdef CONFIG_FSL_QBMAN_DEBUG + u32 fcnt, bcnt; + u32 fcnt_rx_total = 0, fcnt_tx_total = 0; + u32 bcnt_rx_total = 0, bcnt_tx_total = 0; + u32 buf_cnt; +#endif + u64 cdan = 0; + u64 portal_busy = 0; + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + struct dpaa2_eth_stats *extras; + struct dpaa2_eth_ch_stats *ch_stats; + + memset(data, 0, + sizeof(u64) * (DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS)); + + /* Print standard counters, from DPNI statistics */ + for (i = 0; i < DPAA2_ETH_NUM_STATS; i++) { + err = dpni_get_counter(priv->mc_io, 0, priv->mc_token, i, + data + i); + if (err != 0) + netdev_warn(net_dev, "Err %d getting DPNI counter %d", + err, i); + } + + /* Print per-cpu extra stats */ + for_each_online_cpu(k) { + extras = per_cpu_ptr(priv->percpu_extras, k); + for (j = 0; j < sizeof(*extras) / sizeof(__u64); j++) + *((__u64 *)data + i + j) += *((__u64 *)extras + j); + } + i += j; + + /* We may be using fewer DPIOs than actual CPUs */ + for_each_cpu(j, &priv->dpio_cpumask) { + ch_stats = &priv->channel[j]->stats; + cdan += ch_stats->cdan; + portal_busy += ch_stats->dequeue_portal_busy; + } + + *(data + i++) = portal_busy; + *(data + i++) = cdan; + +#ifdef CONFIG_FSL_QBMAN_DEBUG + for (j = 0; j < priv->num_fqs; j++) { + /* Print FQ instantaneous counts */ + err = dpaa2_io_query_fq_count(NULL, priv->fq[j].fqid, + &fcnt, &bcnt); + if (err) { + netdev_warn(net_dev, "FQ query error %d", err); + return; + } + + if (priv->fq[j].type == DPAA2_TX_CONF_FQ) { + fcnt_tx_total += fcnt; + bcnt_tx_total += bcnt; + } else { + fcnt_rx_total += fcnt; + bcnt_rx_total += bcnt; + } + } + *(data + i++) = fcnt_rx_total; + *(data + i++) = bcnt_rx_total; + *(data + i++) = fcnt_tx_total; + *(data + i++) = bcnt_tx_total; + + err = dpaa2_io_query_bp_count(NULL, priv->dpbp_attrs.bpid, &buf_cnt); + if (err) { + netdev_warn(net_dev, "Buffer count query error %d\n", err); + return; + } + *(data + i++) = buf_cnt; +#endif +} + +static const struct dpaa2_hash_fields { + u64 rxnfc_field; + enum net_prot cls_prot; + int cls_field; + int size; +} dpaa2_hash_fields[] = { + { + /* L2 header */ + .rxnfc_field = RXH_L2DA, + .cls_prot = NET_PROT_ETH, + .cls_field = NH_FLD_ETH_DA, + .size = 6, + }, { + /* VLAN header */ + .rxnfc_field = RXH_VLAN, + .cls_prot = NET_PROT_VLAN, + .cls_field = NH_FLD_VLAN_TCI, + .size = 2, + }, { + /* IP header */ + .rxnfc_field = RXH_IP_SRC, + .cls_prot = NET_PROT_IP, + .cls_field = NH_FLD_IP_SRC, + .size = 4, + }, { + .rxnfc_field = RXH_IP_DST, + .cls_prot = NET_PROT_IP, + .cls_field = NH_FLD_IP_DST, + .size = 4, + }, { + .rxnfc_field = RXH_L3_PROTO, + .cls_prot = NET_PROT_IP, + .cls_field = NH_FLD_IP_PROTO, + .size = 1, + }, { + /* Using UDP ports, this is functionally equivalent to raw + * byte pairs from L4 header. + */ + .rxnfc_field = RXH_L4_B_0_1, + .cls_prot = NET_PROT_UDP, + .cls_field = NH_FLD_UDP_PORT_SRC, + .size = 2, + }, { + .rxnfc_field = RXH_L4_B_2_3, + .cls_prot = NET_PROT_UDP, + .cls_field = NH_FLD_UDP_PORT_DST, + .size = 2, + }, +}; + +static int dpaa2_cls_is_enabled(struct net_device *net_dev, u64 flag) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + + return !!(priv->rx_hash_fields & flag); +} + +static int dpaa2_cls_key_off(struct net_device *net_dev, u64 flag) +{ + int i, off = 0; + + for (i = 0; i < ARRAY_SIZE(dpaa2_hash_fields); i++) { + if (dpaa2_hash_fields[i].rxnfc_field & flag) + return off; + if (dpaa2_cls_is_enabled(net_dev, + dpaa2_hash_fields[i].rxnfc_field)) + off += dpaa2_hash_fields[i].size; + } + + return -1; +} + +static u8 dpaa2_cls_key_size(struct net_device *net_dev) +{ + u8 i, size = 0; + + for (i = 0; i < ARRAY_SIZE(dpaa2_hash_fields); i++) { + if (!dpaa2_cls_is_enabled(net_dev, + dpaa2_hash_fields[i].rxnfc_field)) + continue; + size += dpaa2_hash_fields[i].size; + } + + return size; +} + +static u8 dpaa2_cls_max_key_size(struct net_device *net_dev) +{ + u8 i, size = 0; + + for (i = 0; i < ARRAY_SIZE(dpaa2_hash_fields); i++) + size += dpaa2_hash_fields[i].size; + + return size; +} + +void dpaa2_cls_check(struct net_device *net_dev) +{ + u8 key_size = dpaa2_cls_max_key_size(net_dev); + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + + if (priv->dpni_attrs.options & DPNI_OPT_DIST_FS && + priv->dpni_attrs.max_dist_key_size < key_size) { + dev_err(&net_dev->dev, + "max_dist_key_size = %d, expected %d. Steering is disabled\n", + priv->dpni_attrs.max_dist_key_size, + key_size); + priv->dpni_attrs.options &= ~DPNI_OPT_DIST_FS; + } +} + +/* Set RX hash options + * flags is a combination of RXH_ bits + */ +int dpaa2_set_hash(struct net_device *net_dev, u64 flags) +{ + struct device *dev = net_dev->dev.parent; + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + struct dpkg_profile_cfg cls_cfg; + struct dpni_rx_tc_dist_cfg dist_cfg; + u8 *dma_mem; + u64 enabled_flags = 0; + int i; + int err = 0; + + if (!dpaa2_eth_hash_enabled(priv)) { + dev_err(dev, "Hashing support is not enabled\n"); + return -EOPNOTSUPP; + } + + if (flags & ~DPAA2_RXH_SUPPORTED) { + /* RXH_DISCARD is not supported */ + dev_err(dev, "unsupported option selected, supported options are: mvtsdfn\n"); + return -EOPNOTSUPP; + } + + memset(&cls_cfg, 0, sizeof(cls_cfg)); + + for (i = 0; i < ARRAY_SIZE(dpaa2_hash_fields); i++) { + struct dpkg_extract *key = + &cls_cfg.extracts[cls_cfg.num_extracts]; + + if (!(flags & dpaa2_hash_fields[i].rxnfc_field)) + continue; + + if (cls_cfg.num_extracts >= DPKG_MAX_NUM_OF_EXTRACTS) { + dev_err(dev, "error adding key extraction rule, too many rules?\n"); + return -E2BIG; + } + + key->type = DPKG_EXTRACT_FROM_HDR; + key->extract.from_hdr.prot = + dpaa2_hash_fields[i].cls_prot; + key->extract.from_hdr.type = DPKG_FULL_FIELD; + key->extract.from_hdr.field = + dpaa2_hash_fields[i].cls_field; + cls_cfg.num_extracts++; + + enabled_flags |= dpaa2_hash_fields[i].rxnfc_field; + } + + dma_mem = kzalloc(DPAA2_CLASSIFIER_DMA_SIZE, GFP_DMA | GFP_KERNEL); + if (!dma_mem) + return -ENOMEM; + + err = dpni_prepare_key_cfg(&cls_cfg, dma_mem); + if (err) { + dev_err(dev, "dpni_prepare_key_cfg error %d", err); + return err; + } + + memset(&dist_cfg, 0, sizeof(dist_cfg)); + + /* Prepare for setting the rx dist */ + dist_cfg.key_cfg_iova = dma_map_single(net_dev->dev.parent, dma_mem, + DPAA2_CLASSIFIER_DMA_SIZE, + DMA_TO_DEVICE); + if (dma_mapping_error(net_dev->dev.parent, dist_cfg.key_cfg_iova)) { + dev_err(dev, "DMA mapping failed\n"); + kfree(dma_mem); + return -ENOMEM; + } + + dist_cfg.dist_size = dpaa2_queue_count(priv); + if (dpaa2_eth_fs_enabled(priv)) { + dist_cfg.dist_mode = DPNI_DIST_MODE_FS; + dist_cfg.fs_cfg.miss_action = DPNI_FS_MISS_HASH; + } else { + dist_cfg.dist_mode = DPNI_DIST_MODE_HASH; + } + + err = dpni_set_rx_tc_dist(priv->mc_io, 0, priv->mc_token, 0, &dist_cfg); + dma_unmap_single(net_dev->dev.parent, dist_cfg.key_cfg_iova, + DPAA2_CLASSIFIER_DMA_SIZE, DMA_TO_DEVICE); + kfree(dma_mem); + if (err) { + dev_err(dev, "dpni_set_rx_tc_dist() error %d\n", err); + return err; + } + + priv->rx_hash_fields = enabled_flags; + + return 0; +} + +static int dpaa2_cls_prep_rule(struct net_device *net_dev, + struct ethtool_rx_flow_spec *fs, + void *key) +{ + struct ethtool_tcpip4_spec *l4ip4_h, *l4ip4_m; + struct ethhdr *eth_h, *eth_m; + struct ethtool_flow_ext *ext_h, *ext_m; + const u8 key_size = dpaa2_cls_key_size(net_dev); + void *msk = key + key_size; + + memset(key, 0, key_size * 2); + + /* This code is a major mess, it has to be cleaned up after the + * classification mask issue is fixed and key format will be made static + */ + + switch (fs->flow_type & 0xff) { + case TCP_V4_FLOW: + l4ip4_h = &fs->h_u.tcp_ip4_spec; + l4ip4_m = &fs->m_u.tcp_ip4_spec; + /* TODO: ethertype to match IPv4 and protocol to match TCP */ + goto l4ip4; + + case UDP_V4_FLOW: + l4ip4_h = &fs->h_u.udp_ip4_spec; + l4ip4_m = &fs->m_u.udp_ip4_spec; + goto l4ip4; + + case SCTP_V4_FLOW: + l4ip4_h = &fs->h_u.sctp_ip4_spec; + l4ip4_m = &fs->m_u.sctp_ip4_spec; + +l4ip4: + if (l4ip4_m->tos) { + netdev_err(net_dev, + "ToS is not supported for IPv4 L4\n"); + return -EOPNOTSUPP; + } + if (l4ip4_m->ip4src && + !dpaa2_cls_is_enabled(net_dev, RXH_IP_SRC)) { + netdev_err(net_dev, "IP SRC not supported!\n"); + return -EOPNOTSUPP; + } + if (l4ip4_m->ip4dst && + !dpaa2_cls_is_enabled(net_dev, RXH_IP_DST)) { + netdev_err(net_dev, "IP DST not supported!\n"); + return -EOPNOTSUPP; + } + if (l4ip4_m->psrc && + !dpaa2_cls_is_enabled(net_dev, RXH_L4_B_0_1)) { + netdev_err(net_dev, "PSRC not supported, ignored\n"); + return -EOPNOTSUPP; + } + if (l4ip4_m->pdst && + !dpaa2_cls_is_enabled(net_dev, RXH_L4_B_2_3)) { + netdev_err(net_dev, "PDST not supported, ignored\n"); + return -EOPNOTSUPP; + } + + if (dpaa2_cls_is_enabled(net_dev, RXH_IP_SRC)) { + *(u32 *)(key + dpaa2_cls_key_off(net_dev, RXH_IP_SRC)) + = l4ip4_h->ip4src; + *(u32 *)(msk + dpaa2_cls_key_off(net_dev, RXH_IP_SRC)) + = l4ip4_m->ip4src; + } + if (dpaa2_cls_is_enabled(net_dev, RXH_IP_DST)) { + *(u32 *)(key + dpaa2_cls_key_off(net_dev, RXH_IP_DST)) + = l4ip4_h->ip4dst; + *(u32 *)(msk + dpaa2_cls_key_off(net_dev, RXH_IP_DST)) + = l4ip4_m->ip4dst; + } + + if (dpaa2_cls_is_enabled(net_dev, RXH_L4_B_0_1)) { + *(u32 *)(key + dpaa2_cls_key_off(net_dev, RXH_L4_B_0_1)) + = l4ip4_h->psrc; + *(u32 *)(msk + dpaa2_cls_key_off(net_dev, RXH_L4_B_0_1)) + = l4ip4_m->psrc; + } + + if (dpaa2_cls_is_enabled(net_dev, RXH_L4_B_2_3)) { + *(u32 *)(key + dpaa2_cls_key_off(net_dev, RXH_L4_B_2_3)) + = l4ip4_h->pdst; + *(u32 *)(msk + dpaa2_cls_key_off(net_dev, RXH_L4_B_2_3)) + = l4ip4_m->pdst; + } + break; + + case ETHER_FLOW: + eth_h = &fs->h_u.ether_spec; + eth_m = &fs->m_u.ether_spec; + + if (eth_m->h_proto) { + netdev_err(net_dev, "Ethertype is not supported!\n"); + return -EOPNOTSUPP; + } + + if (!is_zero_ether_addr(eth_m->h_source)) { + netdev_err(net_dev, "ETH SRC is not supported!\n"); + return -EOPNOTSUPP; + } + + if (dpaa2_cls_is_enabled(net_dev, RXH_L2DA)) { + ether_addr_copy(key + + dpaa2_cls_key_off(net_dev, RXH_L2DA), + eth_h->h_dest); + ether_addr_copy(msk + + dpaa2_cls_key_off(net_dev, RXH_L2DA), + eth_m->h_dest); + } else { + if (!is_zero_ether_addr(eth_m->h_dest)) { + netdev_err(net_dev, + "ETH DST is not supported!\n"); + return -EOPNOTSUPP; + } + } + break; + + default: + /* TODO: IP user flow, AH, ESP */ + return -EOPNOTSUPP; + } + + if (fs->flow_type & FLOW_EXT) { + /* TODO: ETH data, VLAN ethertype, VLAN TCI .. */ + return -EOPNOTSUPP; + } + + if (fs->flow_type & FLOW_MAC_EXT) { + ext_h = &fs->h_ext; + ext_m = &fs->m_ext; + + if (dpaa2_cls_is_enabled(net_dev, RXH_L2DA)) { + ether_addr_copy(key + + dpaa2_cls_key_off(net_dev, RXH_L2DA), + ext_h->h_dest); + ether_addr_copy(msk + + dpaa2_cls_key_off(net_dev, RXH_L2DA), + ext_m->h_dest); + } else { + if (!is_zero_ether_addr(ext_m->h_dest)) { + netdev_err(net_dev, + "ETH DST is not supported!\n"); + return -EOPNOTSUPP; + } + } + } + return 0; +} + +static int dpaa2_do_cls(struct net_device *net_dev, + struct ethtool_rx_flow_spec *fs, + bool add) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + const int rule_cnt = DPAA2_CLASSIFIER_ENTRY_COUNT; + struct dpni_rule_cfg rule_cfg; + void *dma_mem; + int err = 0; + + if (!dpaa2_eth_fs_enabled(priv)) { + netdev_err(net_dev, "dev does not support steering!\n"); + /* dev doesn't support steering */ + return -EOPNOTSUPP; + } + + if ((fs->ring_cookie != RX_CLS_FLOW_DISC && + fs->ring_cookie >= dpaa2_queue_count(priv)) || + fs->location >= rule_cnt) + return -EINVAL; + + memset(&rule_cfg, 0, sizeof(rule_cfg)); + rule_cfg.key_size = dpaa2_cls_key_size(net_dev); + + /* allocate twice the key size, for the actual key and for mask */ + dma_mem = kzalloc(rule_cfg.key_size * 2, GFP_DMA | GFP_KERNEL); + if (!dma_mem) + return -ENOMEM; + + err = dpaa2_cls_prep_rule(net_dev, fs, dma_mem); + if (err) + goto err_free_mem; + + rule_cfg.key_iova = dma_map_single(net_dev->dev.parent, dma_mem, + rule_cfg.key_size * 2, + DMA_TO_DEVICE); + + rule_cfg.mask_iova = rule_cfg.key_iova + rule_cfg.key_size; + + if (!(priv->dpni_attrs.options & DPNI_OPT_FS_MASK_SUPPORT)) { + int i; + u8 *mask = dma_mem + rule_cfg.key_size; + + /* check that nothing is masked out, otherwise it won't work */ + for (i = 0; i < rule_cfg.key_size; i++) { + if (mask[i] == 0xff) + continue; + netdev_err(net_dev, "dev does not support masking!\n"); + err = -EOPNOTSUPP; + goto err_free_mem; + } + rule_cfg.mask_iova = 0; + } + + /* No way to control rule order in firmware */ + if (add) + err = dpni_add_fs_entry(priv->mc_io, 0, priv->mc_token, 0, + &rule_cfg, (u16)fs->ring_cookie); + else + err = dpni_remove_fs_entry(priv->mc_io, 0, priv->mc_token, 0, + &rule_cfg); + + dma_unmap_single(net_dev->dev.parent, rule_cfg.key_iova, + rule_cfg.key_size * 2, DMA_TO_DEVICE); + if (err) { + netdev_err(net_dev, "dpaa2_add_cls() error %d\n", err); + goto err_free_mem; + } + + priv->cls_rule[fs->location].fs = *fs; + priv->cls_rule[fs->location].in_use = true; + +err_free_mem: + kfree(dma_mem); + + return err; +} + +static int dpaa2_add_cls(struct net_device *net_dev, + struct ethtool_rx_flow_spec *fs) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + int err; + + err = dpaa2_do_cls(net_dev, fs, true); + if (err) + return err; + + priv->cls_rule[fs->location].in_use = true; + priv->cls_rule[fs->location].fs = *fs; + + return 0; +} + +static int dpaa2_del_cls(struct net_device *net_dev, int location) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + int err; + + err = dpaa2_do_cls(net_dev, &priv->cls_rule[location].fs, false); + if (err) + return err; + + priv->cls_rule[location].in_use = false; + + return 0; +} + +static void dpaa2_clear_cls(struct net_device *net_dev) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + int i, err; + + for (i = 0; i < DPAA2_CLASSIFIER_ENTRY_COUNT; i++) { + if (!priv->cls_rule[i].in_use) + continue; + + err = dpaa2_del_cls(net_dev, i); + if (err) + netdev_warn(net_dev, + "err trying to delete classification entry %d\n", + i); + } +} + +static int dpaa2_set_rxnfc(struct net_device *net_dev, + struct ethtool_rxnfc *rxnfc) +{ + int err = 0; + + switch (rxnfc->cmd) { + case ETHTOOL_SRXFH: + /* first off clear ALL classification rules, chaging key + * composition will break them anyway + */ + dpaa2_clear_cls(net_dev); + /* we purposely ignore cmd->flow_type for now, because the + * classifier only supports a single set of fields for all + * protocols + */ + err = dpaa2_set_hash(net_dev, rxnfc->data); + break; + case ETHTOOL_SRXCLSRLINS: + err = dpaa2_add_cls(net_dev, &rxnfc->fs); + break; + + case ETHTOOL_SRXCLSRLDEL: + err = dpaa2_del_cls(net_dev, rxnfc->fs.location); + break; + + default: + err = -EOPNOTSUPP; + } + + return err; +} + +static int dpaa2_get_rxnfc(struct net_device *net_dev, + struct ethtool_rxnfc *rxnfc, u32 *rule_locs) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + const int rule_cnt = DPAA2_CLASSIFIER_ENTRY_COUNT; + int i, j; + + switch (rxnfc->cmd) { + case ETHTOOL_GRXFH: + /* we purposely ignore cmd->flow_type for now, because the + * classifier only supports a single set of fields for all + * protocols + */ + rxnfc->data = priv->rx_hash_fields; + break; + + case ETHTOOL_GRXRINGS: + rxnfc->data = dpaa2_queue_count(priv); + break; + + case ETHTOOL_GRXCLSRLCNT: + for (i = 0, rxnfc->rule_cnt = 0; i < rule_cnt; i++) + if (priv->cls_rule[i].in_use) + rxnfc->rule_cnt++; + rxnfc->data = rule_cnt; + break; + + case ETHTOOL_GRXCLSRULE: + if (!priv->cls_rule[rxnfc->fs.location].in_use) + return -EINVAL; + + rxnfc->fs = priv->cls_rule[rxnfc->fs.location].fs; + break; + + case ETHTOOL_GRXCLSRLALL: + for (i = 0, j = 0; i < rule_cnt; i++) { + if (!priv->cls_rule[i].in_use) + continue; + if (j == rxnfc->rule_cnt) + return -EMSGSIZE; + rule_locs[j++] = i; + } + rxnfc->rule_cnt = j; + rxnfc->data = rule_cnt; + break; + + default: + return -EOPNOTSUPP; + } + + return 0; +} + +const struct ethtool_ops dpaa2_ethtool_ops = { + .get_drvinfo = dpaa2_get_drvinfo, + .get_msglevel = dpaa2_get_msglevel, + .set_msglevel = dpaa2_set_msglevel, + .get_link = ethtool_op_get_link, + .get_settings = dpaa2_get_settings, + .set_settings = dpaa2_set_settings, + .get_sset_count = dpaa2_get_sset_count, + .get_ethtool_stats = dpaa2_get_ethtool_stats, + .get_strings = dpaa2_get_strings, + .get_rxnfc = dpaa2_get_rxnfc, + .set_rxnfc = dpaa2_set_rxnfc, +}; --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethernet/dpkg.h @@ -0,0 +1,175 @@ +/* Copyright 2013-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __FSL_DPKG_H_ +#define __FSL_DPKG_H_ + +#include +#include "../../fsl-mc/include/net.h" + +/* Data Path Key Generator API + * Contains initialization APIs and runtime APIs for the Key Generator + */ + +/** Key Generator properties */ + +/** + * Number of masks per key extraction + */ +#define DPKG_NUM_OF_MASKS 4 +/** + * Number of extractions per key profile + */ +#define DPKG_MAX_NUM_OF_EXTRACTS 10 + +/** + * enum dpkg_extract_from_hdr_type - Selecting extraction by header types + * @DPKG_FROM_HDR: Extract selected bytes from header, by offset + * @DPKG_FROM_FIELD: Extract selected bytes from header, by offset from field + * @DPKG_FULL_FIELD: Extract a full field + */ +enum dpkg_extract_from_hdr_type { + DPKG_FROM_HDR = 0, + DPKG_FROM_FIELD = 1, + DPKG_FULL_FIELD = 2 +}; + +/** + * enum dpkg_extract_type - Enumeration for selecting extraction type + * @DPKG_EXTRACT_FROM_HDR: Extract from the header + * @DPKG_EXTRACT_FROM_DATA: Extract from data not in specific header + * @DPKG_EXTRACT_FROM_PARSE: Extract from parser-result; + * e.g. can be used to extract header existence; + * please refer to 'Parse Result definition' section in the parser BG + */ +enum dpkg_extract_type { + DPKG_EXTRACT_FROM_HDR = 0, + DPKG_EXTRACT_FROM_DATA = 1, + DPKG_EXTRACT_FROM_PARSE = 3 +}; + +/** + * struct dpkg_mask - A structure for defining a single extraction mask + * @mask: Byte mask for the extracted content + * @offset: Offset within the extracted content + */ +struct dpkg_mask { + uint8_t mask; + uint8_t offset; +}; + +/** + * struct dpkg_extract - A structure for defining a single extraction + * @type: Determines how the union below is interpreted: + * DPKG_EXTRACT_FROM_HDR: selects 'from_hdr'; + * DPKG_EXTRACT_FROM_DATA: selects 'from_data'; + * DPKG_EXTRACT_FROM_PARSE: selects 'from_parse' + * @extract: Selects extraction method + * @num_of_byte_masks: Defines the number of valid entries in the array below; + * This is also the number of bytes to be used as masks + * @masks: Masks parameters + */ +struct dpkg_extract { + enum dpkg_extract_type type; + /** + * union extract - Selects extraction method + * @from_hdr - Used when 'type = DPKG_EXTRACT_FROM_HDR' + * @from_data - Used when 'type = DPKG_EXTRACT_FROM_DATA' + * @from_parse - Used when 'type = DPKG_EXTRACT_FROM_PARSE' + */ + union { + /** + * struct from_hdr - Used when 'type = DPKG_EXTRACT_FROM_HDR' + * @prot: Any of the supported headers + * @type: Defines the type of header extraction: + * DPKG_FROM_HDR: use size & offset below; + * DPKG_FROM_FIELD: use field, size and offset below; + * DPKG_FULL_FIELD: use field below + * @field: One of the supported fields (NH_FLD_) + * + * @size: Size in bytes + * @offset: Byte offset + * @hdr_index: Clear for cases not listed below; + * Used for protocols that may have more than a single + * header, 0 indicates an outer header; + * Supported protocols (possible values): + * NET_PROT_VLAN (0, HDR_INDEX_LAST); + * NET_PROT_MPLS (0, 1, HDR_INDEX_LAST); + * NET_PROT_IP(0, HDR_INDEX_LAST); + * NET_PROT_IPv4(0, HDR_INDEX_LAST); + * NET_PROT_IPv6(0, HDR_INDEX_LAST); + */ + + struct { + enum net_prot prot; + enum dpkg_extract_from_hdr_type type; + uint32_t field; + uint8_t size; + uint8_t offset; + uint8_t hdr_index; + } from_hdr; + /** + * struct from_data - Used when 'type = DPKG_EXTRACT_FROM_DATA' + * @size: Size in bytes + * @offset: Byte offset + */ + struct { + uint8_t size; + uint8_t offset; + } from_data; + + /** + * struct from_parse - Used when 'type = DPKG_EXTRACT_FROM_PARSE' + * @size: Size in bytes + * @offset: Byte offset + */ + struct { + uint8_t size; + uint8_t offset; + } from_parse; + } extract; + + uint8_t num_of_byte_masks; + struct dpkg_mask masks[DPKG_NUM_OF_MASKS]; +}; + +/** + * struct dpkg_profile_cfg - A structure for defining a full Key Generation + * profile (rule) + * @num_extracts: Defines the number of valid entries in the array below + * @extracts: Array of required extractions + */ +struct dpkg_profile_cfg { + uint8_t num_extracts; + struct dpkg_extract extracts[DPKG_MAX_NUM_OF_EXTRACTS]; +}; + +#endif /* __FSL_DPKG_H_ */ --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h @@ -0,0 +1,1058 @@ +/* Copyright 2013-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _FSL_DPNI_CMD_H +#define _FSL_DPNI_CMD_H + +/* DPNI Version */ +#define DPNI_VER_MAJOR 6 +#define DPNI_VER_MINOR 0 + +/* Command IDs */ +#define DPNI_CMDID_OPEN 0x801 +#define DPNI_CMDID_CLOSE 0x800 +#define DPNI_CMDID_CREATE 0x901 +#define DPNI_CMDID_DESTROY 0x900 + +#define DPNI_CMDID_ENABLE 0x002 +#define DPNI_CMDID_DISABLE 0x003 +#define DPNI_CMDID_GET_ATTR 0x004 +#define DPNI_CMDID_RESET 0x005 +#define DPNI_CMDID_IS_ENABLED 0x006 + +#define DPNI_CMDID_SET_IRQ 0x010 +#define DPNI_CMDID_GET_IRQ 0x011 +#define DPNI_CMDID_SET_IRQ_ENABLE 0x012 +#define DPNI_CMDID_GET_IRQ_ENABLE 0x013 +#define DPNI_CMDID_SET_IRQ_MASK 0x014 +#define DPNI_CMDID_GET_IRQ_MASK 0x015 +#define DPNI_CMDID_GET_IRQ_STATUS 0x016 +#define DPNI_CMDID_CLEAR_IRQ_STATUS 0x017 + +#define DPNI_CMDID_SET_POOLS 0x200 +#define DPNI_CMDID_GET_RX_BUFFER_LAYOUT 0x201 +#define DPNI_CMDID_SET_RX_BUFFER_LAYOUT 0x202 +#define DPNI_CMDID_GET_TX_BUFFER_LAYOUT 0x203 +#define DPNI_CMDID_SET_TX_BUFFER_LAYOUT 0x204 +#define DPNI_CMDID_SET_TX_CONF_BUFFER_LAYOUT 0x205 +#define DPNI_CMDID_GET_TX_CONF_BUFFER_LAYOUT 0x206 +#define DPNI_CMDID_SET_L3_CHKSUM_VALIDATION 0x207 +#define DPNI_CMDID_GET_L3_CHKSUM_VALIDATION 0x208 +#define DPNI_CMDID_SET_L4_CHKSUM_VALIDATION 0x209 +#define DPNI_CMDID_GET_L4_CHKSUM_VALIDATION 0x20A +#define DPNI_CMDID_SET_ERRORS_BEHAVIOR 0x20B +#define DPNI_CMDID_SET_TX_CONF_REVOKE 0x20C + +#define DPNI_CMDID_GET_QDID 0x210 +#define DPNI_CMDID_GET_SP_INFO 0x211 +#define DPNI_CMDID_GET_TX_DATA_OFFSET 0x212 +#define DPNI_CMDID_GET_COUNTER 0x213 +#define DPNI_CMDID_SET_COUNTER 0x214 +#define DPNI_CMDID_GET_LINK_STATE 0x215 +#define DPNI_CMDID_SET_MAX_FRAME_LENGTH 0x216 +#define DPNI_CMDID_GET_MAX_FRAME_LENGTH 0x217 +#define DPNI_CMDID_SET_MTU 0x218 +#define DPNI_CMDID_GET_MTU 0x219 +#define DPNI_CMDID_SET_LINK_CFG 0x21A +#define DPNI_CMDID_SET_TX_SHAPING 0x21B + +#define DPNI_CMDID_SET_MCAST_PROMISC 0x220 +#define DPNI_CMDID_GET_MCAST_PROMISC 0x221 +#define DPNI_CMDID_SET_UNICAST_PROMISC 0x222 +#define DPNI_CMDID_GET_UNICAST_PROMISC 0x223 +#define DPNI_CMDID_SET_PRIM_MAC 0x224 +#define DPNI_CMDID_GET_PRIM_MAC 0x225 +#define DPNI_CMDID_ADD_MAC_ADDR 0x226 +#define DPNI_CMDID_REMOVE_MAC_ADDR 0x227 +#define DPNI_CMDID_CLR_MAC_FILTERS 0x228 + +#define DPNI_CMDID_SET_VLAN_FILTERS 0x230 +#define DPNI_CMDID_ADD_VLAN_ID 0x231 +#define DPNI_CMDID_REMOVE_VLAN_ID 0x232 +#define DPNI_CMDID_CLR_VLAN_FILTERS 0x233 + +#define DPNI_CMDID_SET_RX_TC_DIST 0x235 +#define DPNI_CMDID_SET_TX_FLOW 0x236 +#define DPNI_CMDID_GET_TX_FLOW 0x237 +#define DPNI_CMDID_SET_RX_FLOW 0x238 +#define DPNI_CMDID_GET_RX_FLOW 0x239 +#define DPNI_CMDID_SET_RX_ERR_QUEUE 0x23A +#define DPNI_CMDID_GET_RX_ERR_QUEUE 0x23B + +#define DPNI_CMDID_SET_RX_TC_POLICING 0x23E +#define DPNI_CMDID_SET_RX_TC_EARLY_DROP 0x23F + +#define DPNI_CMDID_SET_QOS_TBL 0x240 +#define DPNI_CMDID_ADD_QOS_ENT 0x241 +#define DPNI_CMDID_REMOVE_QOS_ENT 0x242 +#define DPNI_CMDID_CLR_QOS_TBL 0x243 +#define DPNI_CMDID_ADD_FS_ENT 0x244 +#define DPNI_CMDID_REMOVE_FS_ENT 0x245 +#define DPNI_CMDID_CLR_FS_ENT 0x246 +#define DPNI_CMDID_SET_VLAN_INSERTION 0x247 +#define DPNI_CMDID_SET_VLAN_REMOVAL 0x248 +#define DPNI_CMDID_SET_IPR 0x249 +#define DPNI_CMDID_SET_IPF 0x24A + +#define DPNI_CMDID_SET_TX_SELECTION 0x250 +#define DPNI_CMDID_GET_RX_TC_POLICING 0x251 +#define DPNI_CMDID_GET_RX_TC_EARLY_DROP 0x252 +#define DPNI_CMDID_SET_RX_TC_CONGESTION_NOTIFICATION 0x253 +#define DPNI_CMDID_GET_RX_TC_CONGESTION_NOTIFICATION 0x254 +#define DPNI_CMDID_SET_TX_TC_CONGESTION_NOTIFICATION 0x255 +#define DPNI_CMDID_GET_TX_TC_CONGESTION_NOTIFICATION 0x256 +#define DPNI_CMDID_SET_TX_CONF 0x257 +#define DPNI_CMDID_GET_TX_CONF 0x258 +#define DPNI_CMDID_SET_TX_CONF_CONGESTION_NOTIFICATION 0x259 +#define DPNI_CMDID_GET_TX_CONF_CONGESTION_NOTIFICATION 0x25A +#define DPNI_CMDID_SET_TX_TC_EARLY_DROP 0x25B +#define DPNI_CMDID_GET_TX_TC_EARLY_DROP 0x25C + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_OPEN(cmd, dpni_id) \ + MC_CMD_OP(cmd, 0, 0, 32, int, dpni_id) + +#define DPNI_PREP_EXTENDED_CFG(ext, cfg) \ +do { \ + MC_PREP_OP(ext, 0, 0, 16, uint16_t, cfg->tc_cfg[0].max_dist); \ + MC_PREP_OP(ext, 0, 16, 16, uint16_t, cfg->tc_cfg[0].max_fs_entries); \ + MC_PREP_OP(ext, 0, 32, 16, uint16_t, cfg->tc_cfg[1].max_dist); \ + MC_PREP_OP(ext, 0, 48, 16, uint16_t, cfg->tc_cfg[1].max_fs_entries); \ + MC_PREP_OP(ext, 1, 0, 16, uint16_t, cfg->tc_cfg[2].max_dist); \ + MC_PREP_OP(ext, 1, 16, 16, uint16_t, cfg->tc_cfg[2].max_fs_entries); \ + MC_PREP_OP(ext, 1, 32, 16, uint16_t, cfg->tc_cfg[3].max_dist); \ + MC_PREP_OP(ext, 1, 48, 16, uint16_t, cfg->tc_cfg[3].max_fs_entries); \ + MC_PREP_OP(ext, 2, 0, 16, uint16_t, cfg->tc_cfg[4].max_dist); \ + MC_PREP_OP(ext, 2, 16, 16, uint16_t, cfg->tc_cfg[4].max_fs_entries); \ + MC_PREP_OP(ext, 2, 32, 16, uint16_t, cfg->tc_cfg[5].max_dist); \ + MC_PREP_OP(ext, 2, 48, 16, uint16_t, cfg->tc_cfg[5].max_fs_entries); \ + MC_PREP_OP(ext, 3, 0, 16, uint16_t, cfg->tc_cfg[6].max_dist); \ + MC_PREP_OP(ext, 3, 16, 16, uint16_t, cfg->tc_cfg[6].max_fs_entries); \ + MC_PREP_OP(ext, 3, 32, 16, uint16_t, cfg->tc_cfg[7].max_dist); \ + MC_PREP_OP(ext, 3, 48, 16, uint16_t, cfg->tc_cfg[7].max_fs_entries); \ + MC_PREP_OP(ext, 4, 0, 16, uint16_t, \ + cfg->ipr_cfg.max_open_frames_ipv4); \ + MC_PREP_OP(ext, 4, 16, 16, uint16_t, \ + cfg->ipr_cfg.max_open_frames_ipv6); \ + MC_PREP_OP(ext, 4, 32, 16, uint16_t, \ + cfg->ipr_cfg.max_reass_frm_size); \ + MC_PREP_OP(ext, 5, 0, 16, uint16_t, \ + cfg->ipr_cfg.min_frag_size_ipv4); \ + MC_PREP_OP(ext, 5, 16, 16, uint16_t, \ + cfg->ipr_cfg.min_frag_size_ipv6); \ +} while (0) + +#define DPNI_EXT_EXTENDED_CFG(ext, cfg) \ +do { \ + MC_EXT_OP(ext, 0, 0, 16, uint16_t, cfg->tc_cfg[0].max_dist); \ + MC_EXT_OP(ext, 0, 16, 16, uint16_t, cfg->tc_cfg[0].max_fs_entries); \ + MC_EXT_OP(ext, 0, 32, 16, uint16_t, cfg->tc_cfg[1].max_dist); \ + MC_EXT_OP(ext, 0, 48, 16, uint16_t, cfg->tc_cfg[1].max_fs_entries); \ + MC_EXT_OP(ext, 1, 0, 16, uint16_t, cfg->tc_cfg[2].max_dist); \ + MC_EXT_OP(ext, 1, 16, 16, uint16_t, cfg->tc_cfg[2].max_fs_entries); \ + MC_EXT_OP(ext, 1, 32, 16, uint16_t, cfg->tc_cfg[3].max_dist); \ + MC_EXT_OP(ext, 1, 48, 16, uint16_t, cfg->tc_cfg[3].max_fs_entries); \ + MC_EXT_OP(ext, 2, 0, 16, uint16_t, cfg->tc_cfg[4].max_dist); \ + MC_EXT_OP(ext, 2, 16, 16, uint16_t, cfg->tc_cfg[4].max_fs_entries); \ + MC_EXT_OP(ext, 2, 32, 16, uint16_t, cfg->tc_cfg[5].max_dist); \ + MC_EXT_OP(ext, 2, 48, 16, uint16_t, cfg->tc_cfg[5].max_fs_entries); \ + MC_EXT_OP(ext, 3, 0, 16, uint16_t, cfg->tc_cfg[6].max_dist); \ + MC_EXT_OP(ext, 3, 16, 16, uint16_t, cfg->tc_cfg[6].max_fs_entries); \ + MC_EXT_OP(ext, 3, 32, 16, uint16_t, cfg->tc_cfg[7].max_dist); \ + MC_EXT_OP(ext, 3, 48, 16, uint16_t, cfg->tc_cfg[7].max_fs_entries); \ + MC_EXT_OP(ext, 4, 0, 16, uint16_t, \ + cfg->ipr_cfg.max_open_frames_ipv4); \ + MC_EXT_OP(ext, 4, 16, 16, uint16_t, \ + cfg->ipr_cfg.max_open_frames_ipv6); \ + MC_EXT_OP(ext, 4, 32, 16, uint16_t, \ + cfg->ipr_cfg.max_reass_frm_size); \ + MC_EXT_OP(ext, 5, 0, 16, uint16_t, \ + cfg->ipr_cfg.min_frag_size_ipv4); \ + MC_EXT_OP(ext, 5, 16, 16, uint16_t, \ + cfg->ipr_cfg.min_frag_size_ipv6); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_CREATE(cmd, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 8, uint8_t, cfg->adv.max_tcs); \ + MC_CMD_OP(cmd, 0, 8, 8, uint8_t, cfg->adv.max_senders); \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, cfg->mac_addr[5]); \ + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, cfg->mac_addr[4]); \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, cfg->mac_addr[3]); \ + MC_CMD_OP(cmd, 0, 40, 8, uint8_t, cfg->mac_addr[2]); \ + MC_CMD_OP(cmd, 0, 48, 8, uint8_t, cfg->mac_addr[1]); \ + MC_CMD_OP(cmd, 0, 56, 8, uint8_t, cfg->mac_addr[0]); \ + MC_CMD_OP(cmd, 1, 0, 32, uint32_t, cfg->adv.options); \ + MC_CMD_OP(cmd, 2, 0, 8, uint8_t, cfg->adv.max_unicast_filters); \ + MC_CMD_OP(cmd, 2, 8, 8, uint8_t, cfg->adv.max_multicast_filters); \ + MC_CMD_OP(cmd, 2, 16, 8, uint8_t, cfg->adv.max_vlan_filters); \ + MC_CMD_OP(cmd, 2, 24, 8, uint8_t, cfg->adv.max_qos_entries); \ + MC_CMD_OP(cmd, 2, 32, 8, uint8_t, cfg->adv.max_qos_key_size); \ + MC_CMD_OP(cmd, 2, 48, 8, uint8_t, cfg->adv.max_dist_key_size); \ + MC_CMD_OP(cmd, 2, 56, 8, enum net_prot, cfg->adv.start_hdr); \ + MC_CMD_OP(cmd, 4, 48, 8, uint8_t, cfg->adv.max_policers); \ + MC_CMD_OP(cmd, 4, 56, 8, uint8_t, cfg->adv.max_congestion_ctrl); \ + MC_CMD_OP(cmd, 5, 0, 64, uint64_t, cfg->adv.ext_cfg_iova); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_POOLS(cmd, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 8, uint8_t, cfg->num_dpbp); \ + MC_CMD_OP(cmd, 0, 8, 1, int, cfg->pools[0].backup_pool); \ + MC_CMD_OP(cmd, 0, 9, 1, int, cfg->pools[1].backup_pool); \ + MC_CMD_OP(cmd, 0, 10, 1, int, cfg->pools[2].backup_pool); \ + MC_CMD_OP(cmd, 0, 11, 1, int, cfg->pools[3].backup_pool); \ + MC_CMD_OP(cmd, 0, 12, 1, int, cfg->pools[4].backup_pool); \ + MC_CMD_OP(cmd, 0, 13, 1, int, cfg->pools[5].backup_pool); \ + MC_CMD_OP(cmd, 0, 14, 1, int, cfg->pools[6].backup_pool); \ + MC_CMD_OP(cmd, 0, 15, 1, int, cfg->pools[7].backup_pool); \ + MC_CMD_OP(cmd, 0, 32, 32, int, cfg->pools[0].dpbp_id); \ + MC_CMD_OP(cmd, 4, 32, 16, uint16_t, cfg->pools[0].buffer_size);\ + MC_CMD_OP(cmd, 1, 0, 32, int, cfg->pools[1].dpbp_id); \ + MC_CMD_OP(cmd, 4, 48, 16, uint16_t, cfg->pools[1].buffer_size);\ + MC_CMD_OP(cmd, 1, 32, 32, int, cfg->pools[2].dpbp_id); \ + MC_CMD_OP(cmd, 5, 0, 16, uint16_t, cfg->pools[2].buffer_size);\ + MC_CMD_OP(cmd, 2, 0, 32, int, cfg->pools[3].dpbp_id); \ + MC_CMD_OP(cmd, 5, 16, 16, uint16_t, cfg->pools[3].buffer_size);\ + MC_CMD_OP(cmd, 2, 32, 32, int, cfg->pools[4].dpbp_id); \ + MC_CMD_OP(cmd, 5, 32, 16, uint16_t, cfg->pools[4].buffer_size);\ + MC_CMD_OP(cmd, 3, 0, 32, int, cfg->pools[5].dpbp_id); \ + MC_CMD_OP(cmd, 5, 48, 16, uint16_t, cfg->pools[5].buffer_size);\ + MC_CMD_OP(cmd, 3, 32, 32, int, cfg->pools[6].dpbp_id); \ + MC_CMD_OP(cmd, 6, 0, 16, uint16_t, cfg->pools[6].buffer_size);\ + MC_CMD_OP(cmd, 4, 0, 32, int, cfg->pools[7].dpbp_id); \ + MC_CMD_OP(cmd, 6, 16, 16, uint16_t, cfg->pools[7].buffer_size);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_IS_ENABLED(cmd, en) \ + MC_RSP_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_IRQ(cmd, irq_index, irq_cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 32, uint32_t, irq_cfg->val); \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index); \ + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, irq_cfg->addr); \ + MC_CMD_OP(cmd, 2, 0, 32, int, irq_cfg->irq_num); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_GET_IRQ(cmd, irq_index) \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_IRQ(cmd, type, irq_cfg) \ +do { \ + MC_RSP_OP(cmd, 0, 0, 32, uint32_t, irq_cfg->val); \ + MC_RSP_OP(cmd, 1, 0, 64, uint64_t, irq_cfg->addr); \ + MC_RSP_OP(cmd, 2, 0, 32, int, irq_cfg->irq_num); \ + MC_RSP_OP(cmd, 2, 32, 32, int, type); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_IRQ_ENABLE(cmd, irq_index, en) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 8, uint8_t, en); \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_GET_IRQ_ENABLE(cmd, irq_index) \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_IRQ_ENABLE(cmd, en) \ + MC_RSP_OP(cmd, 0, 0, 8, uint8_t, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_IRQ_MASK(cmd, irq_index, mask) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 32, uint32_t, mask); \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_GET_IRQ_MASK(cmd, irq_index) \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_IRQ_MASK(cmd, mask) \ + MC_RSP_OP(cmd, 0, 0, 32, uint32_t, mask) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_GET_IRQ_STATUS(cmd, irq_index, status) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 32, uint32_t, status);\ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_IRQ_STATUS(cmd, status) \ + MC_RSP_OP(cmd, 0, 0, 32, uint32_t, status) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_CLEAR_IRQ_STATUS(cmd, irq_index, status) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 32, uint32_t, status); \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_GET_ATTR(cmd, attr) \ + MC_CMD_OP(cmd, 6, 0, 64, uint64_t, attr->ext_cfg_iova) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_ATTR(cmd, attr) \ +do { \ + MC_RSP_OP(cmd, 0, 0, 32, int, attr->id);\ + MC_RSP_OP(cmd, 0, 32, 8, uint8_t, attr->max_tcs); \ + MC_RSP_OP(cmd, 0, 40, 8, uint8_t, attr->max_senders); \ + MC_RSP_OP(cmd, 0, 48, 8, enum net_prot, attr->start_hdr); \ + MC_RSP_OP(cmd, 1, 0, 32, uint32_t, attr->options); \ + MC_RSP_OP(cmd, 2, 0, 8, uint8_t, attr->max_unicast_filters); \ + MC_RSP_OP(cmd, 2, 8, 8, uint8_t, attr->max_multicast_filters);\ + MC_RSP_OP(cmd, 2, 16, 8, uint8_t, attr->max_vlan_filters); \ + MC_RSP_OP(cmd, 2, 24, 8, uint8_t, attr->max_qos_entries); \ + MC_RSP_OP(cmd, 2, 32, 8, uint8_t, attr->max_qos_key_size); \ + MC_RSP_OP(cmd, 2, 40, 8, uint8_t, attr->max_dist_key_size); \ + MC_RSP_OP(cmd, 4, 48, 8, uint8_t, attr->max_policers); \ + MC_RSP_OP(cmd, 4, 56, 8, uint8_t, attr->max_congestion_ctrl); \ + MC_RSP_OP(cmd, 5, 32, 16, uint16_t, attr->version.major);\ + MC_RSP_OP(cmd, 5, 48, 16, uint16_t, attr->version.minor);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_ERRORS_BEHAVIOR(cmd, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 32, uint32_t, cfg->errors); \ + MC_CMD_OP(cmd, 0, 32, 4, enum dpni_error_action, cfg->error_action); \ + MC_CMD_OP(cmd, 0, 36, 1, int, cfg->set_frame_annotation); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_RX_BUFFER_LAYOUT(cmd, layout) \ +do { \ + MC_RSP_OP(cmd, 0, 0, 16, uint16_t, layout->private_data_size); \ + MC_RSP_OP(cmd, 0, 16, 16, uint16_t, layout->data_align); \ + MC_RSP_OP(cmd, 1, 0, 1, int, layout->pass_timestamp); \ + MC_RSP_OP(cmd, 1, 1, 1, int, layout->pass_parser_result); \ + MC_RSP_OP(cmd, 1, 2, 1, int, layout->pass_frame_status); \ + MC_RSP_OP(cmd, 1, 16, 16, uint16_t, layout->data_head_room); \ + MC_RSP_OP(cmd, 1, 32, 16, uint16_t, layout->data_tail_room); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_RX_BUFFER_LAYOUT(cmd, layout) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, layout->private_data_size); \ + MC_CMD_OP(cmd, 0, 16, 16, uint16_t, layout->data_align); \ + MC_CMD_OP(cmd, 0, 32, 32, uint32_t, layout->options); \ + MC_CMD_OP(cmd, 1, 0, 1, int, layout->pass_timestamp); \ + MC_CMD_OP(cmd, 1, 1, 1, int, layout->pass_parser_result); \ + MC_CMD_OP(cmd, 1, 2, 1, int, layout->pass_frame_status); \ + MC_CMD_OP(cmd, 1, 16, 16, uint16_t, layout->data_head_room); \ + MC_CMD_OP(cmd, 1, 32, 16, uint16_t, layout->data_tail_room); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_TX_BUFFER_LAYOUT(cmd, layout) \ +do { \ + MC_RSP_OP(cmd, 0, 0, 16, uint16_t, layout->private_data_size); \ + MC_RSP_OP(cmd, 0, 16, 16, uint16_t, layout->data_align); \ + MC_RSP_OP(cmd, 1, 0, 1, int, layout->pass_timestamp); \ + MC_RSP_OP(cmd, 1, 1, 1, int, layout->pass_parser_result); \ + MC_RSP_OP(cmd, 1, 2, 1, int, layout->pass_frame_status); \ + MC_RSP_OP(cmd, 1, 16, 16, uint16_t, layout->data_head_room); \ + MC_RSP_OP(cmd, 1, 32, 16, uint16_t, layout->data_tail_room); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_TX_BUFFER_LAYOUT(cmd, layout) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, layout->private_data_size); \ + MC_CMD_OP(cmd, 0, 16, 16, uint16_t, layout->data_align); \ + MC_CMD_OP(cmd, 0, 32, 32, uint32_t, layout->options); \ + MC_CMD_OP(cmd, 1, 0, 1, int, layout->pass_timestamp); \ + MC_CMD_OP(cmd, 1, 1, 1, int, layout->pass_parser_result); \ + MC_CMD_OP(cmd, 1, 2, 1, int, layout->pass_frame_status); \ + MC_CMD_OP(cmd, 1, 16, 16, uint16_t, layout->data_head_room); \ + MC_CMD_OP(cmd, 1, 32, 16, uint16_t, layout->data_tail_room); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_TX_CONF_BUFFER_LAYOUT(cmd, layout) \ +do { \ + MC_RSP_OP(cmd, 0, 0, 16, uint16_t, layout->private_data_size); \ + MC_RSP_OP(cmd, 0, 16, 16, uint16_t, layout->data_align); \ + MC_RSP_OP(cmd, 1, 0, 1, int, layout->pass_timestamp); \ + MC_RSP_OP(cmd, 1, 1, 1, int, layout->pass_parser_result); \ + MC_RSP_OP(cmd, 1, 2, 1, int, layout->pass_frame_status); \ + MC_RSP_OP(cmd, 1, 16, 16, uint16_t, layout->data_head_room); \ + MC_RSP_OP(cmd, 1, 32, 16, uint16_t, layout->data_tail_room); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_TX_CONF_BUFFER_LAYOUT(cmd, layout) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, layout->private_data_size); \ + MC_CMD_OP(cmd, 0, 16, 16, uint16_t, layout->data_align); \ + MC_CMD_OP(cmd, 0, 32, 32, uint32_t, layout->options); \ + MC_CMD_OP(cmd, 1, 0, 1, int, layout->pass_timestamp); \ + MC_CMD_OP(cmd, 1, 1, 1, int, layout->pass_parser_result); \ + MC_CMD_OP(cmd, 1, 2, 1, int, layout->pass_frame_status); \ + MC_CMD_OP(cmd, 1, 16, 16, uint16_t, layout->data_head_room); \ + MC_CMD_OP(cmd, 1, 32, 16, uint16_t, layout->data_tail_room); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_L3_CHKSUM_VALIDATION(cmd, en) \ + MC_CMD_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_L3_CHKSUM_VALIDATION(cmd, en) \ + MC_RSP_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_L4_CHKSUM_VALIDATION(cmd, en) \ + MC_CMD_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_L4_CHKSUM_VALIDATION(cmd, en) \ + MC_RSP_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_QDID(cmd, qdid) \ + MC_RSP_OP(cmd, 0, 0, 16, uint16_t, qdid) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_SP_INFO(cmd, sp_info) \ +do { \ + MC_RSP_OP(cmd, 0, 0, 16, uint16_t, sp_info->spids[0]); \ + MC_RSP_OP(cmd, 0, 16, 16, uint16_t, sp_info->spids[1]); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_TX_DATA_OFFSET(cmd, data_offset) \ + MC_RSP_OP(cmd, 0, 0, 16, uint16_t, data_offset) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_GET_COUNTER(cmd, counter) \ + MC_CMD_OP(cmd, 0, 0, 16, enum dpni_counter, counter) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_COUNTER(cmd, value) \ + MC_RSP_OP(cmd, 1, 0, 64, uint64_t, value) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_COUNTER(cmd, counter, value) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 16, enum dpni_counter, counter); \ + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, value); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_LINK_CFG(cmd, cfg) \ +do { \ + MC_CMD_OP(cmd, 1, 0, 32, uint32_t, cfg->rate);\ + MC_CMD_OP(cmd, 2, 0, 64, uint64_t, cfg->options);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_LINK_STATE(cmd, state) \ +do { \ + MC_RSP_OP(cmd, 0, 32, 1, int, state->up);\ + MC_RSP_OP(cmd, 1, 0, 32, uint32_t, state->rate);\ + MC_RSP_OP(cmd, 2, 0, 64, uint64_t, state->options);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_TX_SHAPING(cmd, tx_shaper) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, tx_shaper->max_burst_size);\ + MC_CMD_OP(cmd, 1, 0, 32, uint32_t, tx_shaper->rate_limit);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_MAX_FRAME_LENGTH(cmd, max_frame_length) \ + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, max_frame_length) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_MAX_FRAME_LENGTH(cmd, max_frame_length) \ + MC_RSP_OP(cmd, 0, 0, 16, uint16_t, max_frame_length) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_MTU(cmd, mtu) \ + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, mtu) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_MTU(cmd, mtu) \ + MC_RSP_OP(cmd, 0, 0, 16, uint16_t, mtu) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_MULTICAST_PROMISC(cmd, en) \ + MC_CMD_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_MULTICAST_PROMISC(cmd, en) \ + MC_RSP_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_UNICAST_PROMISC(cmd, en) \ + MC_CMD_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_UNICAST_PROMISC(cmd, en) \ + MC_RSP_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_PRIMARY_MAC_ADDR(cmd, mac_addr) \ +do { \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, mac_addr[5]); \ + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, mac_addr[4]); \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, mac_addr[3]); \ + MC_CMD_OP(cmd, 0, 40, 8, uint8_t, mac_addr[2]); \ + MC_CMD_OP(cmd, 0, 48, 8, uint8_t, mac_addr[1]); \ + MC_CMD_OP(cmd, 0, 56, 8, uint8_t, mac_addr[0]); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_PRIMARY_MAC_ADDR(cmd, mac_addr) \ +do { \ + MC_RSP_OP(cmd, 0, 16, 8, uint8_t, mac_addr[5]); \ + MC_RSP_OP(cmd, 0, 24, 8, uint8_t, mac_addr[4]); \ + MC_RSP_OP(cmd, 0, 32, 8, uint8_t, mac_addr[3]); \ + MC_RSP_OP(cmd, 0, 40, 8, uint8_t, mac_addr[2]); \ + MC_RSP_OP(cmd, 0, 48, 8, uint8_t, mac_addr[1]); \ + MC_RSP_OP(cmd, 0, 56, 8, uint8_t, mac_addr[0]); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_ADD_MAC_ADDR(cmd, mac_addr) \ +do { \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, mac_addr[5]); \ + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, mac_addr[4]); \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, mac_addr[3]); \ + MC_CMD_OP(cmd, 0, 40, 8, uint8_t, mac_addr[2]); \ + MC_CMD_OP(cmd, 0, 48, 8, uint8_t, mac_addr[1]); \ + MC_CMD_OP(cmd, 0, 56, 8, uint8_t, mac_addr[0]); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_REMOVE_MAC_ADDR(cmd, mac_addr) \ +do { \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, mac_addr[5]); \ + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, mac_addr[4]); \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, mac_addr[3]); \ + MC_CMD_OP(cmd, 0, 40, 8, uint8_t, mac_addr[2]); \ + MC_CMD_OP(cmd, 0, 48, 8, uint8_t, mac_addr[1]); \ + MC_CMD_OP(cmd, 0, 56, 8, uint8_t, mac_addr[0]); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_CLEAR_MAC_FILTERS(cmd, unicast, multicast) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 1, int, unicast); \ + MC_CMD_OP(cmd, 0, 1, 1, int, multicast); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_VLAN_FILTERS(cmd, en) \ + MC_CMD_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_ADD_VLAN_ID(cmd, vlan_id) \ + MC_CMD_OP(cmd, 0, 32, 16, uint16_t, vlan_id) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_REMOVE_VLAN_ID(cmd, vlan_id) \ + MC_CMD_OP(cmd, 0, 32, 16, uint16_t, vlan_id) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_TX_SELECTION(cmd, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, cfg->tc_sched[0].delta_bandwidth);\ + MC_CMD_OP(cmd, 0, 16, 4, enum dpni_tx_schedule_mode, \ + cfg->tc_sched[0].mode); \ + MC_CMD_OP(cmd, 0, 32, 16, uint16_t, cfg->tc_sched[1].delta_bandwidth);\ + MC_CMD_OP(cmd, 0, 48, 4, enum dpni_tx_schedule_mode, \ + cfg->tc_sched[1].mode); \ + MC_CMD_OP(cmd, 1, 0, 16, uint16_t, cfg->tc_sched[2].delta_bandwidth);\ + MC_CMD_OP(cmd, 1, 16, 4, enum dpni_tx_schedule_mode, \ + cfg->tc_sched[2].mode); \ + MC_CMD_OP(cmd, 1, 32, 16, uint16_t, cfg->tc_sched[3].delta_bandwidth);\ + MC_CMD_OP(cmd, 1, 48, 4, enum dpni_tx_schedule_mode, \ + cfg->tc_sched[3].mode); \ + MC_CMD_OP(cmd, 2, 0, 16, uint16_t, cfg->tc_sched[4].delta_bandwidth);\ + MC_CMD_OP(cmd, 2, 16, 4, enum dpni_tx_schedule_mode, \ + cfg->tc_sched[4].mode); \ + MC_CMD_OP(cmd, 2, 32, 16, uint16_t, cfg->tc_sched[5].delta_bandwidth);\ + MC_CMD_OP(cmd, 2, 48, 4, enum dpni_tx_schedule_mode, \ + cfg->tc_sched[5].mode); \ + MC_CMD_OP(cmd, 3, 0, 16, uint16_t, cfg->tc_sched[6].delta_bandwidth);\ + MC_CMD_OP(cmd, 3, 16, 4, enum dpni_tx_schedule_mode, \ + cfg->tc_sched[6].mode); \ + MC_CMD_OP(cmd, 3, 32, 16, uint16_t, cfg->tc_sched[7].delta_bandwidth);\ + MC_CMD_OP(cmd, 3, 48, 4, enum dpni_tx_schedule_mode, \ + cfg->tc_sched[7].mode); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_RX_TC_DIST(cmd, tc_id, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 16, uint16_t, cfg->dist_size); \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, tc_id); \ + MC_CMD_OP(cmd, 0, 24, 4, enum dpni_dist_mode, cfg->dist_mode); \ + MC_CMD_OP(cmd, 0, 28, 4, enum dpni_fs_miss_action, \ + cfg->fs_cfg.miss_action); \ + MC_CMD_OP(cmd, 0, 48, 16, uint16_t, cfg->fs_cfg.default_flow_id); \ + MC_CMD_OP(cmd, 6, 0, 64, uint64_t, cfg->key_cfg_iova); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_TX_FLOW(cmd, flow_id, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 43, 1, int, cfg->l3_chksum_gen);\ + MC_CMD_OP(cmd, 0, 44, 1, int, cfg->l4_chksum_gen);\ + MC_CMD_OP(cmd, 0, 45, 1, int, cfg->use_common_tx_conf_queue);\ + MC_CMD_OP(cmd, 0, 48, 16, uint16_t, flow_id);\ + MC_CMD_OP(cmd, 2, 0, 32, uint32_t, cfg->options);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_SET_TX_FLOW(cmd, flow_id) \ + MC_RSP_OP(cmd, 0, 48, 16, uint16_t, flow_id) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_GET_TX_FLOW(cmd, flow_id) \ + MC_CMD_OP(cmd, 0, 48, 16, uint16_t, flow_id) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_TX_FLOW(cmd, attr) \ +do { \ + MC_RSP_OP(cmd, 0, 43, 1, int, attr->l3_chksum_gen);\ + MC_RSP_OP(cmd, 0, 44, 1, int, attr->l4_chksum_gen);\ + MC_RSP_OP(cmd, 0, 45, 1, int, attr->use_common_tx_conf_queue);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_RX_FLOW(cmd, tc_id, flow_id, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 32, int, cfg->dest_cfg.dest_id); \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, cfg->dest_cfg.priority);\ + MC_CMD_OP(cmd, 0, 40, 2, enum dpni_dest, cfg->dest_cfg.dest_type);\ + MC_CMD_OP(cmd, 0, 42, 1, int, cfg->order_preservation_en);\ + MC_CMD_OP(cmd, 0, 48, 16, uint16_t, flow_id); \ + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, cfg->user_ctx); \ + MC_CMD_OP(cmd, 2, 16, 8, uint8_t, tc_id); \ + MC_CMD_OP(cmd, 2, 32, 32, uint32_t, cfg->options); \ + MC_CMD_OP(cmd, 3, 0, 4, enum dpni_flc_type, cfg->flc_cfg.flc_type); \ + MC_CMD_OP(cmd, 3, 4, 4, enum dpni_stash_size, \ + cfg->flc_cfg.frame_data_size);\ + MC_CMD_OP(cmd, 3, 8, 4, enum dpni_stash_size, \ + cfg->flc_cfg.flow_context_size);\ + MC_CMD_OP(cmd, 3, 32, 32, uint32_t, cfg->flc_cfg.options);\ + MC_CMD_OP(cmd, 4, 0, 64, uint64_t, cfg->flc_cfg.flow_context);\ + MC_CMD_OP(cmd, 5, 0, 32, uint32_t, cfg->tail_drop_threshold); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_GET_RX_FLOW(cmd, tc_id, flow_id) \ +do { \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, tc_id); \ + MC_CMD_OP(cmd, 0, 48, 16, uint16_t, flow_id); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_RX_FLOW(cmd, attr) \ +do { \ + MC_RSP_OP(cmd, 0, 0, 32, int, attr->dest_cfg.dest_id); \ + MC_RSP_OP(cmd, 0, 32, 8, uint8_t, attr->dest_cfg.priority);\ + MC_RSP_OP(cmd, 0, 40, 2, enum dpni_dest, attr->dest_cfg.dest_type); \ + MC_RSP_OP(cmd, 0, 42, 1, int, attr->order_preservation_en);\ + MC_RSP_OP(cmd, 1, 0, 64, uint64_t, attr->user_ctx); \ + MC_RSP_OP(cmd, 2, 0, 32, uint32_t, attr->tail_drop_threshold); \ + MC_RSP_OP(cmd, 2, 32, 32, uint32_t, attr->fqid); \ + MC_RSP_OP(cmd, 3, 0, 4, enum dpni_flc_type, attr->flc_cfg.flc_type); \ + MC_RSP_OP(cmd, 3, 4, 4, enum dpni_stash_size, \ + attr->flc_cfg.frame_data_size);\ + MC_RSP_OP(cmd, 3, 8, 4, enum dpni_stash_size, \ + attr->flc_cfg.flow_context_size);\ + MC_RSP_OP(cmd, 3, 32, 32, uint32_t, attr->flc_cfg.options);\ + MC_RSP_OP(cmd, 4, 0, 64, uint64_t, attr->flc_cfg.flow_context);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_RX_ERR_QUEUE(cmd, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 32, int, cfg->dest_cfg.dest_id); \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, cfg->dest_cfg.priority);\ + MC_CMD_OP(cmd, 0, 40, 2, enum dpni_dest, cfg->dest_cfg.dest_type);\ + MC_CMD_OP(cmd, 0, 42, 1, int, cfg->order_preservation_en);\ + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, cfg->user_ctx); \ + MC_CMD_OP(cmd, 2, 0, 32, uint32_t, cfg->options); \ + MC_CMD_OP(cmd, 2, 32, 32, uint32_t, cfg->tail_drop_threshold); \ + MC_CMD_OP(cmd, 3, 0, 4, enum dpni_flc_type, cfg->flc_cfg.flc_type); \ + MC_CMD_OP(cmd, 3, 4, 4, enum dpni_stash_size, \ + cfg->flc_cfg.frame_data_size);\ + MC_CMD_OP(cmd, 3, 8, 4, enum dpni_stash_size, \ + cfg->flc_cfg.flow_context_size);\ + MC_CMD_OP(cmd, 3, 32, 32, uint32_t, cfg->flc_cfg.options);\ + MC_CMD_OP(cmd, 4, 0, 64, uint64_t, cfg->flc_cfg.flow_context);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_RX_ERR_QUEUE(cmd, attr) \ +do { \ + MC_RSP_OP(cmd, 0, 0, 32, int, attr->dest_cfg.dest_id); \ + MC_RSP_OP(cmd, 0, 32, 8, uint8_t, attr->dest_cfg.priority);\ + MC_RSP_OP(cmd, 0, 40, 2, enum dpni_dest, attr->dest_cfg.dest_type);\ + MC_RSP_OP(cmd, 0, 42, 1, int, attr->order_preservation_en);\ + MC_RSP_OP(cmd, 1, 0, 64, uint64_t, attr->user_ctx); \ + MC_RSP_OP(cmd, 2, 0, 32, uint32_t, attr->tail_drop_threshold); \ + MC_RSP_OP(cmd, 2, 32, 32, uint32_t, attr->fqid); \ + MC_RSP_OP(cmd, 3, 0, 4, enum dpni_flc_type, attr->flc_cfg.flc_type); \ + MC_RSP_OP(cmd, 3, 4, 4, enum dpni_stash_size, \ + attr->flc_cfg.frame_data_size);\ + MC_RSP_OP(cmd, 3, 8, 4, enum dpni_stash_size, \ + attr->flc_cfg.flow_context_size);\ + MC_RSP_OP(cmd, 3, 32, 32, uint32_t, attr->flc_cfg.options);\ + MC_RSP_OP(cmd, 4, 0, 64, uint64_t, attr->flc_cfg.flow_context);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_TX_CONF_REVOKE(cmd, revoke) \ + MC_CMD_OP(cmd, 0, 0, 1, int, revoke) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_QOS_TABLE(cmd, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, cfg->default_tc); \ + MC_CMD_OP(cmd, 0, 40, 1, int, cfg->discard_on_miss); \ + MC_CMD_OP(cmd, 6, 0, 64, uint64_t, cfg->key_cfg_iova); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_ADD_QOS_ENTRY(cmd, cfg, tc_id) \ +do { \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, tc_id); \ + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, cfg->key_size); \ + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, cfg->key_iova); \ + MC_CMD_OP(cmd, 2, 0, 64, uint64_t, cfg->mask_iova); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_REMOVE_QOS_ENTRY(cmd, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, cfg->key_size); \ + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, cfg->key_iova); \ + MC_CMD_OP(cmd, 2, 0, 64, uint64_t, cfg->mask_iova); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_ADD_FS_ENTRY(cmd, tc_id, cfg, flow_id) \ +do { \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, tc_id); \ + MC_CMD_OP(cmd, 0, 48, 16, uint16_t, flow_id); \ + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, cfg->key_size); \ + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, cfg->key_iova); \ + MC_CMD_OP(cmd, 2, 0, 64, uint64_t, cfg->mask_iova); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_REMOVE_FS_ENTRY(cmd, tc_id, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, tc_id); \ + MC_CMD_OP(cmd, 0, 24, 8, uint8_t, cfg->key_size); \ + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, cfg->key_iova); \ + MC_CMD_OP(cmd, 2, 0, 64, uint64_t, cfg->mask_iova); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_CLEAR_FS_ENTRIES(cmd, tc_id) \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, tc_id) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_VLAN_INSERTION(cmd, en) \ + MC_CMD_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_VLAN_REMOVAL(cmd, en) \ + MC_CMD_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_IPR(cmd, en) \ + MC_CMD_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_IPF(cmd, en) \ + MC_CMD_OP(cmd, 0, 0, 1, int, en) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_RX_TC_POLICING(cmd, tc_id, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 4, enum dpni_policer_mode, cfg->mode); \ + MC_CMD_OP(cmd, 0, 4, 4, enum dpni_policer_color, cfg->default_color); \ + MC_CMD_OP(cmd, 0, 8, 4, enum dpni_policer_unit, cfg->units); \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, tc_id); \ + MC_CMD_OP(cmd, 0, 32, 32, uint32_t, cfg->options); \ + MC_CMD_OP(cmd, 1, 0, 32, uint32_t, cfg->cir); \ + MC_CMD_OP(cmd, 1, 32, 32, uint32_t, cfg->cbs); \ + MC_CMD_OP(cmd, 2, 0, 32, uint32_t, cfg->eir); \ + MC_CMD_OP(cmd, 2, 32, 32, uint32_t, cfg->ebs);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_GET_RX_TC_POLICING(cmd, tc_id) \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, tc_id) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_RSP_GET_RX_TC_POLICING(cmd, cfg) \ +do { \ + MC_RSP_OP(cmd, 0, 0, 4, enum dpni_policer_mode, cfg->mode); \ + MC_RSP_OP(cmd, 0, 4, 4, enum dpni_policer_color, cfg->default_color); \ + MC_RSP_OP(cmd, 0, 8, 4, enum dpni_policer_unit, cfg->units); \ + MC_RSP_OP(cmd, 0, 32, 32, uint32_t, cfg->options); \ + MC_RSP_OP(cmd, 1, 0, 32, uint32_t, cfg->cir); \ + MC_RSP_OP(cmd, 1, 32, 32, uint32_t, cfg->cbs); \ + MC_RSP_OP(cmd, 2, 0, 32, uint32_t, cfg->eir); \ + MC_RSP_OP(cmd, 2, 32, 32, uint32_t, cfg->ebs);\ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_PREP_EARLY_DROP(ext, cfg) \ +do { \ + MC_PREP_OP(ext, 0, 0, 2, enum dpni_early_drop_mode, cfg->mode); \ + MC_PREP_OP(ext, 0, 2, 2, \ + enum dpni_congestion_unit, cfg->units); \ + MC_PREP_OP(ext, 0, 32, 32, uint32_t, cfg->tail_drop_threshold); \ + MC_PREP_OP(ext, 1, 0, 8, uint8_t, cfg->green.drop_probability); \ + MC_PREP_OP(ext, 2, 0, 64, uint64_t, cfg->green.max_threshold); \ + MC_PREP_OP(ext, 3, 0, 64, uint64_t, cfg->green.min_threshold); \ + MC_PREP_OP(ext, 5, 0, 8, uint8_t, cfg->yellow.drop_probability);\ + MC_PREP_OP(ext, 6, 0, 64, uint64_t, cfg->yellow.max_threshold); \ + MC_PREP_OP(ext, 7, 0, 64, uint64_t, cfg->yellow.min_threshold); \ + MC_PREP_OP(ext, 9, 0, 8, uint8_t, cfg->red.drop_probability); \ + MC_PREP_OP(ext, 10, 0, 64, uint64_t, cfg->red.max_threshold); \ + MC_PREP_OP(ext, 11, 0, 64, uint64_t, cfg->red.min_threshold); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_EXT_EARLY_DROP(ext, cfg) \ +do { \ + MC_EXT_OP(ext, 0, 0, 2, enum dpni_early_drop_mode, cfg->mode); \ + MC_EXT_OP(ext, 0, 2, 2, \ + enum dpni_congestion_unit, cfg->units); \ + MC_EXT_OP(ext, 0, 32, 32, uint32_t, cfg->tail_drop_threshold); \ + MC_EXT_OP(ext, 1, 0, 8, uint8_t, cfg->green.drop_probability); \ + MC_EXT_OP(ext, 2, 0, 64, uint64_t, cfg->green.max_threshold); \ + MC_EXT_OP(ext, 3, 0, 64, uint64_t, cfg->green.min_threshold); \ + MC_EXT_OP(ext, 5, 0, 8, uint8_t, cfg->yellow.drop_probability);\ + MC_EXT_OP(ext, 6, 0, 64, uint64_t, cfg->yellow.max_threshold); \ + MC_EXT_OP(ext, 7, 0, 64, uint64_t, cfg->yellow.min_threshold); \ + MC_EXT_OP(ext, 9, 0, 8, uint8_t, cfg->red.drop_probability); \ + MC_EXT_OP(ext, 10, 0, 64, uint64_t, cfg->red.max_threshold); \ + MC_EXT_OP(ext, 11, 0, 64, uint64_t, cfg->red.min_threshold); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_RX_TC_EARLY_DROP(cmd, tc_id, early_drop_iova) \ +do { \ + MC_CMD_OP(cmd, 0, 8, 8, uint8_t, tc_id); \ + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, early_drop_iova); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_GET_RX_TC_EARLY_DROP(cmd, tc_id, early_drop_iova) \ +do { \ + MC_CMD_OP(cmd, 0, 8, 8, uint8_t, tc_id); \ + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, early_drop_iova); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_SET_TX_TC_EARLY_DROP(cmd, tc_id, early_drop_iova) \ +do { \ + MC_CMD_OP(cmd, 0, 8, 8, uint8_t, tc_id); \ + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, early_drop_iova); \ +} while (0) + +/* cmd, param, offset, width, type, arg_name */ +#define DPNI_CMD_GET_TX_TC_EARLY_DROP(cmd, tc_id, early_drop_iova) \ +do { \ + MC_CMD_OP(cmd, 0, 8, 8, uint8_t, tc_id); \ + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, early_drop_iova); \ +} while (0) + +#define DPNI_CMD_SET_RX_TC_CONGESTION_NOTIFICATION(cmd, tc_id, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 2, enum dpni_congestion_unit, cfg->units); \ + MC_CMD_OP(cmd, 0, 4, 4, enum dpni_dest, cfg->dest_cfg.dest_type); \ + MC_CMD_OP(cmd, 0, 8, 8, uint8_t, tc_id); \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, cfg->dest_cfg.priority); \ + MC_CMD_OP(cmd, 1, 0, 32, uint32_t, cfg->threshold_entry); \ + MC_CMD_OP(cmd, 1, 32, 32, uint32_t, cfg->threshold_exit); \ + MC_CMD_OP(cmd, 2, 0, 16, uint16_t, cfg->options); \ + MC_CMD_OP(cmd, 2, 32, 32, int, cfg->dest_cfg.dest_id); \ + MC_CMD_OP(cmd, 3, 0, 64, uint64_t, cfg->message_ctx); \ + MC_CMD_OP(cmd, 4, 0, 64, uint64_t, cfg->message_iova); \ +} while (0) + +#define DPNI_CMD_GET_RX_TC_CONGESTION_NOTIFICATION(cmd, tc_id) \ + MC_CMD_OP(cmd, 0, 8, 8, uint8_t, tc_id) + +#define DPNI_RSP_GET_RX_TC_CONGESTION_NOTIFICATION(cmd, cfg) \ +do { \ + MC_RSP_OP(cmd, 0, 0, 2, enum dpni_congestion_unit, cfg->units); \ + MC_RSP_OP(cmd, 0, 4, 4, enum dpni_dest, cfg->dest_cfg.dest_type); \ + MC_RSP_OP(cmd, 0, 16, 8, uint8_t, cfg->dest_cfg.priority); \ + MC_RSP_OP(cmd, 1, 0, 32, uint32_t, cfg->threshold_entry); \ + MC_RSP_OP(cmd, 1, 32, 32, uint32_t, cfg->threshold_exit); \ + MC_RSP_OP(cmd, 2, 0, 16, uint16_t, cfg->options); \ + MC_RSP_OP(cmd, 2, 32, 32, int, cfg->dest_cfg.dest_id); \ + MC_RSP_OP(cmd, 3, 0, 64, uint64_t, cfg->message_ctx); \ + MC_RSP_OP(cmd, 4, 0, 64, uint64_t, cfg->message_iova); \ +} while (0) + +#define DPNI_CMD_SET_TX_TC_CONGESTION_NOTIFICATION(cmd, tc_id, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 2, enum dpni_congestion_unit, cfg->units); \ + MC_CMD_OP(cmd, 0, 4, 4, enum dpni_dest, cfg->dest_cfg.dest_type); \ + MC_CMD_OP(cmd, 0, 8, 8, uint8_t, tc_id); \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, cfg->dest_cfg.priority); \ + MC_CMD_OP(cmd, 1, 0, 32, uint32_t, cfg->threshold_entry); \ + MC_CMD_OP(cmd, 1, 32, 32, uint32_t, cfg->threshold_exit); \ + MC_CMD_OP(cmd, 2, 0, 16, uint16_t, cfg->options); \ + MC_CMD_OP(cmd, 2, 32, 32, int, cfg->dest_cfg.dest_id); \ + MC_CMD_OP(cmd, 3, 0, 64, uint64_t, cfg->message_ctx); \ + MC_CMD_OP(cmd, 4, 0, 64, uint64_t, cfg->message_iova); \ +} while (0) + +#define DPNI_CMD_GET_TX_TC_CONGESTION_NOTIFICATION(cmd, tc_id) \ + MC_CMD_OP(cmd, 0, 8, 8, uint8_t, tc_id) + +#define DPNI_RSP_GET_TX_TC_CONGESTION_NOTIFICATION(cmd, cfg) \ +do { \ + MC_RSP_OP(cmd, 0, 0, 2, enum dpni_congestion_unit, cfg->units); \ + MC_RSP_OP(cmd, 0, 4, 4, enum dpni_dest, cfg->dest_cfg.dest_type); \ + MC_RSP_OP(cmd, 0, 16, 8, uint8_t, cfg->dest_cfg.priority); \ + MC_RSP_OP(cmd, 1, 0, 32, uint32_t, cfg->threshold_entry); \ + MC_RSP_OP(cmd, 1, 32, 32, uint32_t, cfg->threshold_exit); \ + MC_RSP_OP(cmd, 2, 0, 16, uint16_t, cfg->options); \ + MC_RSP_OP(cmd, 2, 32, 32, int, cfg->dest_cfg.dest_id); \ + MC_RSP_OP(cmd, 3, 0, 64, uint64_t, cfg->message_ctx); \ + MC_RSP_OP(cmd, 4, 0, 64, uint64_t, cfg->message_iova); \ +} while (0) + +#define DPNI_CMD_SET_TX_CONF(cmd, flow_id, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 32, 8, uint8_t, cfg->queue_cfg.dest_cfg.priority); \ + MC_CMD_OP(cmd, 0, 40, 2, enum dpni_dest, \ + cfg->queue_cfg.dest_cfg.dest_type); \ + MC_CMD_OP(cmd, 0, 42, 1, int, cfg->errors_only); \ + MC_CMD_OP(cmd, 0, 46, 1, int, cfg->queue_cfg.order_preservation_en); \ + MC_CMD_OP(cmd, 0, 48, 16, uint16_t, flow_id); \ + MC_CMD_OP(cmd, 1, 0, 64, uint64_t, cfg->queue_cfg.user_ctx); \ + MC_CMD_OP(cmd, 2, 0, 32, uint32_t, cfg->queue_cfg.options); \ + MC_CMD_OP(cmd, 2, 32, 32, int, cfg->queue_cfg.dest_cfg.dest_id); \ + MC_CMD_OP(cmd, 3, 0, 32, uint32_t, \ + cfg->queue_cfg.tail_drop_threshold); \ + MC_CMD_OP(cmd, 4, 0, 4, enum dpni_flc_type, \ + cfg->queue_cfg.flc_cfg.flc_type); \ + MC_CMD_OP(cmd, 4, 4, 4, enum dpni_stash_size, \ + cfg->queue_cfg.flc_cfg.frame_data_size); \ + MC_CMD_OP(cmd, 4, 8, 4, enum dpni_stash_size, \ + cfg->queue_cfg.flc_cfg.flow_context_size); \ + MC_CMD_OP(cmd, 4, 32, 32, uint32_t, cfg->queue_cfg.flc_cfg.options); \ + MC_CMD_OP(cmd, 5, 0, 64, uint64_t, \ + cfg->queue_cfg.flc_cfg.flow_context); \ +} while (0) + +#define DPNI_CMD_GET_TX_CONF(cmd, flow_id) \ + MC_CMD_OP(cmd, 0, 48, 16, uint16_t, flow_id) + +#define DPNI_RSP_GET_TX_CONF(cmd, attr) \ +do { \ + MC_RSP_OP(cmd, 0, 32, 8, uint8_t, \ + attr->queue_attr.dest_cfg.priority); \ + MC_RSP_OP(cmd, 0, 40, 2, enum dpni_dest, \ + attr->queue_attr.dest_cfg.dest_type); \ + MC_RSP_OP(cmd, 0, 42, 1, int, attr->errors_only); \ + MC_RSP_OP(cmd, 0, 46, 1, int, \ + attr->queue_attr.order_preservation_en); \ + MC_RSP_OP(cmd, 1, 0, 64, uint64_t, attr->queue_attr.user_ctx); \ + MC_RSP_OP(cmd, 2, 32, 32, int, attr->queue_attr.dest_cfg.dest_id); \ + MC_RSP_OP(cmd, 3, 0, 32, uint32_t, \ + attr->queue_attr.tail_drop_threshold); \ + MC_RSP_OP(cmd, 3, 32, 32, uint32_t, attr->queue_attr.fqid); \ + MC_RSP_OP(cmd, 4, 0, 4, enum dpni_flc_type, \ + attr->queue_attr.flc_cfg.flc_type); \ + MC_RSP_OP(cmd, 4, 4, 4, enum dpni_stash_size, \ + attr->queue_attr.flc_cfg.frame_data_size); \ + MC_RSP_OP(cmd, 4, 8, 4, enum dpni_stash_size, \ + attr->queue_attr.flc_cfg.flow_context_size); \ + MC_RSP_OP(cmd, 4, 32, 32, uint32_t, attr->queue_attr.flc_cfg.options); \ + MC_RSP_OP(cmd, 5, 0, 64, uint64_t, \ + attr->queue_attr.flc_cfg.flow_context); \ +} while (0) + +#define DPNI_CMD_SET_TX_CONF_CONGESTION_NOTIFICATION(cmd, flow_id, cfg) \ +do { \ + MC_CMD_OP(cmd, 0, 0, 2, enum dpni_congestion_unit, cfg->units); \ + MC_CMD_OP(cmd, 0, 4, 4, enum dpni_dest, cfg->dest_cfg.dest_type); \ + MC_CMD_OP(cmd, 0, 16, 8, uint8_t, cfg->dest_cfg.priority); \ + MC_CMD_OP(cmd, 0, 48, 16, uint16_t, flow_id); \ + MC_CMD_OP(cmd, 1, 0, 32, uint32_t, cfg->threshold_entry); \ + MC_CMD_OP(cmd, 1, 32, 32, uint32_t, cfg->threshold_exit); \ + MC_CMD_OP(cmd, 2, 0, 16, uint16_t, cfg->options); \ + MC_CMD_OP(cmd, 2, 32, 32, int, cfg->dest_cfg.dest_id); \ + MC_CMD_OP(cmd, 3, 0, 64, uint64_t, cfg->message_ctx); \ + MC_CMD_OP(cmd, 4, 0, 64, uint64_t, cfg->message_iova); \ +} while (0) + +#define DPNI_CMD_GET_TX_CONF_CONGESTION_NOTIFICATION(cmd, flow_id) \ + MC_CMD_OP(cmd, 0, 48, 16, uint16_t, flow_id) + +#define DPNI_RSP_GET_TX_CONF_CONGESTION_NOTIFICATION(cmd, cfg) \ +do { \ + MC_RSP_OP(cmd, 0, 0, 2, enum dpni_congestion_unit, cfg->units); \ + MC_RSP_OP(cmd, 0, 4, 4, enum dpni_dest, cfg->dest_cfg.dest_type); \ + MC_RSP_OP(cmd, 0, 16, 8, uint8_t, cfg->dest_cfg.priority); \ + MC_RSP_OP(cmd, 1, 0, 32, uint32_t, cfg->threshold_entry); \ + MC_RSP_OP(cmd, 1, 32, 32, uint32_t, cfg->threshold_exit); \ + MC_RSP_OP(cmd, 2, 0, 16, uint16_t, cfg->options); \ + MC_RSP_OP(cmd, 2, 32, 32, int, cfg->dest_cfg.dest_id); \ + MC_RSP_OP(cmd, 3, 0, 64, uint64_t, cfg->message_ctx); \ + MC_RSP_OP(cmd, 4, 0, 64, uint64_t, cfg->message_iova); \ +} while (0) + +#endif /* _FSL_DPNI_CMD_H */ --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethernet/dpni.c @@ -0,0 +1,1907 @@ +/* Copyright 2013-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "../../fsl-mc/include/mc-sys.h" +#include "../../fsl-mc/include/mc-cmd.h" +#include "dpni.h" +#include "dpni-cmd.h" + +int dpni_prepare_key_cfg(const struct dpkg_profile_cfg *cfg, + uint8_t *key_cfg_buf) +{ + int i, j; + int offset = 0; + int param = 1; + uint64_t *params = (uint64_t *)key_cfg_buf; + + if (!key_cfg_buf || !cfg) + return -EINVAL; + + params[0] |= mc_enc(0, 8, cfg->num_extracts); + params[0] = cpu_to_le64(params[0]); + + if (cfg->num_extracts >= DPKG_MAX_NUM_OF_EXTRACTS) + return -EINVAL; + + for (i = 0; i < cfg->num_extracts; i++) { + switch (cfg->extracts[i].type) { + case DPKG_EXTRACT_FROM_HDR: + params[param] |= mc_enc(0, 8, + cfg->extracts[i].extract.from_hdr.prot); + params[param] |= mc_enc(8, 4, + cfg->extracts[i].extract.from_hdr.type); + params[param] |= mc_enc(16, 8, + cfg->extracts[i].extract.from_hdr.size); + params[param] |= mc_enc(24, 8, + cfg->extracts[i].extract. + from_hdr.offset); + params[param] |= mc_enc(32, 32, + cfg->extracts[i].extract. + from_hdr.field); + params[param] = cpu_to_le64(params[param]); + param++; + params[param] |= mc_enc(0, 8, + cfg->extracts[i].extract. + from_hdr.hdr_index); + break; + case DPKG_EXTRACT_FROM_DATA: + params[param] |= mc_enc(16, 8, + cfg->extracts[i].extract. + from_data.size); + params[param] |= mc_enc(24, 8, + cfg->extracts[i].extract. + from_data.offset); + params[param] = cpu_to_le64(params[param]); + param++; + break; + case DPKG_EXTRACT_FROM_PARSE: + params[param] |= mc_enc(16, 8, + cfg->extracts[i].extract. + from_parse.size); + params[param] |= mc_enc(24, 8, + cfg->extracts[i].extract. + from_parse.offset); + params[param] = cpu_to_le64(params[param]); + param++; + break; + default: + return -EINVAL; + } + params[param] |= mc_enc( + 24, 8, cfg->extracts[i].num_of_byte_masks); + params[param] |= mc_enc(32, 4, cfg->extracts[i].type); + params[param] = cpu_to_le64(params[param]); + param++; + for (offset = 0, j = 0; + j < DPKG_NUM_OF_MASKS; + offset += 16, j++) { + params[param] |= mc_enc( + (offset), 8, cfg->extracts[i].masks[j].mask); + params[param] |= mc_enc( + (offset + 8), 8, + cfg->extracts[i].masks[j].offset); + } + params[param] = cpu_to_le64(params[param]); + param++; + } + return 0; +} + +int dpni_prepare_extended_cfg(const struct dpni_extended_cfg *cfg, + uint8_t *ext_cfg_buf) +{ + uint64_t *ext_params = (uint64_t *)ext_cfg_buf; + + DPNI_PREP_EXTENDED_CFG(ext_params, cfg); + + return 0; +} + +int dpni_extract_extended_cfg(struct dpni_extended_cfg *cfg, + const uint8_t *ext_cfg_buf) +{ + uint64_t *ext_params = (uint64_t *)ext_cfg_buf; + + DPNI_EXT_EXTENDED_CFG(ext_params, cfg); + + return 0; +} + +int dpni_open(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + int dpni_id, + uint16_t *token) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_OPEN, + cmd_flags, + 0); + DPNI_CMD_OPEN(cmd, dpni_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + + return 0; +} + +int dpni_close(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLOSE, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_create(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + const struct dpni_cfg *cfg, + uint16_t *token) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_CREATE, + cmd_flags, + 0); + DPNI_CMD_CREATE(cmd, cfg); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + *token = MC_CMD_HDR_READ_TOKEN(cmd.header); + + return 0; +} + +int dpni_destroy(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_DESTROY, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_pools(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_pools_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_POOLS, + cmd_flags, + token); + DPNI_CMD_SET_POOLS(cmd, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_enable(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_ENABLE, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_disable(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_DISABLE, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_is_enabled(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int *en) +{ + struct mc_command cmd = { 0 }; + int err; + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_IS_ENABLED, cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_IS_ENABLED(cmd, *en); + + return 0; +} + +int dpni_reset(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_RESET, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_irq(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + struct dpni_irq_cfg *irq_cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_IRQ, + cmd_flags, + token); + DPNI_CMD_SET_IRQ(cmd, irq_index, irq_cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_irq(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + int *type, + struct dpni_irq_cfg *irq_cfg) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_IRQ, + cmd_flags, + token); + DPNI_CMD_GET_IRQ(cmd, irq_index); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_IRQ(cmd, *type, irq_cfg); + + return 0; +} + +int dpni_set_irq_enable(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + uint8_t en) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_IRQ_ENABLE, + cmd_flags, + token); + DPNI_CMD_SET_IRQ_ENABLE(cmd, irq_index, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_irq_enable(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + uint8_t *en) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_IRQ_ENABLE, + cmd_flags, + token); + DPNI_CMD_GET_IRQ_ENABLE(cmd, irq_index); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_IRQ_ENABLE(cmd, *en); + + return 0; +} + +int dpni_set_irq_mask(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + uint32_t mask) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_IRQ_MASK, + cmd_flags, + token); + DPNI_CMD_SET_IRQ_MASK(cmd, irq_index, mask); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_irq_mask(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + uint32_t *mask) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_IRQ_MASK, + cmd_flags, + token); + DPNI_CMD_GET_IRQ_MASK(cmd, irq_index); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_IRQ_MASK(cmd, *mask); + + return 0; +} + +int dpni_get_irq_status(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + uint32_t *status) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_IRQ_STATUS, + cmd_flags, + token); + DPNI_CMD_GET_IRQ_STATUS(cmd, irq_index, *status); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_IRQ_STATUS(cmd, *status); + + return 0; +} + +int dpni_clear_irq_status(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + uint32_t status) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLEAR_IRQ_STATUS, + cmd_flags, + token); + DPNI_CMD_CLEAR_IRQ_STATUS(cmd, irq_index, status); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_attributes(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_attr *attr) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_ATTR, + cmd_flags, + token); + DPNI_CMD_GET_ATTR(cmd, attr); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_ATTR(cmd, attr); + + return 0; +} + +int dpni_set_errors_behavior(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_error_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_ERRORS_BEHAVIOR, + cmd_flags, + token); + DPNI_CMD_SET_ERRORS_BEHAVIOR(cmd, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_rx_buffer_layout(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_buffer_layout *layout) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_RX_BUFFER_LAYOUT, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_RX_BUFFER_LAYOUT(cmd, layout); + + return 0; +} + +int dpni_set_rx_buffer_layout(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_buffer_layout *layout) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_BUFFER_LAYOUT, + cmd_flags, + token); + DPNI_CMD_SET_RX_BUFFER_LAYOUT(cmd, layout); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_tx_buffer_layout(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_buffer_layout *layout) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_BUFFER_LAYOUT, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_TX_BUFFER_LAYOUT(cmd, layout); + + return 0; +} + +int dpni_set_tx_buffer_layout(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_buffer_layout *layout) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_BUFFER_LAYOUT, + cmd_flags, + token); + DPNI_CMD_SET_TX_BUFFER_LAYOUT(cmd, layout); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_tx_conf_buffer_layout(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_buffer_layout *layout) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_CONF_BUFFER_LAYOUT, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_TX_CONF_BUFFER_LAYOUT(cmd, layout); + + return 0; +} + +int dpni_set_tx_conf_buffer_layout(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_buffer_layout *layout) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_CONF_BUFFER_LAYOUT, + cmd_flags, + token); + DPNI_CMD_SET_TX_CONF_BUFFER_LAYOUT(cmd, layout); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_l3_chksum_validation(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int *en) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_L3_CHKSUM_VALIDATION, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_L3_CHKSUM_VALIDATION(cmd, *en); + + return 0; +} + +int dpni_set_l3_chksum_validation(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_L3_CHKSUM_VALIDATION, + cmd_flags, + token); + DPNI_CMD_SET_L3_CHKSUM_VALIDATION(cmd, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_l4_chksum_validation(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int *en) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_L4_CHKSUM_VALIDATION, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_L4_CHKSUM_VALIDATION(cmd, *en); + + return 0; +} + +int dpni_set_l4_chksum_validation(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_L4_CHKSUM_VALIDATION, + cmd_flags, + token); + DPNI_CMD_SET_L4_CHKSUM_VALIDATION(cmd, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_qdid(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t *qdid) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_QDID, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_QDID(cmd, *qdid); + + return 0; +} + +int dpni_get_sp_info(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_sp_info *sp_info) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_SP_INFO, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_SP_INFO(cmd, sp_info); + + return 0; +} + +int dpni_get_tx_data_offset(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t *data_offset) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_DATA_OFFSET, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_TX_DATA_OFFSET(cmd, *data_offset); + + return 0; +} + +int dpni_get_counter(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + enum dpni_counter counter, + uint64_t *value) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_COUNTER, + cmd_flags, + token); + DPNI_CMD_GET_COUNTER(cmd, counter); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_COUNTER(cmd, *value); + + return 0; +} + +int dpni_set_counter(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + enum dpni_counter counter, + uint64_t value) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_COUNTER, + cmd_flags, + token); + DPNI_CMD_SET_COUNTER(cmd, counter, value); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_link_cfg(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_link_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_LINK_CFG, + cmd_flags, + token); + DPNI_CMD_SET_LINK_CFG(cmd, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_link_state(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_link_state *state) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_LINK_STATE, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_LINK_STATE(cmd, state); + + return 0; +} + +int dpni_set_tx_shaping(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_tx_shaping_cfg *tx_shaper) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_SHAPING, + cmd_flags, + token); + DPNI_CMD_SET_TX_SHAPING(cmd, tx_shaper); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_max_frame_length(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t max_frame_length) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_MAX_FRAME_LENGTH, + cmd_flags, + token); + DPNI_CMD_SET_MAX_FRAME_LENGTH(cmd, max_frame_length); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_max_frame_length(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t *max_frame_length) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_MAX_FRAME_LENGTH, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_MAX_FRAME_LENGTH(cmd, *max_frame_length); + + return 0; +} + +int dpni_set_mtu(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t mtu) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_MTU, + cmd_flags, + token); + DPNI_CMD_SET_MTU(cmd, mtu); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_mtu(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t *mtu) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_MTU, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_MTU(cmd, *mtu); + + return 0; +} + +int dpni_set_multicast_promisc(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_MCAST_PROMISC, + cmd_flags, + token); + DPNI_CMD_SET_MULTICAST_PROMISC(cmd, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_multicast_promisc(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int *en) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_MCAST_PROMISC, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_MULTICAST_PROMISC(cmd, *en); + + return 0; +} + +int dpni_set_unicast_promisc(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_UNICAST_PROMISC, + cmd_flags, + token); + DPNI_CMD_SET_UNICAST_PROMISC(cmd, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_unicast_promisc(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int *en) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_UNICAST_PROMISC, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_UNICAST_PROMISC(cmd, *en); + + return 0; +} + +int dpni_set_primary_mac_addr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const uint8_t mac_addr[6]) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_PRIM_MAC, + cmd_flags, + token); + DPNI_CMD_SET_PRIMARY_MAC_ADDR(cmd, mac_addr); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_primary_mac_addr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t mac_addr[6]) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_PRIM_MAC, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_PRIMARY_MAC_ADDR(cmd, mac_addr); + + return 0; +} + +int dpni_add_mac_addr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const uint8_t mac_addr[6]) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_MAC_ADDR, + cmd_flags, + token); + DPNI_CMD_ADD_MAC_ADDR(cmd, mac_addr); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_remove_mac_addr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const uint8_t mac_addr[6]) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_MAC_ADDR, + cmd_flags, + token); + DPNI_CMD_REMOVE_MAC_ADDR(cmd, mac_addr); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_clear_mac_filters(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int unicast, + int multicast) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLR_MAC_FILTERS, + cmd_flags, + token); + DPNI_CMD_CLEAR_MAC_FILTERS(cmd, unicast, multicast); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_vlan_filters(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_VLAN_FILTERS, + cmd_flags, + token); + DPNI_CMD_SET_VLAN_FILTERS(cmd, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_add_vlan_id(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t vlan_id) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_VLAN_ID, + cmd_flags, + token); + DPNI_CMD_ADD_VLAN_ID(cmd, vlan_id); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_remove_vlan_id(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t vlan_id) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_VLAN_ID, + cmd_flags, + token); + DPNI_CMD_REMOVE_VLAN_ID(cmd, vlan_id); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_clear_vlan_filters(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLR_VLAN_FILTERS, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_tx_selection(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_tx_selection_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_SELECTION, + cmd_flags, + token); + DPNI_CMD_SET_TX_SELECTION(cmd, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_rx_tc_dist(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + const struct dpni_rx_tc_dist_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_TC_DIST, + cmd_flags, + token); + DPNI_CMD_SET_RX_TC_DIST(cmd, tc_id, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_tx_flow(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t *flow_id, + const struct dpni_tx_flow_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_FLOW, + cmd_flags, + token); + DPNI_CMD_SET_TX_FLOW(cmd, *flow_id, cfg); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_SET_TX_FLOW(cmd, *flow_id); + + return 0; +} + +int dpni_get_tx_flow(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t flow_id, + struct dpni_tx_flow_attr *attr) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_FLOW, + cmd_flags, + token); + DPNI_CMD_GET_TX_FLOW(cmd, flow_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_TX_FLOW(cmd, attr); + + return 0; +} + +int dpni_set_rx_flow(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + uint16_t flow_id, + const struct dpni_queue_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_FLOW, + cmd_flags, + token); + DPNI_CMD_SET_RX_FLOW(cmd, tc_id, flow_id, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_rx_flow(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + uint16_t flow_id, + struct dpni_queue_attr *attr) +{ + struct mc_command cmd = { 0 }; + int err; + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_RX_FLOW, + cmd_flags, + token); + DPNI_CMD_GET_RX_FLOW(cmd, tc_id, flow_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_RX_FLOW(cmd, attr); + + return 0; +} + +int dpni_set_rx_err_queue(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_queue_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_ERR_QUEUE, + cmd_flags, + token); + DPNI_CMD_SET_RX_ERR_QUEUE(cmd, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_rx_err_queue(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_queue_attr *attr) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_RX_ERR_QUEUE, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + DPNI_RSP_GET_RX_ERR_QUEUE(cmd, attr); + + return 0; +} + +int dpni_set_tx_conf_revoke(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int revoke) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_CONF_REVOKE, + cmd_flags, + token); + DPNI_CMD_SET_TX_CONF_REVOKE(cmd, revoke); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_qos_table(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_qos_tbl_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_QOS_TBL, + cmd_flags, + token); + DPNI_CMD_SET_QOS_TABLE(cmd, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_add_qos_entry(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_rule_cfg *cfg, + uint8_t tc_id) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_QOS_ENT, + cmd_flags, + token); + DPNI_CMD_ADD_QOS_ENTRY(cmd, cfg, tc_id); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_remove_qos_entry(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_rule_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_QOS_ENT, + cmd_flags, + token); + DPNI_CMD_REMOVE_QOS_ENTRY(cmd, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_clear_qos_table(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLR_QOS_TBL, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_add_fs_entry(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + const struct dpni_rule_cfg *cfg, + uint16_t flow_id) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_FS_ENT, + cmd_flags, + token); + DPNI_CMD_ADD_FS_ENTRY(cmd, tc_id, cfg, flow_id); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_remove_fs_entry(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + const struct dpni_rule_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_FS_ENT, + cmd_flags, + token); + DPNI_CMD_REMOVE_FS_ENTRY(cmd, tc_id, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_clear_fs_entries(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLR_FS_ENT, + cmd_flags, + token); + DPNI_CMD_CLEAR_FS_ENTRIES(cmd, tc_id); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_vlan_insertion(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_VLAN_INSERTION, + cmd_flags, token); + DPNI_CMD_SET_VLAN_INSERTION(cmd, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_vlan_removal(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_VLAN_REMOVAL, + cmd_flags, token); + DPNI_CMD_SET_VLAN_REMOVAL(cmd, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_ipr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_IPR, + cmd_flags, + token); + DPNI_CMD_SET_IPR(cmd, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_ipf(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_IPF, + cmd_flags, + token); + DPNI_CMD_SET_IPF(cmd, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_rx_tc_policing(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + const struct dpni_rx_tc_policing_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_TC_POLICING, + cmd_flags, + token); + DPNI_CMD_SET_RX_TC_POLICING(cmd, tc_id, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_rx_tc_policing(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + struct dpni_rx_tc_policing_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_RX_TC_POLICING, + cmd_flags, + token); + DPNI_CMD_GET_RX_TC_POLICING(cmd, tc_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + DPNI_RSP_GET_RX_TC_POLICING(cmd, cfg); + + return 0; +} + +void dpni_prepare_early_drop(const struct dpni_early_drop_cfg *cfg, + uint8_t *early_drop_buf) +{ + uint64_t *ext_params = (uint64_t *)early_drop_buf; + + DPNI_PREP_EARLY_DROP(ext_params, cfg); +} + +void dpni_extract_early_drop(struct dpni_early_drop_cfg *cfg, + const uint8_t *early_drop_buf) +{ + uint64_t *ext_params = (uint64_t *)early_drop_buf; + + DPNI_EXT_EARLY_DROP(ext_params, cfg); +} + +int dpni_set_rx_tc_early_drop(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + uint64_t early_drop_iova) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_TC_EARLY_DROP, + cmd_flags, + token); + DPNI_CMD_SET_RX_TC_EARLY_DROP(cmd, tc_id, early_drop_iova); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_rx_tc_early_drop(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + uint64_t early_drop_iova) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_RX_TC_EARLY_DROP, + cmd_flags, + token); + DPNI_CMD_GET_RX_TC_EARLY_DROP(cmd, tc_id, early_drop_iova); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_tx_tc_early_drop(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + uint64_t early_drop_iova) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_TC_EARLY_DROP, + cmd_flags, + token); + DPNI_CMD_SET_TX_TC_EARLY_DROP(cmd, tc_id, early_drop_iova); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_tx_tc_early_drop(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + uint64_t early_drop_iova) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_TC_EARLY_DROP, + cmd_flags, + token); + DPNI_CMD_GET_TX_TC_EARLY_DROP(cmd, tc_id, early_drop_iova); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_set_rx_tc_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + const struct dpni_congestion_notification_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header( + DPNI_CMDID_SET_RX_TC_CONGESTION_NOTIFICATION, + cmd_flags, + token); + DPNI_CMD_SET_RX_TC_CONGESTION_NOTIFICATION(cmd, tc_id, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_rx_tc_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + struct dpni_congestion_notification_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header( + DPNI_CMDID_GET_RX_TC_CONGESTION_NOTIFICATION, + cmd_flags, + token); + DPNI_CMD_GET_RX_TC_CONGESTION_NOTIFICATION(cmd, tc_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + DPNI_RSP_GET_RX_TC_CONGESTION_NOTIFICATION(cmd, cfg); + + return 0; +} + +int dpni_set_tx_tc_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + const struct dpni_congestion_notification_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header( + DPNI_CMDID_SET_TX_TC_CONGESTION_NOTIFICATION, + cmd_flags, + token); + DPNI_CMD_SET_TX_TC_CONGESTION_NOTIFICATION(cmd, tc_id, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_tx_tc_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + struct dpni_congestion_notification_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header( + DPNI_CMDID_GET_TX_TC_CONGESTION_NOTIFICATION, + cmd_flags, + token); + DPNI_CMD_GET_TX_TC_CONGESTION_NOTIFICATION(cmd, tc_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + DPNI_RSP_GET_TX_TC_CONGESTION_NOTIFICATION(cmd, cfg); + + return 0; +} + +int dpni_set_tx_conf(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t flow_id, + const struct dpni_tx_conf_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_CONF, + cmd_flags, + token); + DPNI_CMD_SET_TX_CONF(cmd, flow_id, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_tx_conf(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t flow_id, + struct dpni_tx_conf_attr *attr) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_CONF, + cmd_flags, + token); + DPNI_CMD_GET_TX_CONF(cmd, flow_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + DPNI_RSP_GET_TX_CONF(cmd, attr); + + return 0; +} + +int dpni_set_tx_conf_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t flow_id, + const struct dpni_congestion_notification_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header( + DPNI_CMDID_SET_TX_CONF_CONGESTION_NOTIFICATION, + cmd_flags, + token); + DPNI_CMD_SET_TX_CONF_CONGESTION_NOTIFICATION(cmd, flow_id, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_tx_conf_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t flow_id, + struct dpni_congestion_notification_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header( + DPNI_CMDID_GET_TX_CONF_CONGESTION_NOTIFICATION, + cmd_flags, + token); + DPNI_CMD_GET_TX_CONF_CONGESTION_NOTIFICATION(cmd, flow_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + DPNI_RSP_GET_TX_CONF_CONGESTION_NOTIFICATION(cmd, cfg); + + return 0; +} --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethernet/dpni.h @@ -0,0 +1,2581 @@ +/* Copyright 2013-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __FSL_DPNI_H +#define __FSL_DPNI_H + +#include "dpkg.h" + +struct fsl_mc_io; + +/** + * Data Path Network Interface API + * Contains initialization APIs and runtime control APIs for DPNI + */ + +/** General DPNI macros */ + +/** + * Maximum number of traffic classes + */ +#define DPNI_MAX_TC 8 +/** + * Maximum number of buffer pools per DPNI + */ +#define DPNI_MAX_DPBP 8 +/** + * Maximum number of storage-profiles per DPNI + */ +#define DPNI_MAX_SP 2 + +/** + * All traffic classes considered; see dpni_set_rx_flow() + */ +#define DPNI_ALL_TCS (uint8_t)(-1) +/** + * All flows within traffic class considered; see dpni_set_rx_flow() + */ +#define DPNI_ALL_TC_FLOWS (uint16_t)(-1) +/** + * Generate new flow ID; see dpni_set_tx_flow() + */ +#define DPNI_NEW_FLOW_ID (uint16_t)(-1) +/* use for common tx-conf queue; see dpni_set_tx_conf_() */ +#define DPNI_COMMON_TX_CONF (uint16_t)(-1) + +/** + * dpni_open() - Open a control session for the specified object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @dpni_id: DPNI unique ID + * @token: Returned token; use in subsequent API calls + * + * This function can be used to open a control session for an + * already created object; an object may have been declared in + * the DPL or by calling the dpni_create() function. + * This function returns a unique authentication token, + * associated with the specific object ID and the specific MC + * portal; this token must be used in all subsequent commands for + * this specific object. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_open(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + int dpni_id, + uint16_t *token); + +/** + * dpni_close() - Close the control session of the object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * + * After this function is called, no further operations are + * allowed on the object without opening a new control session. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_close(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token); + +/* DPNI configuration options */ + +/** + * Allow different distribution key profiles for different traffic classes; + * if not set, a single key profile is assumed + */ +#define DPNI_OPT_ALLOW_DIST_KEY_PER_TC 0x00000001 + +/** + * Disable all non-error transmit confirmation; error frames are reported + * back to a common Tx error queue + */ +#define DPNI_OPT_TX_CONF_DISABLED 0x00000002 + +/** + * Disable per-sender private Tx confirmation/error queue + */ +#define DPNI_OPT_PRIVATE_TX_CONF_ERROR_DISABLED 0x00000004 + +/** + * Support distribution based on hashed key; + * allows statistical distribution over receive queues in a traffic class + */ +#define DPNI_OPT_DIST_HASH 0x00000010 + +/** + * DEPRECATED - if this flag is selected and and all new 'max_fs_entries' are + * '0' then backward compatibility is preserved; + * Support distribution based on flow steering; + * allows explicit control of distribution over receive queues in a traffic + * class + */ +#define DPNI_OPT_DIST_FS 0x00000020 + +/** + * Unicast filtering support + */ +#define DPNI_OPT_UNICAST_FILTER 0x00000080 +/** + * Multicast filtering support + */ +#define DPNI_OPT_MULTICAST_FILTER 0x00000100 +/** + * VLAN filtering support + */ +#define DPNI_OPT_VLAN_FILTER 0x00000200 +/** + * Support IP reassembly on received packets + */ +#define DPNI_OPT_IPR 0x00000800 +/** + * Support IP fragmentation on transmitted packets + */ +#define DPNI_OPT_IPF 0x00001000 +/** + * VLAN manipulation support + */ +#define DPNI_OPT_VLAN_MANIPULATION 0x00010000 +/** + * Support masking of QoS lookup keys + */ +#define DPNI_OPT_QOS_MASK_SUPPORT 0x00020000 +/** + * Support masking of Flow Steering lookup keys + */ +#define DPNI_OPT_FS_MASK_SUPPORT 0x00040000 + +/** + * struct dpni_extended_cfg - Structure representing extended DPNI configuration + * @tc_cfg: TCs configuration + * @ipr_cfg: IP reassembly configuration + */ +struct dpni_extended_cfg { + /** + * struct tc_cfg - TC configuration + * @max_dist: Maximum distribution size for Rx traffic class; + * supported values: 1,2,3,4,6,7,8,12,14,16,24,28,32,48,56,64,96, + * 112,128,192,224,256,384,448,512,768,896,1024; + * value '0' will be treated as '1'. + * other unsupported values will be round down to the nearest + * supported value. + * @max_fs_entries: Maximum FS entries for Rx traffic class; + * '0' means no support for this TC; + */ + struct { + uint16_t max_dist; + uint16_t max_fs_entries; + } tc_cfg[DPNI_MAX_TC]; + /** + * struct ipr_cfg - Structure representing IP reassembly configuration + * @max_reass_frm_size: Maximum size of the reassembled frame + * @min_frag_size_ipv4: Minimum fragment size of IPv4 fragments + * @min_frag_size_ipv6: Minimum fragment size of IPv6 fragments + * @max_open_frames_ipv4: Maximum concurrent IPv4 packets in reassembly + * process + * @max_open_frames_ipv6: Maximum concurrent IPv6 packets in reassembly + * process + */ + struct { + uint16_t max_reass_frm_size; + uint16_t min_frag_size_ipv4; + uint16_t min_frag_size_ipv6; + uint16_t max_open_frames_ipv4; + uint16_t max_open_frames_ipv6; + } ipr_cfg; +}; + +/** + * dpni_prepare_extended_cfg() - function prepare extended parameters + * @cfg: extended structure + * @ext_cfg_buf: Zeroed 256 bytes of memory before mapping it to DMA + * + * This function has to be called before dpni_create() + */ +int dpni_prepare_extended_cfg(const struct dpni_extended_cfg *cfg, + uint8_t *ext_cfg_buf); + +/** + * struct dpni_cfg - Structure representing DPNI configuration + * @mac_addr: Primary MAC address + * @adv: Advanced parameters; default is all zeros; + * use this structure to change default settings + */ +struct dpni_cfg { + uint8_t mac_addr[6]; + /** + * struct adv - Advanced parameters + * @options: Mask of available options; use 'DPNI_OPT_' values + * @start_hdr: Selects the packet starting header for parsing; + * 'NET_PROT_NONE' is treated as default: 'NET_PROT_ETH' + * @max_senders: Maximum number of different senders; used as the number + * of dedicated Tx flows; Non-power-of-2 values are rounded + * up to the next power-of-2 value as hardware demands it; + * '0' will be treated as '1' + * @max_tcs: Maximum number of traffic classes (for both Tx and Rx); + * '0' will e treated as '1' + * @max_unicast_filters: Maximum number of unicast filters; + * '0' is treated as '16' + * @max_multicast_filters: Maximum number of multicast filters; + * '0' is treated as '64' + * @max_qos_entries: if 'max_tcs > 1', declares the maximum entries in + * the QoS table; '0' is treated as '64' + * @max_qos_key_size: Maximum key size for the QoS look-up; + * '0' is treated as '24' which is enough for IPv4 + * 5-tuple + * @max_dist_key_size: Maximum key size for the distribution; + * '0' is treated as '24' which is enough for IPv4 5-tuple + * @max_policers: Maximum number of policers; + * should be between '0' and max_tcs + * @max_congestion_ctrl: Maximum number of congestion control groups + * (CGs); covers early drop and congestion notification + * requirements; + * should be between '0' and ('max_tcs' + 'max_senders') + * @ext_cfg_iova: I/O virtual address of 256 bytes DMA-able memory + * filled with the extended configuration by calling + * dpni_prepare_extended_cfg() + */ + struct { + uint32_t options; + enum net_prot start_hdr; + uint8_t max_senders; + uint8_t max_tcs; + uint8_t max_unicast_filters; + uint8_t max_multicast_filters; + uint8_t max_vlan_filters; + uint8_t max_qos_entries; + uint8_t max_qos_key_size; + uint8_t max_dist_key_size; + uint8_t max_policers; + uint8_t max_congestion_ctrl; + uint64_t ext_cfg_iova; + } adv; +}; + +/** + * dpni_create() - Create the DPNI object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @cfg: Configuration structure + * @token: Returned token; use in subsequent API calls + * + * Create the DPNI object, allocate required resources and + * perform required initialization. + * + * The object can be created either by declaring it in the + * DPL file, or by calling this function. + * + * This function returns a unique authentication token, + * associated with the specific object ID and the specific MC + * portal; this token must be used in all subsequent calls to + * this specific object. For objects that are created using the + * DPL file, call dpni_open() function to get an authentication + * token first. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_create(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + const struct dpni_cfg *cfg, + uint16_t *token); + +/** + * dpni_destroy() - Destroy the DPNI object and release all its resources. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_destroy(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token); + +/** + * struct dpni_pools_cfg - Structure representing buffer pools configuration + * @num_dpbp: Number of DPBPs + * @pools: Array of buffer pools parameters; The number of valid entries + * must match 'num_dpbp' value + */ +struct dpni_pools_cfg { + uint8_t num_dpbp; + /** + * struct pools - Buffer pools parameters + * @dpbp_id: DPBP object ID + * @buffer_size: Buffer size + * @backup_pool: Backup pool + */ + struct { + int dpbp_id; + uint16_t buffer_size; + int backup_pool; + } pools[DPNI_MAX_DPBP]; +}; + +/** + * dpni_set_pools() - Set buffer pools configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cfg: Buffer pools configuration + * + * mandatory for DPNI operation + * warning:Allowed only when DPNI is disabled + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_pools(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_pools_cfg *cfg); + +/** + * dpni_enable() - Enable the DPNI, allow sending and receiving frames. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_enable(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token); + +/** + * dpni_disable() - Disable the DPNI, stop sending and receiving frames. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_disable(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token); + +/** + * dpni_is_enabled() - Check if the DPNI is enabled. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Returns '1' if object is enabled; '0' otherwise + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_is_enabled(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int *en); + +/** + * dpni_reset() - Reset the DPNI, returns the object to initial state. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_reset(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token); + +/** + * DPNI IRQ Index and Events + */ + +/** + * IRQ index + */ +#define DPNI_IRQ_INDEX 0 +/** + * IRQ event - indicates a change in link state + */ +#define DPNI_IRQ_EVENT_LINK_CHANGED 0x00000001 + +/** + * struct dpni_irq_cfg - IRQ configuration + * @addr: Address that must be written to signal a message-based interrupt + * @val: Value to write into irq_addr address + * @irq_num: A user defined number associated with this IRQ + */ +struct dpni_irq_cfg { + uint64_t addr; + uint32_t val; + int irq_num; +}; + +/** + * dpni_set_irq() - Set IRQ information for the DPNI to trigger an interrupt. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @irq_index: Identifies the interrupt index to configure + * @irq_cfg: IRQ configuration + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_irq(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + struct dpni_irq_cfg *irq_cfg); + +/** + * dpni_get_irq() - Get IRQ information from the DPNI. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @irq_index: The interrupt index to configure + * @type: Interrupt type: 0 represents message interrupt + * type (both irq_addr and irq_val are valid) + * @irq_cfg: IRQ attributes + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_irq(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + int *type, + struct dpni_irq_cfg *irq_cfg); + +/** + * dpni_set_irq_enable() - Set overall interrupt state. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @irq_index: The interrupt index to configure + * @en: Interrupt state: - enable = 1, disable = 0 + * + * Allows GPP software to control when interrupts are generated. + * Each interrupt can have up to 32 causes. The enable/disable control's the + * overall interrupt state. if the interrupt is disabled no causes will cause + * an interrupt. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_irq_enable(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + uint8_t en); + +/** + * dpni_get_irq_enable() - Get overall interrupt state + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @irq_index: The interrupt index to configure + * @en: Returned interrupt state - enable = 1, disable = 0 + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_irq_enable(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + uint8_t *en); + +/** + * dpni_set_irq_mask() - Set interrupt mask. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @irq_index: The interrupt index to configure + * @mask: event mask to trigger interrupt; + * each bit: + * 0 = ignore event + * 1 = consider event for asserting IRQ + * + * Every interrupt can have up to 32 causes and the interrupt model supports + * masking/unmasking each cause independently + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_irq_mask(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + uint32_t mask); + +/** + * dpni_get_irq_mask() - Get interrupt mask. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @irq_index: The interrupt index to configure + * @mask: Returned event mask to trigger interrupt + * + * Every interrupt can have up to 32 causes and the interrupt model supports + * masking/unmasking each cause independently + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_irq_mask(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + uint32_t *mask); + +/** + * dpni_get_irq_status() - Get the current status of any pending interrupts. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @irq_index: The interrupt index to configure + * @status: Returned interrupts status - one bit per cause: + * 0 = no interrupt pending + * 1 = interrupt pending + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_irq_status(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + uint32_t *status); + +/** + * dpni_clear_irq_status() - Clear a pending interrupt's status + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @irq_index: The interrupt index to configure + * @status: bits to clear (W1C) - one bit per cause: + * 0 = don't change + * 1 = clear status bit + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_clear_irq_status(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t irq_index, + uint32_t status); + +/** + * struct dpni_attr - Structure representing DPNI attributes + * @id: DPNI object ID + * @version: DPNI version + * @start_hdr: Indicates the packet starting header for parsing + * @options: Mask of available options; reflects the value as was given in + * object's creation + * @max_senders: Maximum number of different senders; used as the number + * of dedicated Tx flows; + * @max_tcs: Maximum number of traffic classes (for both Tx and Rx) + * @max_unicast_filters: Maximum number of unicast filters + * @max_multicast_filters: Maximum number of multicast filters + * @max_vlan_filters: Maximum number of VLAN filters + * @max_qos_entries: if 'max_tcs > 1', declares the maximum entries in QoS table + * @max_qos_key_size: Maximum key size for the QoS look-up + * @max_dist_key_size: Maximum key size for the distribution look-up + * @max_policers: Maximum number of policers; + * @max_congestion_ctrl: Maximum number of congestion control groups (CGs); + * @ext_cfg_iova: I/O virtual address of 256 bytes DMA-able memory; + * call dpni_extract_extended_cfg() to extract the extended configuration + */ +struct dpni_attr { + int id; + /** + * struct version - DPNI version + * @major: DPNI major version + * @minor: DPNI minor version + */ + struct { + uint16_t major; + uint16_t minor; + } version; + enum net_prot start_hdr; + uint32_t options; + uint8_t max_senders; + uint8_t max_tcs; + uint8_t max_unicast_filters; + uint8_t max_multicast_filters; + uint8_t max_vlan_filters; + uint8_t max_qos_entries; + uint8_t max_qos_key_size; + uint8_t max_dist_key_size; + uint8_t max_policers; + uint8_t max_congestion_ctrl; + uint64_t ext_cfg_iova; +}; + +/** + * dpni_get_attributes() - Retrieve DPNI attributes. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @attr: Object's attributes + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_attributes(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_attr *attr); + +/** + * dpni_extract_extended_cfg() - extract the extended parameters + * @cfg: extended structure + * @ext_cfg_buf: 256 bytes of DMA-able memory + * + * This function has to be called after dpni_get_attributes() + */ +int dpni_extract_extended_cfg(struct dpni_extended_cfg *cfg, + const uint8_t *ext_cfg_buf); + +/** + * DPNI errors + */ + +/** + * Extract out of frame header error + */ +#define DPNI_ERROR_EOFHE 0x00020000 +/** + * Frame length error + */ +#define DPNI_ERROR_FLE 0x00002000 +/** + * Frame physical error + */ +#define DPNI_ERROR_FPE 0x00001000 +/** + * Parsing header error + */ +#define DPNI_ERROR_PHE 0x00000020 +/** + * Parser L3 checksum error + */ +#define DPNI_ERROR_L3CE 0x00000004 +/** + * Parser L3 checksum error + */ +#define DPNI_ERROR_L4CE 0x00000001 + +/** + * enum dpni_error_action - Defines DPNI behavior for errors + * @DPNI_ERROR_ACTION_DISCARD: Discard the frame + * @DPNI_ERROR_ACTION_CONTINUE: Continue with the normal flow + * @DPNI_ERROR_ACTION_SEND_TO_ERROR_QUEUE: Send the frame to the error queue + */ +enum dpni_error_action { + DPNI_ERROR_ACTION_DISCARD = 0, + DPNI_ERROR_ACTION_CONTINUE = 1, + DPNI_ERROR_ACTION_SEND_TO_ERROR_QUEUE = 2 +}; + +/** + * struct dpni_error_cfg - Structure representing DPNI errors treatment + * @errors: Errors mask; use 'DPNI_ERROR__ + * @error_action: The desired action for the errors mask + * @set_frame_annotation: Set to '1' to mark the errors in frame annotation + * status (FAS); relevant only for the non-discard action + */ +struct dpni_error_cfg { + uint32_t errors; + enum dpni_error_action error_action; + int set_frame_annotation; +}; + +/** + * dpni_set_errors_behavior() - Set errors behavior + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cfg: Errors configuration + * + * this function may be called numerous times with different + * error masks + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_errors_behavior(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_error_cfg *cfg); + +/** + * DPNI buffer layout modification options + */ + +/** + * Select to modify the time-stamp setting + */ +#define DPNI_BUF_LAYOUT_OPT_TIMESTAMP 0x00000001 +/** + * Select to modify the parser-result setting; not applicable for Tx + */ +#define DPNI_BUF_LAYOUT_OPT_PARSER_RESULT 0x00000002 +/** + * Select to modify the frame-status setting + */ +#define DPNI_BUF_LAYOUT_OPT_FRAME_STATUS 0x00000004 +/** + * Select to modify the private-data-size setting + */ +#define DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE 0x00000008 +/** + * Select to modify the data-alignment setting + */ +#define DPNI_BUF_LAYOUT_OPT_DATA_ALIGN 0x00000010 +/** + * Select to modify the data-head-room setting + */ +#define DPNI_BUF_LAYOUT_OPT_DATA_HEAD_ROOM 0x00000020 +/** + * Select to modify the data-tail-room setting + */ +#define DPNI_BUF_LAYOUT_OPT_DATA_TAIL_ROOM 0x00000040 + +/** + * struct dpni_buffer_layout - Structure representing DPNI buffer layout + * @options: Flags representing the suggested modifications to the buffer + * layout; Use any combination of 'DPNI_BUF_LAYOUT_OPT_' flags + * @pass_timestamp: Pass timestamp value + * @pass_parser_result: Pass parser results + * @pass_frame_status: Pass frame status + * @private_data_size: Size kept for private data (in bytes) + * @data_align: Data alignment + * @data_head_room: Data head room + * @data_tail_room: Data tail room + */ +struct dpni_buffer_layout { + uint32_t options; + int pass_timestamp; + int pass_parser_result; + int pass_frame_status; + uint16_t private_data_size; + uint16_t data_align; + uint16_t data_head_room; + uint16_t data_tail_room; +}; + +/** + * dpni_get_rx_buffer_layout() - Retrieve Rx buffer layout attributes. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @layout: Returns buffer layout attributes + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_rx_buffer_layout(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_buffer_layout *layout); + +/** + * dpni_set_rx_buffer_layout() - Set Rx buffer layout configuration. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @layout: Buffer layout configuration + * + * Return: '0' on Success; Error code otherwise. + * + * @warning Allowed only when DPNI is disabled + */ +int dpni_set_rx_buffer_layout(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_buffer_layout *layout); + +/** + * dpni_get_tx_buffer_layout() - Retrieve Tx buffer layout attributes. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @layout: Returns buffer layout attributes + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_tx_buffer_layout(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_buffer_layout *layout); + +/** + * dpni_set_tx_buffer_layout() - Set Tx buffer layout configuration. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @layout: Buffer layout configuration + * + * Return: '0' on Success; Error code otherwise. + * + * @warning Allowed only when DPNI is disabled + */ +int dpni_set_tx_buffer_layout(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_buffer_layout *layout); + +/** + * dpni_get_tx_conf_buffer_layout() - Retrieve Tx confirmation buffer layout + * attributes. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @layout: Returns buffer layout attributes + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_tx_conf_buffer_layout(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_buffer_layout *layout); + +/** + * dpni_set_tx_conf_buffer_layout() - Set Tx confirmation buffer layout + * configuration. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @layout: Buffer layout configuration + * + * Return: '0' on Success; Error code otherwise. + * + * @warning Allowed only when DPNI is disabled + */ +int dpni_set_tx_conf_buffer_layout(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_buffer_layout *layout); + +/** + * dpni_set_l3_chksum_validation() - Enable/disable L3 checksum validation + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Set to '1' to enable; '0' to disable + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_l3_chksum_validation(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en); + +/** + * dpni_get_l3_chksum_validation() - Get L3 checksum validation mode + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Returns '1' if enabled; '0' otherwise + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_l3_chksum_validation(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int *en); + +/** + * dpni_set_l4_chksum_validation() - Enable/disable L4 checksum validation + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Set to '1' to enable; '0' to disable + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_l4_chksum_validation(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en); + +/** + * dpni_get_l4_chksum_validation() - Get L4 checksum validation mode + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Returns '1' if enabled; '0' otherwise + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_l4_chksum_validation(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int *en); + +/** + * dpni_get_qdid() - Get the Queuing Destination ID (QDID) that should be used + * for enqueue operations + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @qdid: Returned virtual QDID value that should be used as an argument + * in all enqueue operations + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_qdid(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t *qdid); + +/** + * struct dpni_sp_info - Structure representing DPNI storage-profile information + * (relevant only for DPNI owned by AIOP) + * @spids: array of storage-profiles + */ +struct dpni_sp_info { + uint16_t spids[DPNI_MAX_SP]; +}; + +/** + * dpni_get_spids() - Get the AIOP storage profile IDs associated with the DPNI + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @sp_info: Returned AIOP storage-profile information + * + * Return: '0' on Success; Error code otherwise. + * + * @warning Only relevant for DPNI that belongs to AIOP container. + */ +int dpni_get_sp_info(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_sp_info *sp_info); + +/** + * dpni_get_tx_data_offset() - Get the Tx data offset (from start of buffer) + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @data_offset: Tx data offset (from start of buffer) + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_tx_data_offset(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t *data_offset); + +/** + * enum dpni_counter - DPNI counter types + * @DPNI_CNT_ING_FRAME: Counts ingress frames + * @DPNI_CNT_ING_BYTE: Counts ingress bytes + * @DPNI_CNT_ING_FRAME_DROP: Counts ingress frames dropped due to explicit + * 'drop' setting + * @DPNI_CNT_ING_FRAME_DISCARD: Counts ingress frames discarded due to errors + * @DPNI_CNT_ING_MCAST_FRAME: Counts ingress multicast frames + * @DPNI_CNT_ING_MCAST_BYTE: Counts ingress multicast bytes + * @DPNI_CNT_ING_BCAST_FRAME: Counts ingress broadcast frames + * @DPNI_CNT_ING_BCAST_BYTES: Counts ingress broadcast bytes + * @DPNI_CNT_EGR_FRAME: Counts egress frames + * @DPNI_CNT_EGR_BYTE: Counts egress bytes + * @DPNI_CNT_EGR_FRAME_DISCARD: Counts egress frames discarded due to errors + */ +enum dpni_counter { + DPNI_CNT_ING_FRAME = 0x0, + DPNI_CNT_ING_BYTE = 0x1, + DPNI_CNT_ING_FRAME_DROP = 0x2, + DPNI_CNT_ING_FRAME_DISCARD = 0x3, + DPNI_CNT_ING_MCAST_FRAME = 0x4, + DPNI_CNT_ING_MCAST_BYTE = 0x5, + DPNI_CNT_ING_BCAST_FRAME = 0x6, + DPNI_CNT_ING_BCAST_BYTES = 0x7, + DPNI_CNT_EGR_FRAME = 0x8, + DPNI_CNT_EGR_BYTE = 0x9, + DPNI_CNT_EGR_FRAME_DISCARD = 0xa +}; + +/** + * dpni_get_counter() - Read a specific DPNI counter + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @counter: The requested counter + * @value: Returned counter's current value + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_counter(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + enum dpni_counter counter, + uint64_t *value); + +/** + * dpni_set_counter() - Set (or clear) a specific DPNI counter + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @counter: The requested counter + * @value: New counter value; typically pass '0' for resetting + * the counter. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_counter(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + enum dpni_counter counter, + uint64_t value); + +/** + * Enable auto-negotiation + */ +#define DPNI_LINK_OPT_AUTONEG 0x0000000000000001ULL +/** + * Enable half-duplex mode + */ +#define DPNI_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL +/** + * Enable pause frames + */ +#define DPNI_LINK_OPT_PAUSE 0x0000000000000004ULL +/** + * Enable a-symmetric pause frames + */ +#define DPNI_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL + +/** + * struct - Structure representing DPNI link configuration + * @rate: Rate + * @options: Mask of available options; use 'DPNI_LINK_OPT_' values + */ +struct dpni_link_cfg { + uint32_t rate; + uint64_t options; +}; + +/** + * dpni_set_link_cfg() - set the link configuration. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cfg: Link configuration + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_link_cfg(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_link_cfg *cfg); + +/** + * struct dpni_link_state - Structure representing DPNI link state + * @rate: Rate + * @options: Mask of available options; use 'DPNI_LINK_OPT_' values + * @up: Link state; '0' for down, '1' for up + */ +struct dpni_link_state { + uint32_t rate; + uint64_t options; + int up; +}; + +/** + * dpni_get_link_state() - Return the link state (either up or down) + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @state: Returned link state; + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_link_state(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_link_state *state); + +/** + * struct dpni_tx_shaping - Structure representing DPNI tx shaping configuration + * @rate_limit: rate in Mbps + * @max_burst_size: burst size in bytes (up to 64KB) + */ +struct dpni_tx_shaping_cfg { + uint32_t rate_limit; + uint16_t max_burst_size; +}; + +/** + * dpni_set_tx_shaping() - Set the transmit shaping + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tx_shaper: tx shaping configuration + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_tx_shaping(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_tx_shaping_cfg *tx_shaper); + +/** + * dpni_set_max_frame_length() - Set the maximum received frame length. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @max_frame_length: Maximum received frame length (in + * bytes); frame is discarded if its + * length exceeds this value + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_max_frame_length(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t max_frame_length); + +/** + * dpni_get_max_frame_length() - Get the maximum received frame length. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @max_frame_length: Maximum received frame length (in + * bytes); frame is discarded if its + * length exceeds this value + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_max_frame_length(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t *max_frame_length); + +/** + * dpni_set_mtu() - Set the MTU for the interface. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @mtu: MTU length (in bytes) + * + * MTU determines the maximum fragment size for performing IP + * fragmentation on egress packets. + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_mtu(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t mtu); + +/** + * dpni_get_mtu() - Get the MTU. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @mtu: Returned MTU length (in bytes) + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_mtu(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t *mtu); + +/** + * dpni_set_multicast_promisc() - Enable/disable multicast promiscuous mode + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Set to '1' to enable; '0' to disable + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_multicast_promisc(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en); + +/** + * dpni_get_multicast_promisc() - Get multicast promiscuous mode + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Returns '1' if enabled; '0' otherwise + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_multicast_promisc(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int *en); + +/** + * dpni_set_unicast_promisc() - Enable/disable unicast promiscuous mode + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Set to '1' to enable; '0' to disable + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_unicast_promisc(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en); + +/** + * dpni_get_unicast_promisc() - Get unicast promiscuous mode + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Returns '1' if enabled; '0' otherwise + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_unicast_promisc(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int *en); + +/** + * dpni_set_primary_mac_addr() - Set the primary MAC address + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @mac_addr: MAC address to set as primary address + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_primary_mac_addr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const uint8_t mac_addr[6]); + +/** + * dpni_get_primary_mac_addr() - Get the primary MAC address + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @mac_addr: Returned MAC address + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_primary_mac_addr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t mac_addr[6]); + +/** + * dpni_add_mac_addr() - Add MAC address filter + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @mac_addr: MAC address to add + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_add_mac_addr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const uint8_t mac_addr[6]); + +/** + * dpni_remove_mac_addr() - Remove MAC address filter + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @mac_addr: MAC address to remove + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_remove_mac_addr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const uint8_t mac_addr[6]); + +/** + * dpni_clear_mac_filters() - Clear all unicast and/or multicast MAC filters + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @unicast: Set to '1' to clear unicast addresses + * @multicast: Set to '1' to clear multicast addresses + * + * The primary MAC address is not cleared by this operation. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_clear_mac_filters(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int unicast, + int multicast); + +/** + * dpni_set_vlan_filters() - Enable/disable VLAN filtering mode + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Set to '1' to enable; '0' to disable + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_vlan_filters(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en); + +/** + * dpni_add_vlan_id() - Add VLAN ID filter + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @vlan_id: VLAN ID to add + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_add_vlan_id(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t vlan_id); + +/** + * dpni_remove_vlan_id() - Remove VLAN ID filter + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @vlan_id: VLAN ID to remove + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_remove_vlan_id(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t vlan_id); + +/** + * dpni_clear_vlan_filters() - Clear all VLAN filters + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_clear_vlan_filters(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token); + +/** + * enum dpni_tx_schedule_mode - DPNI Tx scheduling mode + * @DPNI_TX_SCHED_STRICT_PRIORITY: strict priority + * @DPNI_TX_SCHED_WEIGHTED: weighted based scheduling + */ +enum dpni_tx_schedule_mode { + DPNI_TX_SCHED_STRICT_PRIORITY, + DPNI_TX_SCHED_WEIGHTED, +}; + +/** + * struct dpni_tx_schedule_cfg - Structure representing Tx + * scheduling configuration + * @mode: scheduling mode + * @delta_bandwidth: Bandwidth represented in weights from 100 to 10000; + * not applicable for 'strict-priority' mode; + */ +struct dpni_tx_schedule_cfg { + enum dpni_tx_schedule_mode mode; + uint16_t delta_bandwidth; +}; + +/** + * struct dpni_tx_selection_cfg - Structure representing transmission + * selection configuration + * @tc_sched: an array of traffic-classes + */ +struct dpni_tx_selection_cfg { + struct dpni_tx_schedule_cfg tc_sched[DPNI_MAX_TC]; +}; + +/** + * dpni_set_tx_selection() - Set transmission selection configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cfg: transmission selection configuration + * + * warning: Allowed only when DPNI is disabled + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_tx_selection(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_tx_selection_cfg *cfg); + +/** + * enum dpni_dist_mode - DPNI distribution mode + * @DPNI_DIST_MODE_NONE: No distribution + * @DPNI_DIST_MODE_HASH: Use hash distribution; only relevant if + * the 'DPNI_OPT_DIST_HASH' option was set at DPNI creation + * @DPNI_DIST_MODE_FS: Use explicit flow steering; only relevant if + * the 'DPNI_OPT_DIST_FS' option was set at DPNI creation + */ +enum dpni_dist_mode { + DPNI_DIST_MODE_NONE = 0, + DPNI_DIST_MODE_HASH = 1, + DPNI_DIST_MODE_FS = 2 +}; + +/** + * enum dpni_fs_miss_action - DPNI Flow Steering miss action + * @DPNI_FS_MISS_DROP: In case of no-match, drop the frame + * @DPNI_FS_MISS_EXPLICIT_FLOWID: In case of no-match, use explicit flow-id + * @DPNI_FS_MISS_HASH: In case of no-match, distribute using hash + */ +enum dpni_fs_miss_action { + DPNI_FS_MISS_DROP = 0, + DPNI_FS_MISS_EXPLICIT_FLOWID = 1, + DPNI_FS_MISS_HASH = 2 +}; + +/** + * struct dpni_fs_tbl_cfg - Flow Steering table configuration + * @miss_action: Miss action selection + * @default_flow_id: Used when 'miss_action = DPNI_FS_MISS_EXPLICIT_FLOWID' + */ +struct dpni_fs_tbl_cfg { + enum dpni_fs_miss_action miss_action; + uint16_t default_flow_id; +}; + +/** + * dpni_prepare_key_cfg() - function prepare extract parameters + * @cfg: defining a full Key Generation profile (rule) + * @key_cfg_buf: Zeroed 256 bytes of memory before mapping it to DMA + * + * This function has to be called before the following functions: + * - dpni_set_rx_tc_dist() + * - dpni_set_qos_table() + */ +int dpni_prepare_key_cfg(const struct dpkg_profile_cfg *cfg, + uint8_t *key_cfg_buf); + +/** + * struct dpni_rx_tc_dist_cfg - Rx traffic class distribution configuration + * @dist_size: Set the distribution size; + * supported values: 1,2,3,4,6,7,8,12,14,16,24,28,32,48,56,64,96, + * 112,128,192,224,256,384,448,512,768,896,1024 + * @dist_mode: Distribution mode + * @key_cfg_iova: I/O virtual address of 256 bytes DMA-able memory filled with + * the extractions to be used for the distribution key by calling + * dpni_prepare_key_cfg() relevant only when + * 'dist_mode != DPNI_DIST_MODE_NONE', otherwise it can be '0' + * @fs_cfg: Flow Steering table configuration; only relevant if + * 'dist_mode = DPNI_DIST_MODE_FS' + */ +struct dpni_rx_tc_dist_cfg { + uint16_t dist_size; + enum dpni_dist_mode dist_mode; + uint64_t key_cfg_iova; + struct dpni_fs_tbl_cfg fs_cfg; +}; + +/** + * dpni_set_rx_tc_dist() - Set Rx traffic class distribution configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @cfg: Traffic class distribution configuration + * + * warning: if 'dist_mode != DPNI_DIST_MODE_NONE', call dpni_prepare_key_cfg() + * first to prepare the key_cfg_iova parameter + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_set_rx_tc_dist(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + const struct dpni_rx_tc_dist_cfg *cfg); + +/** + * Set to select color aware mode (otherwise - color blind) + */ +#define DPNI_POLICER_OPT_COLOR_AWARE 0x00000001 +/** + * Set to discard frame with RED color + */ +#define DPNI_POLICER_OPT_DISCARD_RED 0x00000002 + +/** + * enum dpni_policer_mode - selecting the policer mode + * @DPNI_POLICER_MODE_NONE: Policer is disabled + * @DPNI_POLICER_MODE_PASS_THROUGH: Policer pass through + * @DPNI_POLICER_MODE_RFC_2698: Policer algorithm RFC 2698 + * @DPNI_POLICER_MODE_RFC_4115: Policer algorithm RFC 4115 + */ +enum dpni_policer_mode { + DPNI_POLICER_MODE_NONE = 0, + DPNI_POLICER_MODE_PASS_THROUGH, + DPNI_POLICER_MODE_RFC_2698, + DPNI_POLICER_MODE_RFC_4115 +}; + +/** + * enum dpni_policer_unit - DPNI policer units + * @DPNI_POLICER_UNIT_BYTES: bytes units + * @DPNI_POLICER_UNIT_FRAMES: frames units + */ +enum dpni_policer_unit { + DPNI_POLICER_UNIT_BYTES = 0, + DPNI_POLICER_UNIT_FRAMES +}; + +/** + * enum dpni_policer_color - selecting the policer color + * @DPNI_POLICER_COLOR_GREEN: Green color + * @DPNI_POLICER_COLOR_YELLOW: Yellow color + * @DPNI_POLICER_COLOR_RED: Red color + */ +enum dpni_policer_color { + DPNI_POLICER_COLOR_GREEN = 0, + DPNI_POLICER_COLOR_YELLOW, + DPNI_POLICER_COLOR_RED +}; + +/** + * struct dpni_rx_tc_policing_cfg - Policer configuration + * @options: Mask of available options; use 'DPNI_POLICER_OPT_' values + * @mode: policer mode + * @default_color: For pass-through mode the policer re-colors with this + * color any incoming packets. For Color aware non-pass-through mode: + * policer re-colors with this color all packets with FD[DROPP]>2. + * @units: Bytes or Packets + * @cir: Committed information rate (CIR) in Kbps or packets/second + * @cbs: Committed burst size (CBS) in bytes or packets + * @eir: Peak information rate (PIR, rfc2698) in Kbps or packets/second + * Excess information rate (EIR, rfc4115) in Kbps or packets/second + * @ebs: Peak burst size (PBS, rfc2698) in bytes or packets + * Excess burst size (EBS, rfc4115) in bytes or packets + */ +struct dpni_rx_tc_policing_cfg { + uint32_t options; + enum dpni_policer_mode mode; + enum dpni_policer_unit units; + enum dpni_policer_color default_color; + uint32_t cir; + uint32_t cbs; + uint32_t eir; + uint32_t ebs; +}; + +/** + * dpni_set_rx_tc_policing() - Set Rx traffic class policing configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @cfg: Traffic class policing configuration + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_set_rx_tc_policing(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + const struct dpni_rx_tc_policing_cfg *cfg); + +/** + * dpni_get_rx_tc_policing() - Get Rx traffic class policing configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @cfg: Traffic class policing configuration + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_get_rx_tc_policing(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + struct dpni_rx_tc_policing_cfg *cfg); + +/** + * enum dpni_congestion_unit - DPNI congestion units + * @DPNI_CONGESTION_UNIT_BYTES: bytes units + * @DPNI_CONGESTION_UNIT_FRAMES: frames units + */ +enum dpni_congestion_unit { + DPNI_CONGESTION_UNIT_BYTES = 0, + DPNI_CONGESTION_UNIT_FRAMES +}; + +/** + * enum dpni_early_drop_mode - DPNI early drop mode + * @DPNI_EARLY_DROP_MODE_NONE: early drop is disabled + * @DPNI_EARLY_DROP_MODE_TAIL: early drop in taildrop mode + * @DPNI_EARLY_DROP_MODE_WRED: early drop in WRED mode + */ +enum dpni_early_drop_mode { + DPNI_EARLY_DROP_MODE_NONE = 0, + DPNI_EARLY_DROP_MODE_TAIL, + DPNI_EARLY_DROP_MODE_WRED +}; + +/** + * struct dpni_wred_cfg - WRED configuration + * @max_threshold: maximum threshold that packets may be discarded. Above this + * threshold all packets are discarded; must be less than 2^39; + * approximated to be expressed as (x+256)*2^(y-1) due to HW + * implementation. + * @min_threshold: minimum threshold that packets may be discarded at + * @drop_probability: probability that a packet will be discarded (1-100, + * associated with the max_threshold). + */ +struct dpni_wred_cfg { + uint64_t max_threshold; + uint64_t min_threshold; + uint8_t drop_probability; +}; + +/** + * struct dpni_early_drop_cfg - early-drop configuration + * @mode: drop mode + * @units: units type + * @green: WRED - 'green' configuration + * @yellow: WRED - 'yellow' configuration + * @red: WRED - 'red' configuration + * @tail_drop_threshold: tail drop threshold + */ +struct dpni_early_drop_cfg { + enum dpni_early_drop_mode mode; + enum dpni_congestion_unit units; + + struct dpni_wred_cfg green; + struct dpni_wred_cfg yellow; + struct dpni_wred_cfg red; + + uint32_t tail_drop_threshold; +}; + +/** + * dpni_prepare_early_drop() - prepare an early drop. + * @cfg: Early-drop configuration + * @early_drop_buf: Zeroed 256 bytes of memory before mapping it to DMA + * + * This function has to be called before dpni_set_rx_tc_early_drop or + * dpni_set_tx_tc_early_drop + * + */ +void dpni_prepare_early_drop(const struct dpni_early_drop_cfg *cfg, + uint8_t *early_drop_buf); + +/** + * dpni_extract_early_drop() - extract the early drop configuration. + * @cfg: Early-drop configuration + * @early_drop_buf: Zeroed 256 bytes of memory before mapping it to DMA + * + * This function has to be called after dpni_get_rx_tc_early_drop or + * dpni_get_tx_tc_early_drop + * + */ +void dpni_extract_early_drop(struct dpni_early_drop_cfg *cfg, + const uint8_t *early_drop_buf); + +/** + * dpni_set_rx_tc_early_drop() - Set Rx traffic class early-drop configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @early_drop_iova: I/O virtual address of 256 bytes DMA-able memory filled + * with the early-drop configuration by calling dpni_prepare_early_drop() + * + * warning: Before calling this function, call dpni_prepare_early_drop() to + * prepare the early_drop_iova parameter + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_set_rx_tc_early_drop(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + uint64_t early_drop_iova); + +/** + * dpni_get_rx_tc_early_drop() - Get Rx traffic class early-drop configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @early_drop_iova: I/O virtual address of 256 bytes DMA-able memory + * + * warning: After calling this function, call dpni_extract_early_drop() to + * get the early drop configuration + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_get_rx_tc_early_drop(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + uint64_t early_drop_iova); + +/** + * dpni_set_tx_tc_early_drop() - Set Tx traffic class early-drop configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @early_drop_iova: I/O virtual address of 256 bytes DMA-able memory filled + * with the early-drop configuration by calling dpni_prepare_early_drop() + * + * warning: Before calling this function, call dpni_prepare_early_drop() to + * prepare the early_drop_iova parameter + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_set_tx_tc_early_drop(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + uint64_t early_drop_iova); + +/** + * dpni_get_tx_tc_early_drop() - Get Tx traffic class early-drop configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @early_drop_iova: I/O virtual address of 256 bytes DMA-able memory + * + * warning: After calling this function, call dpni_extract_early_drop() to + * get the early drop configuration + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_get_tx_tc_early_drop(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + uint64_t early_drop_iova); + +/** + * enum dpni_dest - DPNI destination types + * @DPNI_DEST_NONE: Unassigned destination; The queue is set in parked mode and + * does not generate FQDAN notifications; user is expected to + * dequeue from the queue based on polling or other user-defined + * method + * @DPNI_DEST_DPIO: The queue is set in schedule mode and generates FQDAN + * notifications to the specified DPIO; user is expected to dequeue + * from the queue only after notification is received + * @DPNI_DEST_DPCON: The queue is set in schedule mode and does not generate + * FQDAN notifications, but is connected to the specified DPCON + * object; user is expected to dequeue from the DPCON channel + */ +enum dpni_dest { + DPNI_DEST_NONE = 0, + DPNI_DEST_DPIO = 1, + DPNI_DEST_DPCON = 2 +}; + +/** + * struct dpni_dest_cfg - Structure representing DPNI destination parameters + * @dest_type: Destination type + * @dest_id: Either DPIO ID or DPCON ID, depending on the destination type + * @priority: Priority selection within the DPIO or DPCON channel; valid values + * are 0-1 or 0-7, depending on the number of priorities in that + * channel; not relevant for 'DPNI_DEST_NONE' option + */ +struct dpni_dest_cfg { + enum dpni_dest dest_type; + int dest_id; + uint8_t priority; +}; + +/* DPNI congestion options */ + +/** + * CSCN message is written to message_iova once entering a + * congestion state (see 'threshold_entry') + */ +#define DPNI_CONG_OPT_WRITE_MEM_ON_ENTER 0x00000001 +/** + * CSCN message is written to message_iova once exiting a + * congestion state (see 'threshold_exit') + */ +#define DPNI_CONG_OPT_WRITE_MEM_ON_EXIT 0x00000002 +/** + * CSCN write will attempt to allocate into a cache (coherent write); + * valid only if 'DPNI_CONG_OPT_WRITE_MEM_' is selected + */ +#define DPNI_CONG_OPT_COHERENT_WRITE 0x00000004 +/** + * if 'dest_cfg.dest_type != DPNI_DEST_NONE' CSCN message is sent to + * DPIO/DPCON's WQ channel once entering a congestion state + * (see 'threshold_entry') + */ +#define DPNI_CONG_OPT_NOTIFY_DEST_ON_ENTER 0x00000008 +/** + * if 'dest_cfg.dest_type != DPNI_DEST_NONE' CSCN message is sent to + * DPIO/DPCON's WQ channel once exiting a congestion state + * (see 'threshold_exit') + */ +#define DPNI_CONG_OPT_NOTIFY_DEST_ON_EXIT 0x00000010 +/** + * if 'dest_cfg.dest_type != DPNI_DEST_NONE' when the CSCN is written to the + * sw-portal's DQRR, the DQRI interrupt is asserted immediately (if enabled) + */ +#define DPNI_CONG_OPT_INTR_COALESCING_DISABLED 0x00000020 + +/** + * struct dpni_congestion_notification_cfg - congestion notification + * configuration + * @units: units type + * @threshold_entry: above this threshold we enter a congestion state. + * set it to '0' to disable it + * @threshold_exit: below this threshold we exit the congestion state. + * @message_ctx: The context that will be part of the CSCN message + * @message_iova: I/O virtual address (must be in DMA-able memory), + * must be 16B aligned; valid only if 'DPNI_CONG_OPT_WRITE_MEM_' is + * contained in 'options' + * @dest_cfg: CSCN can be send to either DPIO or DPCON WQ channel + * @options: Mask of available options; use 'DPNI_CONG_OPT_' values + */ + +struct dpni_congestion_notification_cfg { + enum dpni_congestion_unit units; + uint32_t threshold_entry; + uint32_t threshold_exit; + uint64_t message_ctx; + uint64_t message_iova; + struct dpni_dest_cfg dest_cfg; + uint16_t options; +}; + +/** + * dpni_set_rx_tc_congestion_notification() - Set Rx traffic class congestion + * notification configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @cfg: congestion notification configuration + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_set_rx_tc_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + const struct dpni_congestion_notification_cfg *cfg); + +/** + * dpni_get_rx_tc_congestion_notification() - Get Rx traffic class congestion + * notification configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @cfg: congestion notification configuration + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_get_rx_tc_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + struct dpni_congestion_notification_cfg *cfg); + +/** + * dpni_set_tx_tc_congestion_notification() - Set Tx traffic class congestion + * notification configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @cfg: congestion notification configuration + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_set_tx_tc_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + const struct dpni_congestion_notification_cfg *cfg); + +/** + * dpni_get_tx_tc_congestion_notification() - Get Tx traffic class congestion + * notification configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @cfg: congestion notification configuration + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_get_tx_tc_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + struct dpni_congestion_notification_cfg *cfg); + +/** + * enum dpni_flc_type - DPNI FLC types + * @DPNI_FLC_USER_DEFINED: select the FLC to be used for user defined value + * @DPNI_FLC_STASH: select the FLC to be used for stash control + */ +enum dpni_flc_type { + DPNI_FLC_USER_DEFINED = 0, + DPNI_FLC_STASH = 1, +}; + +/** + * enum dpni_stash_size - DPNI FLC stashing size + * @DPNI_STASH_SIZE_0B: no stash + * @DPNI_STASH_SIZE_64B: stashes 64 bytes + * @DPNI_STASH_SIZE_128B: stashes 128 bytes + * @DPNI_STASH_SIZE_192B: stashes 192 bytes + */ +enum dpni_stash_size { + DPNI_STASH_SIZE_0B = 0, + DPNI_STASH_SIZE_64B = 1, + DPNI_STASH_SIZE_128B = 2, + DPNI_STASH_SIZE_192B = 3, +}; + +/* DPNI FLC stash options */ + +/** + * stashes the whole annotation area (up to 192 bytes) + */ +#define DPNI_FLC_STASH_FRAME_ANNOTATION 0x00000001 + +/** + * struct dpni_flc_cfg - Structure representing DPNI FLC configuration + * @flc_type: FLC type + * @options: Mask of available options; + * use 'DPNI_FLC_STASH_' values + * @frame_data_size: Size of frame data to be stashed + * @flow_context_size: Size of flow context to be stashed + * @flow_context: 1. In case flc_type is 'DPNI_FLC_USER_DEFINED': + * this value will be provided in the frame descriptor + * (FD[FLC]) + * 2. In case flc_type is 'DPNI_FLC_STASH': + * this value will be I/O virtual address of the + * flow-context; + * Must be cacheline-aligned and DMA-able memory + */ +struct dpni_flc_cfg { + enum dpni_flc_type flc_type; + uint32_t options; + enum dpni_stash_size frame_data_size; + enum dpni_stash_size flow_context_size; + uint64_t flow_context; +}; + +/** + * DPNI queue modification options + */ + +/** + * Select to modify the user's context associated with the queue + */ +#define DPNI_QUEUE_OPT_USER_CTX 0x00000001 +/** + * Select to modify the queue's destination + */ +#define DPNI_QUEUE_OPT_DEST 0x00000002 +/** Select to modify the flow-context parameters; + * not applicable for Tx-conf/Err queues as the FD comes from the user + */ +#define DPNI_QUEUE_OPT_FLC 0x00000004 +/** + * Select to modify the queue's order preservation + */ +#define DPNI_QUEUE_OPT_ORDER_PRESERVATION 0x00000008 +/* Select to modify the queue's tail-drop threshold */ +#define DPNI_QUEUE_OPT_TAILDROP_THRESHOLD 0x00000010 + +/** + * struct dpni_queue_cfg - Structure representing queue configuration + * @options: Flags representing the suggested modifications to the queue; + * Use any combination of 'DPNI_QUEUE_OPT_' flags + * @user_ctx: User context value provided in the frame descriptor of each + * dequeued frame; valid only if 'DPNI_QUEUE_OPT_USER_CTX' + * is contained in 'options' + * @dest_cfg: Queue destination parameters; + * valid only if 'DPNI_QUEUE_OPT_DEST' is contained in 'options' + * @flc_cfg: Flow context configuration; in case the TC's distribution + * is either NONE or HASH the FLC's settings of flow#0 are used. + * in the case of FS (flow-steering) the flow's FLC settings + * are used. + * valid only if 'DPNI_QUEUE_OPT_FLC' is contained in 'options' + * @order_preservation_en: enable/disable order preservation; + * valid only if 'DPNI_QUEUE_OPT_ORDER_PRESERVATION' is contained + * in 'options' + * @tail_drop_threshold: set the queue's tail drop threshold in bytes; + * '0' value disable the threshold; maximum value is 0xE000000; + * valid only if 'DPNI_QUEUE_OPT_TAILDROP_THRESHOLD' is contained + * in 'options' + */ +struct dpni_queue_cfg { + uint32_t options; + uint64_t user_ctx; + struct dpni_dest_cfg dest_cfg; + struct dpni_flc_cfg flc_cfg; + int order_preservation_en; + uint32_t tail_drop_threshold; +}; + +/** + * struct dpni_queue_attr - Structure representing queue attributes + * @user_ctx: User context value provided in the frame descriptor of each + * dequeued frame + * @dest_cfg: Queue destination configuration + * @flc_cfg: Flow context configuration + * @order_preservation_en: enable/disable order preservation + * @tail_drop_threshold: queue's tail drop threshold in bytes; + * @fqid: Virtual fqid value to be used for dequeue operations + */ +struct dpni_queue_attr { + uint64_t user_ctx; + struct dpni_dest_cfg dest_cfg; + struct dpni_flc_cfg flc_cfg; + int order_preservation_en; + uint32_t tail_drop_threshold; + + uint32_t fqid; +}; + +/** + * DPNI Tx flow modification options + */ + +/** + * Select to modify the settings for dedicate Tx confirmation/error + */ +#define DPNI_TX_FLOW_OPT_TX_CONF_ERROR 0x00000001 +/** + * Select to modify the L3 checksum generation setting + */ +#define DPNI_TX_FLOW_OPT_L3_CHKSUM_GEN 0x00000010 +/** + * Select to modify the L4 checksum generation setting + */ +#define DPNI_TX_FLOW_OPT_L4_CHKSUM_GEN 0x00000020 + +/** + * struct dpni_tx_flow_cfg - Structure representing Tx flow configuration + * @options: Flags representing the suggested modifications to the Tx flow; + * Use any combination 'DPNI_TX_FLOW_OPT_' flags + * @use_common_tx_conf_queue: Set to '1' to use the common (default) Tx + * confirmation and error queue; Set to '0' to use the private + * Tx confirmation and error queue; valid only if + * 'DPNI_OPT_PRIVATE_TX_CONF_ERROR_DISABLED' wasn't set at DPNI creation + * and 'DPNI_TX_FLOW_OPT_TX_CONF_ERROR' is contained in 'options' + * @l3_chksum_gen: Set to '1' to enable L3 checksum generation; '0' to disable; + * valid only if 'DPNI_TX_FLOW_OPT_L3_CHKSUM_GEN' is contained in 'options' + * @l4_chksum_gen: Set to '1' to enable L4 checksum generation; '0' to disable; + * valid only if 'DPNI_TX_FLOW_OPT_L4_CHKSUM_GEN' is contained in 'options' + */ +struct dpni_tx_flow_cfg { + uint32_t options; + int use_common_tx_conf_queue; + int l3_chksum_gen; + int l4_chksum_gen; +}; + +/** + * dpni_set_tx_flow() - Set Tx flow configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @flow_id: Provides (or returns) the sender's flow ID; + * for each new sender set (*flow_id) to 'DPNI_NEW_FLOW_ID' to generate + * a new flow_id; this ID should be used as the QDBIN argument + * in enqueue operations + * @cfg: Tx flow configuration + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_tx_flow(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t *flow_id, + const struct dpni_tx_flow_cfg *cfg); + +/** + * struct dpni_tx_flow_attr - Structure representing Tx flow attributes + * @use_common_tx_conf_queue: '1' if using common (default) Tx confirmation and + * error queue; '0' if using private Tx confirmation and error queue + * @l3_chksum_gen: '1' if L3 checksum generation is enabled; '0' if disabled + * @l4_chksum_gen: '1' if L4 checksum generation is enabled; '0' if disabled + */ +struct dpni_tx_flow_attr { + int use_common_tx_conf_queue; + int l3_chksum_gen; + int l4_chksum_gen; +}; + +/** + * dpni_get_tx_flow() - Get Tx flow attributes + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @flow_id: The sender's flow ID, as returned by the + * dpni_set_tx_flow() function + * @attr: Returned Tx flow attributes + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_tx_flow(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t flow_id, + struct dpni_tx_flow_attr *attr); + +/** + * struct dpni_tx_conf_cfg - Structure representing Tx conf configuration + * @errors_only: Set to '1' to report back only error frames; + * Set to '0' to confirm transmission/error for all transmitted frames; + * @queue_cfg: Queue configuration + */ +struct dpni_tx_conf_cfg { + int errors_only; + struct dpni_queue_cfg queue_cfg; +}; + +/** + * dpni_set_tx_conf() - Set Tx confirmation and error queue configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @flow_id: The sender's flow ID, as returned by the + * dpni_set_tx_flow() function; + * use 'DPNI_COMMON_TX_CONF' for common tx-conf + * @cfg: Queue configuration + * + * If either 'DPNI_OPT_TX_CONF_DISABLED' or + * 'DPNI_OPT_PRIVATE_TX_CONF_ERROR_DISABLED' were selected at DPNI creation, + * this function can ONLY be used with 'flow_id == DPNI_COMMON_TX_CONF'; + * i.e. only serve the common tx-conf-err queue; + * if 'DPNI_OPT_TX_CONF_DISABLED' was selected, only error frames are reported + * back - successfully transmitted frames are not confirmed. Otherwise, all + * transmitted frames are sent for confirmation. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_tx_conf(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t flow_id, + const struct dpni_tx_conf_cfg *cfg); + +/** + * struct dpni_tx_conf_attr - Structure representing Tx conf attributes + * @errors_only: '1' if only error frames are reported back; '0' if all + * transmitted frames are confirmed + * @queue_attr: Queue attributes + */ +struct dpni_tx_conf_attr { + int errors_only; + struct dpni_queue_attr queue_attr; +}; + +/** + * dpni_get_tx_conf() - Get Tx confirmation and error queue attributes + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @flow_id: The sender's flow ID, as returned by the + * dpni_set_tx_flow() function; + * use 'DPNI_COMMON_TX_CONF' for common tx-conf + * @attr: Returned tx-conf attributes + * + * If either 'DPNI_OPT_TX_CONF_DISABLED' or + * 'DPNI_OPT_PRIVATE_TX_CONF_ERROR_DISABLED' were selected at DPNI creation, + * this function can ONLY be used with 'flow_id == DPNI_COMMON_TX_CONF'; + * i.e. only serve the common tx-conf-err queue; + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_tx_conf(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t flow_id, + struct dpni_tx_conf_attr *attr); + +/** + * dpni_set_tx_conf_congestion_notification() - Set Tx conf congestion + * notification configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @flow_id: The sender's flow ID, as returned by the + * dpni_set_tx_flow() function; + * use 'DPNI_COMMON_TX_CONF' for common tx-conf + * @cfg: congestion notification configuration + * + * If either 'DPNI_OPT_TX_CONF_DISABLED' or + * 'DPNI_OPT_PRIVATE_TX_CONF_ERROR_DISABLED' were selected at DPNI creation, + * this function can ONLY be used with 'flow_id == DPNI_COMMON_TX_CONF'; + * i.e. only serve the common tx-conf-err queue; + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_set_tx_conf_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t flow_id, + const struct dpni_congestion_notification_cfg *cfg); + +/** + * dpni_get_tx_conf_congestion_notification() - Get Tx conf congestion + * notification configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @flow_id: The sender's flow ID, as returned by the + * dpni_set_tx_flow() function; + * use 'DPNI_COMMON_TX_CONF' for common tx-conf + * @cfg: congestion notification + * + * If either 'DPNI_OPT_TX_CONF_DISABLED' or + * 'DPNI_OPT_PRIVATE_TX_CONF_ERROR_DISABLED' were selected at DPNI creation, + * this function can ONLY be used with 'flow_id == DPNI_COMMON_TX_CONF'; + * i.e. only serve the common tx-conf-err queue; + * + * Return: '0' on Success; error code otherwise. + */ +int dpni_get_tx_conf_congestion_notification(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t flow_id, + struct dpni_congestion_notification_cfg *cfg); + +/** + * dpni_set_tx_conf_revoke() - Tx confirmation revocation + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @revoke: revoke or not + * + * This function is useful only when 'DPNI_OPT_TX_CONF_DISABLED' is not + * selected at DPNI creation. + * Calling this function with 'revoke' set to '1' disables all transmit + * confirmation (including the private confirmation queues), regardless of + * previous settings; Note that in this case, Tx error frames are still + * enqueued to the general transmit errors queue. + * Calling this function with 'revoke' set to '0' restores the previous + * settings for both general and private transmit confirmation. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_tx_conf_revoke(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int revoke); + +/** + * dpni_set_rx_flow() - Set Rx flow configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7); + * use 'DPNI_ALL_TCS' to set all TCs and all flows + * @flow_id: Rx flow id within the traffic class; use + * 'DPNI_ALL_TC_FLOWS' to set all flows within + * this tc_id; ignored if tc_id is set to + * 'DPNI_ALL_TCS'; + * @cfg: Rx flow configuration + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_rx_flow(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + uint16_t flow_id, + const struct dpni_queue_cfg *cfg); + +/** + * dpni_get_rx_flow() - Get Rx flow attributes + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @flow_id: Rx flow id within the traffic class + * @attr: Returned Rx flow attributes + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_rx_flow(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + uint16_t flow_id, + struct dpni_queue_attr *attr); + +/** + * dpni_set_rx_err_queue() - Set Rx error queue configuration + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cfg: Queue configuration + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_rx_err_queue(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_queue_cfg *cfg); + +/** + * dpni_get_rx_err_queue() - Get Rx error queue attributes + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @attr: Returned Queue attributes + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_get_rx_err_queue(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_queue_attr *attr); + +/** + * struct dpni_qos_tbl_cfg - Structure representing QOS table configuration + * @key_cfg_iova: I/O virtual address of 256 bytes DMA-able memory filled with + * key extractions to be used as the QoS criteria by calling + * dpni_prepare_key_cfg() + * @discard_on_miss: Set to '1' to discard frames in case of no match (miss); + * '0' to use the 'default_tc' in such cases + * @default_tc: Used in case of no-match and 'discard_on_miss'= 0 + */ +struct dpni_qos_tbl_cfg { + uint64_t key_cfg_iova; + int discard_on_miss; + uint8_t default_tc; +}; + +/** + * dpni_set_qos_table() - Set QoS mapping table + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cfg: QoS table configuration + * + * This function and all QoS-related functions require that + *'max_tcs > 1' was set at DPNI creation. + * + * warning: Before calling this function, call dpni_prepare_key_cfg() to + * prepare the key_cfg_iova parameter + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_qos_table(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_qos_tbl_cfg *cfg); + +/** + * struct dpni_rule_cfg - Rule configuration for table lookup + * @key_iova: I/O virtual address of the key (must be in DMA-able memory) + * @mask_iova: I/O virtual address of the mask (must be in DMA-able memory) + * @key_size: key and mask size (in bytes) + */ +struct dpni_rule_cfg { + uint64_t key_iova; + uint64_t mask_iova; + uint8_t key_size; +}; + +/** + * dpni_add_qos_entry() - Add QoS mapping entry (to select a traffic class) + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cfg: QoS rule to add + * @tc_id: Traffic class selection (0-7) + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_add_qos_entry(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_rule_cfg *cfg, + uint8_t tc_id); + +/** + * dpni_remove_qos_entry() - Remove QoS mapping entry + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @cfg: QoS rule to remove + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_remove_qos_entry(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + const struct dpni_rule_cfg *cfg); + +/** + * dpni_clear_qos_table() - Clear all QoS mapping entries + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * + * Following this function call, all frames are directed to + * the default traffic class (0) + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_clear_qos_table(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token); + +/** + * dpni_add_fs_entry() - Add Flow Steering entry for a specific traffic class + * (to select a flow ID) + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @cfg: Flow steering rule to add + * @flow_id: Flow id selection (must be smaller than the + * distribution size of the traffic class) + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_add_fs_entry(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + const struct dpni_rule_cfg *cfg, + uint16_t flow_id); + +/** + * dpni_remove_fs_entry() - Remove Flow Steering entry from a specific + * traffic class + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * @cfg: Flow steering rule to remove + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_remove_fs_entry(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id, + const struct dpni_rule_cfg *cfg); + +/** + * dpni_clear_fs_entries() - Clear all Flow Steering entries of a specific + * traffic class + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @tc_id: Traffic class selection (0-7) + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_clear_fs_entries(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint8_t tc_id); + +/** + * dpni_set_vlan_insertion() - Enable/disable VLAN insertion for egress frames + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Set to '1' to enable; '0' to disable + * + * Requires that the 'DPNI_OPT_VLAN_MANIPULATION' option is set + * at DPNI creation. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_vlan_insertion(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en); + +/** + * dpni_set_vlan_removal() - Enable/disable VLAN removal for ingress frames + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Set to '1' to enable; '0' to disable + * + * Requires that the 'DPNI_OPT_VLAN_MANIPULATION' option is set + * at DPNI creation. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_vlan_removal(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en); + +/** + * dpni_set_ipr() - Enable/disable IP reassembly of ingress frames + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Set to '1' to enable; '0' to disable + * + * Requires that the 'DPNI_OPT_IPR' option is set at DPNI creation. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_ipr(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en); + +/** + * dpni_set_ipf() - Enable/disable IP fragmentation of egress frames + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPNI object + * @en: Set to '1' to enable; '0' to disable + * + * Requires that the 'DPNI_OPT_IPF' option is set at DPNI + * creation. Fragmentation is performed according to MTU value + * set by dpni_set_mtu() function + * + * Return: '0' on Success; Error code otherwise. + */ +int dpni_set_ipf(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + int en); + +#endif /* __FSL_DPNI_H */ --- a/drivers/staging/fsl-mc/include/mc-cmd.h +++ b/drivers/staging/fsl-mc/include/mc-cmd.h @@ -103,8 +103,11 @@ enum mc_cmd_status { #define MC_CMD_HDR_READ_FLAGS(_hdr) \ ((u32)mc_dec((_hdr), MC_CMD_HDR_FLAGS_O, MC_CMD_HDR_FLAGS_S)) +#define MC_PREP_OP(_ext, _param, _offset, _width, _type, _arg) \ + ((_ext)[_param] |= cpu_to_le64(mc_enc((_offset), (_width), _arg))) + #define MC_EXT_OP(_ext, _param, _offset, _width, _type, _arg) \ - ((_ext)[_param] |= mc_enc((_offset), (_width), _arg)) + (_arg = (_type)mc_dec(cpu_to_le64(_ext[_param]), (_offset), (_width))) #define MC_CMD_OP(_cmd, _param, _offset, _width, _type, _arg) \ ((_cmd).params[_param] |= mc_enc((_offset), (_width), _arg)) --- /dev/null +++ b/drivers/staging/fsl-mc/include/net.h @@ -0,0 +1,481 @@ +/* Copyright 2013-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __FSL_NET_H +#define __FSL_NET_H + +#define LAST_HDR_INDEX 0xFFFFFFFF + +/*****************************************************************************/ +/* Protocol fields */ +/*****************************************************************************/ + +/************************* Ethernet fields *********************************/ +#define NH_FLD_ETH_DA (1) +#define NH_FLD_ETH_SA (NH_FLD_ETH_DA << 1) +#define NH_FLD_ETH_LENGTH (NH_FLD_ETH_DA << 2) +#define NH_FLD_ETH_TYPE (NH_FLD_ETH_DA << 3) +#define NH_FLD_ETH_FINAL_CKSUM (NH_FLD_ETH_DA << 4) +#define NH_FLD_ETH_PADDING (NH_FLD_ETH_DA << 5) +#define NH_FLD_ETH_ALL_FIELDS ((NH_FLD_ETH_DA << 6) - 1) + +#define NH_FLD_ETH_ADDR_SIZE 6 + +/*************************** VLAN fields ***********************************/ +#define NH_FLD_VLAN_VPRI (1) +#define NH_FLD_VLAN_CFI (NH_FLD_VLAN_VPRI << 1) +#define NH_FLD_VLAN_VID (NH_FLD_VLAN_VPRI << 2) +#define NH_FLD_VLAN_LENGTH (NH_FLD_VLAN_VPRI << 3) +#define NH_FLD_VLAN_TYPE (NH_FLD_VLAN_VPRI << 4) +#define NH_FLD_VLAN_ALL_FIELDS ((NH_FLD_VLAN_VPRI << 5) - 1) + +#define NH_FLD_VLAN_TCI (NH_FLD_VLAN_VPRI | \ + NH_FLD_VLAN_CFI | \ + NH_FLD_VLAN_VID) + +/************************ IP (generic) fields ******************************/ +#define NH_FLD_IP_VER (1) +#define NH_FLD_IP_DSCP (NH_FLD_IP_VER << 2) +#define NH_FLD_IP_ECN (NH_FLD_IP_VER << 3) +#define NH_FLD_IP_PROTO (NH_FLD_IP_VER << 4) +#define NH_FLD_IP_SRC (NH_FLD_IP_VER << 5) +#define NH_FLD_IP_DST (NH_FLD_IP_VER << 6) +#define NH_FLD_IP_TOS_TC (NH_FLD_IP_VER << 7) +#define NH_FLD_IP_ID (NH_FLD_IP_VER << 8) +#define NH_FLD_IP_ALL_FIELDS ((NH_FLD_IP_VER << 9) - 1) + +#define NH_FLD_IP_PROTO_SIZE 1 + +/***************************** IPV4 fields *********************************/ +#define NH_FLD_IPV4_VER (1) +#define NH_FLD_IPV4_HDR_LEN (NH_FLD_IPV4_VER << 1) +#define NH_FLD_IPV4_TOS (NH_FLD_IPV4_VER << 2) +#define NH_FLD_IPV4_TOTAL_LEN (NH_FLD_IPV4_VER << 3) +#define NH_FLD_IPV4_ID (NH_FLD_IPV4_VER << 4) +#define NH_FLD_IPV4_FLAG_D (NH_FLD_IPV4_VER << 5) +#define NH_FLD_IPV4_FLAG_M (NH_FLD_IPV4_VER << 6) +#define NH_FLD_IPV4_OFFSET (NH_FLD_IPV4_VER << 7) +#define NH_FLD_IPV4_TTL (NH_FLD_IPV4_VER << 8) +#define NH_FLD_IPV4_PROTO (NH_FLD_IPV4_VER << 9) +#define NH_FLD_IPV4_CKSUM (NH_FLD_IPV4_VER << 10) +#define NH_FLD_IPV4_SRC_IP (NH_FLD_IPV4_VER << 11) +#define NH_FLD_IPV4_DST_IP (NH_FLD_IPV4_VER << 12) +#define NH_FLD_IPV4_OPTS (NH_FLD_IPV4_VER << 13) +#define NH_FLD_IPV4_OPTS_COUNT (NH_FLD_IPV4_VER << 14) +#define NH_FLD_IPV4_ALL_FIELDS ((NH_FLD_IPV4_VER << 15) - 1) + +#define NH_FLD_IPV4_ADDR_SIZE 4 +#define NH_FLD_IPV4_PROTO_SIZE 1 + +/***************************** IPV6 fields *********************************/ +#define NH_FLD_IPV6_VER (1) +#define NH_FLD_IPV6_TC (NH_FLD_IPV6_VER << 1) +#define NH_FLD_IPV6_SRC_IP (NH_FLD_IPV6_VER << 2) +#define NH_FLD_IPV6_DST_IP (NH_FLD_IPV6_VER << 3) +#define NH_FLD_IPV6_NEXT_HDR (NH_FLD_IPV6_VER << 4) +#define NH_FLD_IPV6_FL (NH_FLD_IPV6_VER << 5) +#define NH_FLD_IPV6_HOP_LIMIT (NH_FLD_IPV6_VER << 6) +#define NH_FLD_IPV6_ID (NH_FLD_IPV6_VER << 7) +#define NH_FLD_IPV6_ALL_FIELDS ((NH_FLD_IPV6_VER << 8) - 1) + +#define NH_FLD_IPV6_ADDR_SIZE 16 +#define NH_FLD_IPV6_NEXT_HDR_SIZE 1 + +/***************************** ICMP fields *********************************/ +#define NH_FLD_ICMP_TYPE (1) +#define NH_FLD_ICMP_CODE (NH_FLD_ICMP_TYPE << 1) +#define NH_FLD_ICMP_CKSUM (NH_FLD_ICMP_TYPE << 2) +#define NH_FLD_ICMP_ID (NH_FLD_ICMP_TYPE << 3) +#define NH_FLD_ICMP_SQ_NUM (NH_FLD_ICMP_TYPE << 4) +#define NH_FLD_ICMP_ALL_FIELDS ((NH_FLD_ICMP_TYPE << 5) - 1) + +#define NH_FLD_ICMP_CODE_SIZE 1 +#define NH_FLD_ICMP_TYPE_SIZE 1 + +/***************************** IGMP fields *********************************/ +#define NH_FLD_IGMP_VERSION (1) +#define NH_FLD_IGMP_TYPE (NH_FLD_IGMP_VERSION << 1) +#define NH_FLD_IGMP_CKSUM (NH_FLD_IGMP_VERSION << 2) +#define NH_FLD_IGMP_DATA (NH_FLD_IGMP_VERSION << 3) +#define NH_FLD_IGMP_ALL_FIELDS ((NH_FLD_IGMP_VERSION << 4) - 1) + +/***************************** TCP fields **********************************/ +#define NH_FLD_TCP_PORT_SRC (1) +#define NH_FLD_TCP_PORT_DST (NH_FLD_TCP_PORT_SRC << 1) +#define NH_FLD_TCP_SEQ (NH_FLD_TCP_PORT_SRC << 2) +#define NH_FLD_TCP_ACK (NH_FLD_TCP_PORT_SRC << 3) +#define NH_FLD_TCP_OFFSET (NH_FLD_TCP_PORT_SRC << 4) +#define NH_FLD_TCP_FLAGS (NH_FLD_TCP_PORT_SRC << 5) +#define NH_FLD_TCP_WINDOW (NH_FLD_TCP_PORT_SRC << 6) +#define NH_FLD_TCP_CKSUM (NH_FLD_TCP_PORT_SRC << 7) +#define NH_FLD_TCP_URGPTR (NH_FLD_TCP_PORT_SRC << 8) +#define NH_FLD_TCP_OPTS (NH_FLD_TCP_PORT_SRC << 9) +#define NH_FLD_TCP_OPTS_COUNT (NH_FLD_TCP_PORT_SRC << 10) +#define NH_FLD_TCP_ALL_FIELDS ((NH_FLD_TCP_PORT_SRC << 11) - 1) + +#define NH_FLD_TCP_PORT_SIZE 2 + +/***************************** UDP fields **********************************/ +#define NH_FLD_UDP_PORT_SRC (1) +#define NH_FLD_UDP_PORT_DST (NH_FLD_UDP_PORT_SRC << 1) +#define NH_FLD_UDP_LEN (NH_FLD_UDP_PORT_SRC << 2) +#define NH_FLD_UDP_CKSUM (NH_FLD_UDP_PORT_SRC << 3) +#define NH_FLD_UDP_ALL_FIELDS ((NH_FLD_UDP_PORT_SRC << 4) - 1) + +#define NH_FLD_UDP_PORT_SIZE 2 + +/*************************** UDP-lite fields *******************************/ +#define NH_FLD_UDP_LITE_PORT_SRC (1) +#define NH_FLD_UDP_LITE_PORT_DST (NH_FLD_UDP_LITE_PORT_SRC << 1) +#define NH_FLD_UDP_LITE_ALL_FIELDS \ + ((NH_FLD_UDP_LITE_PORT_SRC << 2) - 1) + +#define NH_FLD_UDP_LITE_PORT_SIZE 2 + +/*************************** UDP-encap-ESP fields **************************/ +#define NH_FLD_UDP_ENC_ESP_PORT_SRC (1) +#define NH_FLD_UDP_ENC_ESP_PORT_DST (NH_FLD_UDP_ENC_ESP_PORT_SRC << 1) +#define NH_FLD_UDP_ENC_ESP_LEN (NH_FLD_UDP_ENC_ESP_PORT_SRC << 2) +#define NH_FLD_UDP_ENC_ESP_CKSUM (NH_FLD_UDP_ENC_ESP_PORT_SRC << 3) +#define NH_FLD_UDP_ENC_ESP_SPI (NH_FLD_UDP_ENC_ESP_PORT_SRC << 4) +#define NH_FLD_UDP_ENC_ESP_SEQUENCE_NUM (NH_FLD_UDP_ENC_ESP_PORT_SRC << 5) +#define NH_FLD_UDP_ENC_ESP_ALL_FIELDS \ + ((NH_FLD_UDP_ENC_ESP_PORT_SRC << 6) - 1) + +#define NH_FLD_UDP_ENC_ESP_PORT_SIZE 2 +#define NH_FLD_UDP_ENC_ESP_SPI_SIZE 4 + +/***************************** SCTP fields *********************************/ +#define NH_FLD_SCTP_PORT_SRC (1) +#define NH_FLD_SCTP_PORT_DST (NH_FLD_SCTP_PORT_SRC << 1) +#define NH_FLD_SCTP_VER_TAG (NH_FLD_SCTP_PORT_SRC << 2) +#define NH_FLD_SCTP_CKSUM (NH_FLD_SCTP_PORT_SRC << 3) +#define NH_FLD_SCTP_ALL_FIELDS ((NH_FLD_SCTP_PORT_SRC << 4) - 1) + +#define NH_FLD_SCTP_PORT_SIZE 2 + +/***************************** DCCP fields *********************************/ +#define NH_FLD_DCCP_PORT_SRC (1) +#define NH_FLD_DCCP_PORT_DST (NH_FLD_DCCP_PORT_SRC << 1) +#define NH_FLD_DCCP_ALL_FIELDS ((NH_FLD_DCCP_PORT_SRC << 2) - 1) + +#define NH_FLD_DCCP_PORT_SIZE 2 + +/***************************** IPHC fields *********************************/ +#define NH_FLD_IPHC_CID (1) +#define NH_FLD_IPHC_CID_TYPE (NH_FLD_IPHC_CID << 1) +#define NH_FLD_IPHC_HCINDEX (NH_FLD_IPHC_CID << 2) +#define NH_FLD_IPHC_GEN (NH_FLD_IPHC_CID << 3) +#define NH_FLD_IPHC_D_BIT (NH_FLD_IPHC_CID << 4) +#define NH_FLD_IPHC_ALL_FIELDS ((NH_FLD_IPHC_CID << 5) - 1) + +/***************************** SCTP fields *********************************/ +#define NH_FLD_SCTP_CHUNK_DATA_TYPE (1) +#define NH_FLD_SCTP_CHUNK_DATA_FLAGS (NH_FLD_SCTP_CHUNK_DATA_TYPE << 1) +#define NH_FLD_SCTP_CHUNK_DATA_LENGTH (NH_FLD_SCTP_CHUNK_DATA_TYPE << 2) +#define NH_FLD_SCTP_CHUNK_DATA_TSN (NH_FLD_SCTP_CHUNK_DATA_TYPE << 3) +#define NH_FLD_SCTP_CHUNK_DATA_STREAM_ID (NH_FLD_SCTP_CHUNK_DATA_TYPE << 4) +#define NH_FLD_SCTP_CHUNK_DATA_STREAM_SQN (NH_FLD_SCTP_CHUNK_DATA_TYPE << 5) +#define NH_FLD_SCTP_CHUNK_DATA_PAYLOAD_PID (NH_FLD_SCTP_CHUNK_DATA_TYPE << 6) +#define NH_FLD_SCTP_CHUNK_DATA_UNORDERED (NH_FLD_SCTP_CHUNK_DATA_TYPE << 7) +#define NH_FLD_SCTP_CHUNK_DATA_BEGGINING (NH_FLD_SCTP_CHUNK_DATA_TYPE << 8) +#define NH_FLD_SCTP_CHUNK_DATA_END (NH_FLD_SCTP_CHUNK_DATA_TYPE << 9) +#define NH_FLD_SCTP_CHUNK_DATA_ALL_FIELDS \ + ((NH_FLD_SCTP_CHUNK_DATA_TYPE << 10) - 1) + +/*************************** L2TPV2 fields *********************************/ +#define NH_FLD_L2TPV2_TYPE_BIT (1) +#define NH_FLD_L2TPV2_LENGTH_BIT (NH_FLD_L2TPV2_TYPE_BIT << 1) +#define NH_FLD_L2TPV2_SEQUENCE_BIT (NH_FLD_L2TPV2_TYPE_BIT << 2) +#define NH_FLD_L2TPV2_OFFSET_BIT (NH_FLD_L2TPV2_TYPE_BIT << 3) +#define NH_FLD_L2TPV2_PRIORITY_BIT (NH_FLD_L2TPV2_TYPE_BIT << 4) +#define NH_FLD_L2TPV2_VERSION (NH_FLD_L2TPV2_TYPE_BIT << 5) +#define NH_FLD_L2TPV2_LEN (NH_FLD_L2TPV2_TYPE_BIT << 6) +#define NH_FLD_L2TPV2_TUNNEL_ID (NH_FLD_L2TPV2_TYPE_BIT << 7) +#define NH_FLD_L2TPV2_SESSION_ID (NH_FLD_L2TPV2_TYPE_BIT << 8) +#define NH_FLD_L2TPV2_NS (NH_FLD_L2TPV2_TYPE_BIT << 9) +#define NH_FLD_L2TPV2_NR (NH_FLD_L2TPV2_TYPE_BIT << 10) +#define NH_FLD_L2TPV2_OFFSET_SIZE (NH_FLD_L2TPV2_TYPE_BIT << 11) +#define NH_FLD_L2TPV2_FIRST_BYTE (NH_FLD_L2TPV2_TYPE_BIT << 12) +#define NH_FLD_L2TPV2_ALL_FIELDS \ + ((NH_FLD_L2TPV2_TYPE_BIT << 13) - 1) + +/*************************** L2TPV3 fields *********************************/ +#define NH_FLD_L2TPV3_CTRL_TYPE_BIT (1) +#define NH_FLD_L2TPV3_CTRL_LENGTH_BIT (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 1) +#define NH_FLD_L2TPV3_CTRL_SEQUENCE_BIT (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 2) +#define NH_FLD_L2TPV3_CTRL_VERSION (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 3) +#define NH_FLD_L2TPV3_CTRL_LENGTH (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 4) +#define NH_FLD_L2TPV3_CTRL_CONTROL (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 5) +#define NH_FLD_L2TPV3_CTRL_SENT (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 6) +#define NH_FLD_L2TPV3_CTRL_RECV (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 7) +#define NH_FLD_L2TPV3_CTRL_FIRST_BYTE (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 8) +#define NH_FLD_L2TPV3_CTRL_ALL_FIELDS \ + ((NH_FLD_L2TPV3_CTRL_TYPE_BIT << 9) - 1) + +#define NH_FLD_L2TPV3_SESS_TYPE_BIT (1) +#define NH_FLD_L2TPV3_SESS_VERSION (NH_FLD_L2TPV3_SESS_TYPE_BIT << 1) +#define NH_FLD_L2TPV3_SESS_ID (NH_FLD_L2TPV3_SESS_TYPE_BIT << 2) +#define NH_FLD_L2TPV3_SESS_COOKIE (NH_FLD_L2TPV3_SESS_TYPE_BIT << 3) +#define NH_FLD_L2TPV3_SESS_ALL_FIELDS \ + ((NH_FLD_L2TPV3_SESS_TYPE_BIT << 4) - 1) + +/**************************** PPP fields ***********************************/ +#define NH_FLD_PPP_PID (1) +#define NH_FLD_PPP_COMPRESSED (NH_FLD_PPP_PID << 1) +#define NH_FLD_PPP_ALL_FIELDS ((NH_FLD_PPP_PID << 2) - 1) + +/************************** PPPoE fields ***********************************/ +#define NH_FLD_PPPOE_VER (1) +#define NH_FLD_PPPOE_TYPE (NH_FLD_PPPOE_VER << 1) +#define NH_FLD_PPPOE_CODE (NH_FLD_PPPOE_VER << 2) +#define NH_FLD_PPPOE_SID (NH_FLD_PPPOE_VER << 3) +#define NH_FLD_PPPOE_LEN (NH_FLD_PPPOE_VER << 4) +#define NH_FLD_PPPOE_SESSION (NH_FLD_PPPOE_VER << 5) +#define NH_FLD_PPPOE_PID (NH_FLD_PPPOE_VER << 6) +#define NH_FLD_PPPOE_ALL_FIELDS ((NH_FLD_PPPOE_VER << 7) - 1) + +/************************* PPP-Mux fields **********************************/ +#define NH_FLD_PPPMUX_PID (1) +#define NH_FLD_PPPMUX_CKSUM (NH_FLD_PPPMUX_PID << 1) +#define NH_FLD_PPPMUX_COMPRESSED (NH_FLD_PPPMUX_PID << 2) +#define NH_FLD_PPPMUX_ALL_FIELDS ((NH_FLD_PPPMUX_PID << 3) - 1) + +/*********************** PPP-Mux sub-frame fields **************************/ +#define NH_FLD_PPPMUX_SUBFRM_PFF (1) +#define NH_FLD_PPPMUX_SUBFRM_LXT (NH_FLD_PPPMUX_SUBFRM_PFF << 1) +#define NH_FLD_PPPMUX_SUBFRM_LEN (NH_FLD_PPPMUX_SUBFRM_PFF << 2) +#define NH_FLD_PPPMUX_SUBFRM_PID (NH_FLD_PPPMUX_SUBFRM_PFF << 3) +#define NH_FLD_PPPMUX_SUBFRM_USE_PID (NH_FLD_PPPMUX_SUBFRM_PFF << 4) +#define NH_FLD_PPPMUX_SUBFRM_ALL_FIELDS \ + ((NH_FLD_PPPMUX_SUBFRM_PFF << 5) - 1) + +/*************************** LLC fields ************************************/ +#define NH_FLD_LLC_DSAP (1) +#define NH_FLD_LLC_SSAP (NH_FLD_LLC_DSAP << 1) +#define NH_FLD_LLC_CTRL (NH_FLD_LLC_DSAP << 2) +#define NH_FLD_LLC_ALL_FIELDS ((NH_FLD_LLC_DSAP << 3) - 1) + +/*************************** NLPID fields **********************************/ +#define NH_FLD_NLPID_NLPID (1) +#define NH_FLD_NLPID_ALL_FIELDS ((NH_FLD_NLPID_NLPID << 1) - 1) + +/*************************** SNAP fields ***********************************/ +#define NH_FLD_SNAP_OUI (1) +#define NH_FLD_SNAP_PID (NH_FLD_SNAP_OUI << 1) +#define NH_FLD_SNAP_ALL_FIELDS ((NH_FLD_SNAP_OUI << 2) - 1) + +/*************************** LLC SNAP fields *******************************/ +#define NH_FLD_LLC_SNAP_TYPE (1) +#define NH_FLD_LLC_SNAP_ALL_FIELDS ((NH_FLD_LLC_SNAP_TYPE << 1) - 1) + +#define NH_FLD_ARP_HTYPE (1) +#define NH_FLD_ARP_PTYPE (NH_FLD_ARP_HTYPE << 1) +#define NH_FLD_ARP_HLEN (NH_FLD_ARP_HTYPE << 2) +#define NH_FLD_ARP_PLEN (NH_FLD_ARP_HTYPE << 3) +#define NH_FLD_ARP_OPER (NH_FLD_ARP_HTYPE << 4) +#define NH_FLD_ARP_SHA (NH_FLD_ARP_HTYPE << 5) +#define NH_FLD_ARP_SPA (NH_FLD_ARP_HTYPE << 6) +#define NH_FLD_ARP_THA (NH_FLD_ARP_HTYPE << 7) +#define NH_FLD_ARP_TPA (NH_FLD_ARP_HTYPE << 8) +#define NH_FLD_ARP_ALL_FIELDS ((NH_FLD_ARP_HTYPE << 9) - 1) + +/*************************** RFC2684 fields ********************************/ +#define NH_FLD_RFC2684_LLC (1) +#define NH_FLD_RFC2684_NLPID (NH_FLD_RFC2684_LLC << 1) +#define NH_FLD_RFC2684_OUI (NH_FLD_RFC2684_LLC << 2) +#define NH_FLD_RFC2684_PID (NH_FLD_RFC2684_LLC << 3) +#define NH_FLD_RFC2684_VPN_OUI (NH_FLD_RFC2684_LLC << 4) +#define NH_FLD_RFC2684_VPN_IDX (NH_FLD_RFC2684_LLC << 5) +#define NH_FLD_RFC2684_ALL_FIELDS ((NH_FLD_RFC2684_LLC << 6) - 1) + +/*************************** User defined fields ***************************/ +#define NH_FLD_USER_DEFINED_SRCPORT (1) +#define NH_FLD_USER_DEFINED_PCDID (NH_FLD_USER_DEFINED_SRCPORT << 1) +#define NH_FLD_USER_DEFINED_ALL_FIELDS \ + ((NH_FLD_USER_DEFINED_SRCPORT << 2) - 1) + +/*************************** Payload fields ********************************/ +#define NH_FLD_PAYLOAD_BUFFER (1) +#define NH_FLD_PAYLOAD_SIZE (NH_FLD_PAYLOAD_BUFFER << 1) +#define NH_FLD_MAX_FRM_SIZE (NH_FLD_PAYLOAD_BUFFER << 2) +#define NH_FLD_MIN_FRM_SIZE (NH_FLD_PAYLOAD_BUFFER << 3) +#define NH_FLD_PAYLOAD_TYPE (NH_FLD_PAYLOAD_BUFFER << 4) +#define NH_FLD_FRAME_SIZE (NH_FLD_PAYLOAD_BUFFER << 5) +#define NH_FLD_PAYLOAD_ALL_FIELDS ((NH_FLD_PAYLOAD_BUFFER << 6) - 1) + +/*************************** GRE fields ************************************/ +#define NH_FLD_GRE_TYPE (1) +#define NH_FLD_GRE_ALL_FIELDS ((NH_FLD_GRE_TYPE << 1) - 1) + +/*************************** MINENCAP fields *******************************/ +#define NH_FLD_MINENCAP_SRC_IP (1) +#define NH_FLD_MINENCAP_DST_IP (NH_FLD_MINENCAP_SRC_IP << 1) +#define NH_FLD_MINENCAP_TYPE (NH_FLD_MINENCAP_SRC_IP << 2) +#define NH_FLD_MINENCAP_ALL_FIELDS \ + ((NH_FLD_MINENCAP_SRC_IP << 3) - 1) + +/*************************** IPSEC AH fields *******************************/ +#define NH_FLD_IPSEC_AH_SPI (1) +#define NH_FLD_IPSEC_AH_NH (NH_FLD_IPSEC_AH_SPI << 1) +#define NH_FLD_IPSEC_AH_ALL_FIELDS ((NH_FLD_IPSEC_AH_SPI << 2) - 1) + +/*************************** IPSEC ESP fields ******************************/ +#define NH_FLD_IPSEC_ESP_SPI (1) +#define NH_FLD_IPSEC_ESP_SEQUENCE_NUM (NH_FLD_IPSEC_ESP_SPI << 1) +#define NH_FLD_IPSEC_ESP_ALL_FIELDS ((NH_FLD_IPSEC_ESP_SPI << 2) - 1) + +#define NH_FLD_IPSEC_ESP_SPI_SIZE 4 + +/*************************** MPLS fields ***********************************/ +#define NH_FLD_MPLS_LABEL_STACK (1) +#define NH_FLD_MPLS_LABEL_STACK_ALL_FIELDS \ + ((NH_FLD_MPLS_LABEL_STACK << 1) - 1) + +/*************************** MACSEC fields *********************************/ +#define NH_FLD_MACSEC_SECTAG (1) +#define NH_FLD_MACSEC_ALL_FIELDS ((NH_FLD_MACSEC_SECTAG << 1) - 1) + +/*************************** GTP fields ************************************/ +#define NH_FLD_GTP_TEID (1) + + +/* Protocol options */ + +/* Ethernet options */ +#define NH_OPT_ETH_BROADCAST 1 +#define NH_OPT_ETH_MULTICAST 2 +#define NH_OPT_ETH_UNICAST 3 +#define NH_OPT_ETH_BPDU 4 + +#define NH_ETH_IS_MULTICAST_ADDR(addr) (addr[0] & 0x01) +/* also applicable for broadcast */ + +/* VLAN options */ +#define NH_OPT_VLAN_CFI 1 + +/* IPV4 options */ +#define NH_OPT_IPV4_UNICAST 1 +#define NH_OPT_IPV4_MULTICAST 2 +#define NH_OPT_IPV4_BROADCAST 3 +#define NH_OPT_IPV4_OPTION 4 +#define NH_OPT_IPV4_FRAG 5 +#define NH_OPT_IPV4_INITIAL_FRAG 6 + +/* IPV6 options */ +#define NH_OPT_IPV6_UNICAST 1 +#define NH_OPT_IPV6_MULTICAST 2 +#define NH_OPT_IPV6_OPTION 3 +#define NH_OPT_IPV6_FRAG 4 +#define NH_OPT_IPV6_INITIAL_FRAG 5 + +/* General IP options (may be used for any version) */ +#define NH_OPT_IP_FRAG 1 +#define NH_OPT_IP_INITIAL_FRAG 2 +#define NH_OPT_IP_OPTION 3 + +/* Minenc. options */ +#define NH_OPT_MINENCAP_SRC_ADDR_PRESENT 1 + +/* GRE. options */ +#define NH_OPT_GRE_ROUTING_PRESENT 1 + +/* TCP options */ +#define NH_OPT_TCP_OPTIONS 1 +#define NH_OPT_TCP_CONTROL_HIGH_BITS 2 +#define NH_OPT_TCP_CONTROL_LOW_BITS 3 + +/* CAPWAP options */ +#define NH_OPT_CAPWAP_DTLS 1 + +enum net_prot { + NET_PROT_NONE = 0, + NET_PROT_PAYLOAD, + NET_PROT_ETH, + NET_PROT_VLAN, + NET_PROT_IPV4, + NET_PROT_IPV6, + NET_PROT_IP, + NET_PROT_TCP, + NET_PROT_UDP, + NET_PROT_UDP_LITE, + NET_PROT_IPHC, + NET_PROT_SCTP, + NET_PROT_SCTP_CHUNK_DATA, + NET_PROT_PPPOE, + NET_PROT_PPP, + NET_PROT_PPPMUX, + NET_PROT_PPPMUX_SUBFRM, + NET_PROT_L2TPV2, + NET_PROT_L2TPV3_CTRL, + NET_PROT_L2TPV3_SESS, + NET_PROT_LLC, + NET_PROT_LLC_SNAP, + NET_PROT_NLPID, + NET_PROT_SNAP, + NET_PROT_MPLS, + NET_PROT_IPSEC_AH, + NET_PROT_IPSEC_ESP, + NET_PROT_UDP_ENC_ESP, /* RFC 3948 */ + NET_PROT_MACSEC, + NET_PROT_GRE, + NET_PROT_MINENCAP, + NET_PROT_DCCP, + NET_PROT_ICMP, + NET_PROT_IGMP, + NET_PROT_ARP, + NET_PROT_CAPWAP_DATA, + NET_PROT_CAPWAP_CTRL, + NET_PROT_RFC2684, + NET_PROT_ICMPV6, + NET_PROT_FCOE, + NET_PROT_FIP, + NET_PROT_ISCSI, + NET_PROT_GTP, + NET_PROT_USER_DEFINED_L2, + NET_PROT_USER_DEFINED_L3, + NET_PROT_USER_DEFINED_L4, + NET_PROT_USER_DEFINED_L5, + NET_PROT_USER_DEFINED_SHIM1, + NET_PROT_USER_DEFINED_SHIM2, + + NET_PROT_DUMMY_LAST +}; + +/*! IEEE8021.Q */ +#define NH_IEEE8021Q_ETYPE 0x8100 +#define NH_IEEE8021Q_HDR(etype, pcp, dei, vlan_id) \ + ((((uint32_t)(etype & 0xFFFF)) << 16) | \ + (((uint32_t)(pcp & 0x07)) << 13) | \ + (((uint32_t)(dei & 0x01)) << 12) | \ + (((uint32_t)(vlan_id & 0xFFF)))) + +#endif /* __FSL_NET_H */ --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2790,6 +2790,7 @@ static struct sk_buff *pktgen_alloc_skb( } else { skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT); } + skb_reserve(skb, LL_RESERVED_SPACE(dev)); /* the caller pre-fetches from skb->data and reserves for the mac hdr */ if (likely(skb))