diff options
Diffstat (limited to 'target/linux/layerscape/patches-4.4/7201-staging-dpaa2-eth-initial-commit-of-dpaa2-eth-driver.patch')
-rw-r--r-- | target/linux/layerscape/patches-4.4/7201-staging-dpaa2-eth-initial-commit-of-dpaa2-eth-driver.patch | 12268 |
1 files changed, 12268 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-4.4/7201-staging-dpaa2-eth-initial-commit-of-dpaa2-eth-driver.patch b/target/linux/layerscape/patches-4.4/7201-staging-dpaa2-eth-initial-commit-of-dpaa2-eth-driver.patch new file mode 100644 index 0000000000..cbec144516 --- /dev/null +++ b/target/linux/layerscape/patches-4.4/7201-staging-dpaa2-eth-initial-commit-of-dpaa2-eth-driver.patch @@ -0,0 +1,12268 @@ +From e588172442093fe22374dc1bfc88a7da751d6b30 Mon Sep 17 00:00:00 2001 +From: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +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 <bogdan.hamciuc@freescale.com> +[Stuart: split into multiple patches] +Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com> +Integrated-by: Jilong Guo <jilong.guo@nxp.com> + +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 <bogdan.hamciuc@freescale.com> +[Stuart: cherry-picked patch from 4.0 and split it up] +Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com> + +Conflicts: + + drivers/staging/Makefile + +Signed-off-by: Stuart Yoder <stuart.yoder@nxp.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: I9ba0c19fc22f745e6be6cc40862afa18fa3ac3db +Reviewed-on: http://git.am.freescale.net:8181/35579 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: Ida2ec1fdbdebfd2e427f96ddad7582880146fda9 +Reviewed-on: http://git.am.freescale.net:8181/35580 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +dpaa2-eth: Fix ethtool bug + +We were writing beyond the end of the allocated data area for ethtool +statistics. + +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@freescale.com> +Change-Id: I6b77498a78dad06970508ebbed7144be73854f7f +Reviewed-on: http://git.am.freescale.net:8181/35583 +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: I314fbb8b4d9f589715e42d35fc6677d726b8f5ba +Reviewed-on: http://git.am.freescale.net:8181/35584 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: I8782ecb714c032cfeeecf4c8323cf9dbb702b10f +Reviewed-on: http://git.am.freescale.net:8181/35586 +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> +Tested-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Change-Id: Iba197209e9203ed306449729c6dcd23ec95f094d +Reviewed-on: http://git.am.freescale.net:8181/35756 +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +dpaa2-eth: Remove unused field in ldpaa_eth_priv structure + +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@freescale.com> +Change-Id: I124c3e4589b6420b1ea5cc05a03a51ea938b2bea +Reviewed-on: http://git.am.freescale.net:8181/35757 +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@freescale.com> +Change-Id: Ia6f11da433024e80ee59e821c9eabfa5068df5e5 +Reviewed-on: http://git.am.freescale.net:8181/35830 +Reviewed-by: Alexandru Marginean <Alexandru.Marginean@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> +Tested-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Change-Id: If2fe66fc5c0fbee2568d7afa15d43ea33f92e8e2 +Reviewed-on: http://git.am.freescale.net:8181/35967 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +dpaa2-eth: Update copyright years. + +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Change-Id: I7e00eecfc5569027c908124726edaf06be357c02 +Reviewed-on: http://git.am.freescale.net:8181/37666 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Ruxandra Ioana Radulescu <ruxandra.radulescu@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: I24a379b643c8b5161a33b966c3314cf91024ed4a +Reviewed-on: http://git.am.freescale.net:8181/37667 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Ruxandra Ioana Radulescu <ruxandra.radulescu@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Change-Id: Ifd404bbf399d5ba62e2896371076719c1d6b4214 +Reviewed-on: http://git.am.freescale.net:8181/36199 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Reviewed-by: Bharat Bhushan <Bharat.Bhushan@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> +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 <alexandru.marginean@freescale.com> + +Change-Id: I97c9dac1b842fe6bc7115e40c08c42f67dee8c9c +Reviewed-on: http://git.am.freescale.net:8181/37260 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Change-Id: I03e30e0121a40d0d15fcdc4bee1fb98caa17c0ef +Reviewed-on: http://git.am.freescale.net:8181/37668 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Change-Id: I08a0f3f18f82c5581c491bd395e3ad066b25bcf5 +Reviewed-on: http://git.am.freescale.net:8181/37669 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Change-Id: Ia1f5cf341c8414ae2058a73f6bc81490ef134592 +Reviewed-on: http://git.am.freescale.net:8181/37671 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Change-Id: I7d19d00b5d5445514ebd112c886ce8ccdbb1f0da +Reviewed-on: http://git.am.freescale.net:8181/37672 +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> +Tested-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: Ia2870cd019a4934c7835d38752a46b2a0045f30e +Reviewed-on: http://git.am.freescale.net:8181/37674 +Reviewed-by: Ruxandra Ioana Radulescu <ruxandra.radulescu@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> +Tested-by: Stuart Yoder <stuart.yoder@freescale.com> + +dpaa2-eth: Klocwork fixes + +Fix several issues reported by Klocwork. + +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Change-Id: I1e23365765f3b0ff9b6474d8207df7c1f2433ccd +Reviewed-on: http://git.am.freescale.net:8181/37675 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Change-Id: Iaf17e05b15946e6901c39a21b5344b89e9f1d797 +Reviewed-on: http://git.am.freescale.net:8181/37676 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <roy.pledge@freescale.com> +Tested-by: Ioana Radulescu <ruxandra.radulescu@freescale.com> +Tested-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> +[Stuart: split dpio and eth into separate patches, updated subject] +Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Change-Id: Ib55497bdbd769047420b3150668f2e2aef3c93f6 +Reviewed-on: http://git.am.freescale.net:8181/38317 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: If293aeabbd58d031f21456704357d4ff7e53c559 +Reviewed-on: http://git.am.freescale.net:8181/37681 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: Ib111ec61cd4294a7632348c25fa3d7f4002be0c0 +Reviewed-on: http://git.am.freescale.net:8181/37682 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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<X>/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 <bogdan.hamciuc@freescale.com> +Change-Id: I4b3da632e202ceeb22986c842d746aafe2a87a81 +Reviewed-on: http://git.am.freescale.net:8181/37684 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: Ibfe8aad7ad5c719cc95d7817d7de6d2094f0f7ed +Reviewed-on: http://git.am.freescale.net:8181/37685 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: I62ddd3ea1dbfd8b51e2bcb2286e0d5eb10ac7f27 +Reviewed-on: http://git.am.freescale.net:8181/37688 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Change-Id: Id52fab83873c40a711b8cadfcf909eb7e2e210f3 +Reviewed-on: http://git.am.freescale.net:8181/38318 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Tested-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Change-Id: I9de2580c7ff8e46cbca9613890b03737add35e26 +Reviewed-on: http://git.am.freescale.net:8181/37908 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +dpaa2-eth: Minor changes to FQ stats + +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@freescale.com> +Change-Id: I0ced0e7b2eee28599cdea79094336c0d44f0d32b +Reviewed-on: http://git.am.freescale.net:8181/38319 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: Ib08047ffa33518993b1ffa4671d0d4f36d6793d0 +Reviewed-on: http://git.am.freescale.net:8181/38320 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Roy Pledge <roy.pledge@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +dpaa2-eth: cosmetic changes in hashing code + +Signed-off-by: Alex Marginean <alexandru.marginean@freescale.com> +Change-Id: I79e21a69a6fb68cdbdb8d853c059661f8988dbf9 +Reviewed-on: http://git.am.freescale.net:8181/37258 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +dpaa2-eth: Prefetch data before initial access + +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@freescale.com> +Change-Id: Ie8f0163651aea7e3e197a408f89ca98d296d4b8b +Reviewed-on: http://git.am.freescale.net:8181/38753 +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +dpaa2-eth: Use netif_receive_skb + +netif_rx() is a leftover since our pre-NAPI codebase. + +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@freescale.com> +Change-Id: I02ff0a059862964df1bf81b247853193994c2dfe +Reviewed-on: http://git.am.freescale.net:8181/38754 +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +dpaa2-eth: Use napi_alloc_frag() on Rx. + +A bit better-suited than netdev_alloc_frag(). + +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@freescale.com> +Change-Id: I8863a783502db963e5dc968f049534c36ad484e2 +Reviewed-on: http://git.am.freescale.net:8181/38755 +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: I3c12eba29c79aa9c487307d367f6d9f4dbe447a3 +Reviewed-on: http://git.am.freescale.net:8181/38756 +Reviewed-by: Ruxandra Ioana Radulescu <ruxandra.radulescu@freescale.com> +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: If33033201fcee7671ad91c2b56badf3fb56a9e3e +Reviewed-on: http://git.am.freescale.net:8181/38757 +Reviewed-by: Ruxandra Ioana Radulescu <ruxandra.radulescu@freescale.com> +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Change-Id: I55f5bfe07a15b0d1bf0c6175d8829654163a4318 +Reviewed-on: http://git.am.freescale.net:8181/38758 +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> +Tested-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <alexandru.marginean@freescale.com> +Change-Id: I9fa3199f7818a9a5f9d69d3483ffd839056cc468 +Reviewed-on: http://git.am.freescale.net:8181/38759 +Reviewed-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Ruxandra Ioana Radulescu <ruxandra.radulescu@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +dpaa2-eth: Rename files into the dpaa2 nomenclature + +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +Change-Id: I1c3d62e2f19a59d4b65727234fd7df2dfd8683d9 +Reviewed-on: http://git.am.freescale.net:8181/38965 +Reviewed-by: Alexandru Marginean <Alexandru.Marginean@freescale.com> +Reviewed-by: Ruxandra Ioana Radulescu <ruxandra.radulescu@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> +Tested-by: Stuart Yoder <stuart.yoder@freescale.com> + +staging: dpaa2-eth: migrated remaining flibs for MC fw 8.0.0 + +Signed-off-by: J. German Rivera <German.Rivera@freescale.com> +[Stuart: split eth part into separate patch, updated subject] +Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Change-Id: I0a6e6626512b7bbddfef732c71f1400b67f3e619 +Reviewed-on: http://git.am.freescale.net:8181/39149 +Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> +Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <itai.katz@freescale.com> +Signed-off-by: J. German Rivera <German.Rivera@freescale.com> +[Stuart: split original patch into multiple patches] +Signed-off-by: Stuart Yoder <stuart.yoder@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +dpaa2-eth: Declare NETIF_F_LLTX as a capability + +We are effectively doing lock-less Tx. + +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +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<X>/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 <bogdan.hamciuc@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +dpaa2-eth: Fix compilation of Rx Error FQ code + +Conditionally-compiled code slipped between cracks when FLibs were +updated. + +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> +Signed-off-by: David S. Miller <davem@davemloft.net> + +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 <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <cristian.sovaiala@freescale.com> + +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 <ruxandra.radulescu@freescale.com> +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +dpaa2-eth: Stop carrier upon ifdown + +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +dpaa2-eth: Reduce ethtool messages verbosity + +Transform a couple of netdev_info() calls into netdev_dbg(). + +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> + +dpaa2-eth: Only unmask IRQs that we actually handle + +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +dpaa2-eth: Fix hashing distribution size + +Commit be3fb62623e4338e60fb60019f134b6055cbc127 +Author: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> +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 <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <bogdan.hamciuc@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +dpaa2-eth: rename ldpaa to dpaa2 + +Signed-off-by: Haiying Wang <Haiying.wang@freescale.com> +(Stuart: this patch was split out from the origin global rename patch) +Signed-off-by: Stuart Yoder <stuart.yoder@nxp.com> + +dpaa2-eth: Rename dpaa_io_query_fq_count to dpaa2_io_query_fq_count + +Signed-off-by: Cristian Sovaiala <cristian.sovaiala@freescale.com> + +fsl-dpio: rename dpaa_* structure to dpaa2_* + +Signed-off-by: Haiying Wang <Haiying.wang@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +staging: fsl-dpaa2: ethernet: add support for hardware timestamping + +Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> + +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 <bogdan.hamciuc@nxp.com> + +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 <bogdan.hamciuc@nxp.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +fsl-dpaa2: eth: Remove likely/unlikely from cold paths + +Signed-off-by: Cristian Sovaiala <cristi.sovaiala@nxp.com> +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com> + +fsl-dpaa2: eth: Remove __cold attribute + +Signed-off-by: Cristian Sovaiala <cristi.sovaiala@nxp.com> + +fsl-dpaa2: eth: Replace netdev_XXX with dev_XXX before register_netdevice() + +Signed-off-by: Cristian Sovaiala <cristi.sovaiala@nxp.com> +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com> + +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 <cristi.sovaiala@nxp.com> + +fsl-dpaa2: eth: Fix minor spelling issue + +Signed-off-by: Cristian Sovaiala <cristi.sovaiala@nxp.com> + +fsl-dpaa2: eth: Add a couple of 'unlikely' on hot path + +Signed-off-by: Cristian Sovaiala <cristi.sovaiala@nxp.com> +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com> + +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 <cristi.sovaiala@nxp.com> +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com> + +fsl-dpaa2: eth: Remove "inline" keyword from static functions + +Signed-off-by: Cristian Sovaiala <cristi.sovaiala@nxp.com> + +fsl-dpaa2: eth: Remove BUG/BUG_ONs + +Signed-off-by: Cristian Sovaiala <cristi.sovaiala@nxp.com> +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +fsl-dpaa2: eth: Replace uintX_t with uX + +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@freescale.com> +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <ruxandra.radulescu@freescale.com> + +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 <bogdan.hamciuc@nxp.com> + +fsl-dpaa2: eth: Remove dependency on GCOV_KERNEL + +Signed-off-by: Cristian Sovaiala <cristi.sovaiala@nxp.com> + +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 <ruxandra.radulescu@freescale.com> + +fsl-dpaa2: eth: Remove forward declarations + +Instead move the functions such that they are defined prior to +being used. + +Signed-off-by: Ioana Radulescu <ruxandra.radulescu@freescale.com> + +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 <bogdan.hamciuc@nxp.com> + +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 <bogdan.hamciuc@nxp.com> + +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 <ruxandra.radulescu@freescale.com> + +fsl-dpaa2: eth: Move header comment to .c file + +Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com> + +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 <bogdan.hamciuc@nxp.com> + +dpaa2 eth: irq update + +Signed-off-by: Stuart Yoder <stuart.yoder@nxp.com> + +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 <ruxandra.radulescu@freescale.com> ++M: Bogdan Hamciuc <bogdan.hamciuc@freescale.com> ++M: Cristian Sovaiala <cristian.sovaiala@freescale.com> ++L: linux-kernel@vger.kernel.org ++S: Maintained ++F: drivers/staging/fsl-dpaa2/ethernet/ ++ ++FREESCALE QORIQ MANAGEMENT COMPLEX RESTOOL DRIVER ++M: Lijun Pan <Lijun.Pan@freescale.com> ++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 <hch@infradead.org> + 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 <linux/module.h> ++#include <linux/debugfs.h> ++#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 <linux/dcache.h> ++#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 <linux/skbuff.h> ++#include <linux/netdevice.h> ++#include "dpaa2-eth.h" ++#include <linux/tracepoint.h> ++ ++#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 <trace/define_trace.h> +--- /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 <linux/init.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/etherdevice.h> ++#include <linux/of_net.h> ++#include <linux/interrupt.h> ++#include <linux/msi.h> ++#include <linux/debugfs.h> ++#include <linux/kthread.h> ++#include <linux/net_tstamp.h> ++ ++#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 <trace/events/sched.h> ++ */ ++#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 <linux/netdevice.h> ++#include <linux/if_vlan.h> ++#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 <linux/types.h> ++#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_<x>() */ ++#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_<X>' 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__<X> ++ * @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_<X>' 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_<X>' 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_<X>' 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_<X>' 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_<X>' 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_<X>' 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_<X>' 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_<X>' 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_<X>' 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_<X>' 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)) |