Re: [revert 0d60d8df6f49] [net/net-next] [6.8-rc5] Build Failure
On 29/02/2024 08:55, Eric Dumazet wrote: On Thu, Feb 29, 2024 at 9:04 AM Tasmiya Nalatwad wrote: Greetings, I have tried the patch provided below. Moving struct to file "net/core/rtnetlink.c" is not resolving the problem. Please find the below traces. --- Traces --- In file included from ./include/linux/rbtree.h:24, from ./include/linux/mm_types.h:11, from ./include/linux/mmzone.h:22, from ./include/linux/gfp.h:7, from ./include/linux/umh.h:4, from ./include/linux/kmod.h:9, from ./include/linux/module.h:17, from net/core/rtnetlink.c:17: net/core/rtnetlink.c: In function ‘netdev_dpll_pin’: ./include/linux/rcupdate.h:439:9: error: dereferencing pointer to incomplete type ‘struct dpll_pin’ typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \ ^ ./include/linux/rcupdate.h:587:2: note: in expansion of macro ‘__rcu_dereference_check’ __rcu_dereference_check((p), __UNIQUE_ID(rcu), \ ^~~ ./include/linux/rtnetlink.h:70:2: note: in expansion of macro ‘rcu_dereference_check’ rcu_dereference_check(p, lockdep_rtnl_is_held()) ^ net/core/rtnetlink.c:1059:15: note: in expansion of macro ‘rcu_dereference_rtnl’ return rcu_dereference_rtnl(dev->dpll_pin); ^~~~ CC crypto/algboss.o net/core/rtnetlink.c:1063:1: error: control reaches end of non-void function [-Werror=return-type] } ^ CC crypto/authenc.o CC crypto/authencesn.o CC crypto/af_alg.o CC crypto/algif_hash.o CC crypto/algif_skcipher.o CC crypto/algif_rng.o CC crypto/algif_aead.o AR arch/powerpc/kernel/built-in.a cc1: some warnings being treated as errors make[4]: *** [scripts/Makefile.build:243: net/core/rtnetlink.o] Error 1 make[4]: *** Waiting for unfinished jobs CC lib/kobject_uevent.o AR drivers/net/mdio/built-in.a AR net/802/built-in.a AR drivers/connector/built-in.a CC lib/vsprintf.o AR ipc/built-in.a AR net/nsh/built-in.a CC lib/dynamic_debug.o In file included from ./arch/powerpc/include/generated/asm/rwonce.h:1, from ./include/linux/compiler.h:251, from ./include/linux/instrumented.h:10, from ./include/linux/uaccess.h:6, from net/core/dev.c:71: net/core/dev.c: In function ‘netdev_dpll_pin_assign’: ./include/linux/rcupdate.h:462:36: error: dereferencing pointer to incomplete type ‘struct dpll_pin’ #define RCU_INITIALIZER(v) (typeof(*(v)) __force __rcu *)(v) ^~~~ ./include/asm-generic/rwonce.h:55:33: note: in definition of macro ‘__WRITE_ONCE’ *(volatile typeof(x) *)&(x) = (val);\ ^~~ ./arch/powerpc/include/asm/barrier.h:76:2: note: in expansion of macro ‘WRITE_ONCE’ WRITE_ONCE(*p, v); \ ^~ ./include/asm-generic/barrier.h:172:55: note: in expansion of macro ‘__smp_store_release’ #define smp_store_release(p, v) do { kcsan_release(); __smp_store_release(p, v); } while (0) ^~~ ./include/linux/rcupdate.h:503:3: note: in expansion of macro ‘smp_store_release’ smp_store_release(, RCU_INITIALIZER((typeof(p))_r_a_p__v)); \ ^ ./include/linux/rcupdate.h:503:25: note: in expansion of macro ‘RCU_INITIALIZER’ smp_store_release(, RCU_INITIALIZER((typeof(p))_r_a_p__v)); \ ^~~ net/core/dev.c:9081:2: note: in expansion of macro ‘rcu_assign_pointer’ rcu_assign_pointer(dev->dpll_pin, dpll_pin); ^~ On 2/28/24 20:13, Eric Dumazet wrote: On Wed, Feb 28, 2024 at 3:07 PM Vadim Fedorenko wrote: On 28/02/2024 11:09, Tasmiya Nalatwad wrote: Greetings, [revert 0d60d8df6f49] [net/net-next] [6.8-rc5] Build Failure Reverting below commit fixes the issue commit 0d60d8df6f493bb46bf5db40d39dd60a1bafdd4e dpll: rely on rcu for netdev_dpll_pin() --- Traces --- ./include/linux/dpll.h: In function ‘netdev_dpll_pin’: ./include/linux/rcupdate.h:439:9: error: dereferencing pointer to incomplete type ‘struct dpll_pin’ typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \ ^ ./include/linux/rcupdate.h:587:2: note: in expansion of macro ‘__rcu_dereference_check’ __rcu_dereference_check((p), __UNIQUE_ID(rcu), \ ^~~ ./include/linux/rtnetlink.h:70:2: note: in expansion of macro ‘rcu_dereference_check’ rcu_dereference_check(p, lockdep_rtnl_is_held()) ^ ./include/linux/dpll.h:175:9: note: in expansion of macro ‘rcu_dereference_rtnl’ return rcu_dereference_rtnl(dev->dpll_pin); ^~~~ make[4]: *** [scripts/Makefile.build:243: drivers/dpll/dpll_core.o] Error
Re: [revert 0d60d8df6f49] [net/net-next] [6.8-rc5] Build Failure
On 28/02/2024 11:09, Tasmiya Nalatwad wrote: Greetings, [revert 0d60d8df6f49] [net/net-next] [6.8-rc5] Build Failure Reverting below commit fixes the issue commit 0d60d8df6f493bb46bf5db40d39dd60a1bafdd4e dpll: rely on rcu for netdev_dpll_pin() --- Traces --- ./include/linux/dpll.h: In function ‘netdev_dpll_pin’: ./include/linux/rcupdate.h:439:9: error: dereferencing pointer to incomplete type ‘struct dpll_pin’ typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \ ^ ./include/linux/rcupdate.h:587:2: note: in expansion of macro ‘__rcu_dereference_check’ __rcu_dereference_check((p), __UNIQUE_ID(rcu), \ ^~~ ./include/linux/rtnetlink.h:70:2: note: in expansion of macro ‘rcu_dereference_check’ rcu_dereference_check(p, lockdep_rtnl_is_held()) ^ ./include/linux/dpll.h:175:9: note: in expansion of macro ‘rcu_dereference_rtnl’ return rcu_dereference_rtnl(dev->dpll_pin); ^~~~ make[4]: *** [scripts/Makefile.build:243: drivers/dpll/dpll_core.o] Error 1 make[4]: *** Waiting for unfinished jobs AR net/mpls/built-in.a AR net/l3mdev/built-in.a In file included from ./include/linux/rbtree.h:24, from ./include/linux/mm_types.h:11, from ./include/linux/mmzone.h:22, from ./include/linux/gfp.h:7, from ./include/linux/umh.h:4, from ./include/linux/kmod.h:9, from ./include/linux/module.h:17, from drivers/dpll/dpll_netlink.c:9: ./include/linux/dpll.h: In function ‘netdev_dpll_pin’: ./include/linux/rcupdate.h:439:9: error: dereferencing pointer to incomplete type ‘struct dpll_pin’ typeof(*p) *local = (typeof(*p) *__force)READ_ONCE(p); \ ^ ./include/linux/rcupdate.h:587:2: note: in expansion of macro ‘__rcu_dereference_check’ __rcu_dereference_check((p), __UNIQUE_ID(rcu), \ ^~~ ./include/linux/rtnetlink.h:70:2: note: in expansion of macro ‘rcu_dereference_check’ rcu_dereference_check(p, lockdep_rtnl_is_held()) ^ ./include/linux/dpll.h:175:9: note: in expansion of macro ‘rcu_dereference_rtnl’ return rcu_dereference_rtnl(dev->dpll_pin); ^~~~ make[4]: *** [scripts/Makefile.build:243: drivers/dpll/dpll_netlink.o] Error 1 make[3]: *** [scripts/Makefile.build:481: drivers/dpll] Error 2 make[3]: *** Waiting for unfinished jobs In file included from ./arch/powerpc/include/generated/asm/rwonce.h:1, from ./include/linux/compiler.h:251, from ./include/linux/instrumented.h:10, from ./include/linux/uaccess.h:6, from net/core/dev.c:71: net/core/dev.c: In function ‘netdev_dpll_pin_assign’: ./include/linux/rcupdate.h:462:36: error: dereferencing pointer to incomplete type ‘struct dpll_pin’ #define RCU_INITIALIZER(v) (typeof(*(v)) __force __rcu *)(v) ^~~~ ./include/asm-generic/rwonce.h:55:33: note: in definition of macro ‘__WRITE_ONCE’ *(volatile typeof(x) *)&(x) = (val); \ ^~~ ./arch/powerpc/include/asm/barrier.h:76:2: note: in expansion of macro ‘WRITE_ONCE’ WRITE_ONCE(*p, v); \ ^~ ./include/asm-generic/barrier.h:172:55: note: in expansion of macro ‘__smp_store_release’ #define smp_store_release(p, v) do { kcsan_release(); __smp_store_release(p, v); } while (0) ^~~ ./include/linux/rcupdate.h:503:3: note: in expansion of macro ‘smp_store_release’ smp_store_release(, RCU_INITIALIZER((typeof(p))_r_a_p__v)); \ ^ ./include/linux/rcupdate.h:503:25: note: in expansion of macro ‘RCU_INITIALIZER’ smp_store_release(, RCU_INITIALIZER((typeof(p))_r_a_p__v)); \ ^~~ net/core/dev.c:9081:2: note: in expansion of macro ‘rcu_assign_pointer’ rcu_assign_pointer(dev->dpll_pin, dpll_pin); ^~ make[4]: *** [scripts/Makefile.build:243: net/core/dev.o] Error 1 make[4]: *** Waiting for unfinished jobs AR drivers/net/ethernet/built-in.a AR drivers/net/built-in.a AR net/dcb/built-in.a AR net/netlabel/built-in.a AR net/strparser/built-in.a AR net/handshake/built-in.a GEN lib/test_fortify.log AR net/8021q/built-in.a AR net/nsh/built-in.a AR net/unix/built-in.a CC lib/string.o AR net/packet/built-in.a AR net/switchdev/built-in.a AR lib/lib.a AR net/mptcp/built-in.a AR net/devlink/built-in.a In file included from ./include/linux/rbtree.h:24, from ./include/linux/mm_types.h:11, from ./include/linux/mmzone.h:22, from ./include/linux/gfp.h:7, from ./include/linux/umh.h:4, from ./include/linux/kmod.h:9,
Re: [PATCH 3/4] net: wan: fsl_qmc_hdlc: Add runtime timeslots changes support
On 24/01/2024 15:26, Herve Codina wrote: Hi Vadim, On Wed, 24 Jan 2024 10:10:46 + Vadim Fedorenko wrote: [...] +static int qmc_hdlc_xlate_slot_map(struct qmc_hdlc *qmc_hdlc, + u32 slot_map, struct qmc_chan_ts_info *ts_info) +{ + u64 ts_mask_avail; + unsigned int bit; + unsigned int i; + u64 ts_mask; + u64 map; + + /* Tx and Rx masks must be identical */ + if (ts_info->rx_ts_mask_avail != ts_info->tx_ts_mask_avail) { + dev_err(qmc_hdlc->dev, "tx and rx available timeslots mismatch (0x%llx, 0x%llx)\n", + ts_info->rx_ts_mask_avail, ts_info->tx_ts_mask_avail); + return -EINVAL; + } + + ts_mask_avail = ts_info->rx_ts_mask_avail; + ts_mask = 0; + map = slot_map; + bit = 0; + for (i = 0; i < 64; i++) { + if (ts_mask_avail & BIT_ULL(i)) { + if (map & BIT_ULL(bit)) + ts_mask |= BIT_ULL(i); + bit++; + } + } + + if (hweight64(ts_mask) != hweight64(map)) { + dev_err(qmc_hdlc->dev, "Cannot translate timeslots 0x%llx -> (0x%llx,0x%llx)\n", + map, ts_mask_avail, ts_mask); + return -EINVAL; + } + + ts_info->tx_ts_mask = ts_mask; + ts_info->rx_ts_mask = ts_mask; + return 0; +} + +static int qmc_hdlc_xlate_ts_info(struct qmc_hdlc *qmc_hdlc, + const struct qmc_chan_ts_info *ts_info, u32 *slot_map) +{ + u64 ts_mask_avail; + unsigned int bit; + unsigned int i; + u64 ts_mask; + u64 map; + Starting from here ... + /* Tx and Rx masks must be identical */ + if (ts_info->rx_ts_mask_avail != ts_info->tx_ts_mask_avail) { + dev_err(qmc_hdlc->dev, "tx and rx available timeslots mismatch (0x%llx, 0x%llx)\n", + ts_info->rx_ts_mask_avail, ts_info->tx_ts_mask_avail); + return -EINVAL; + } + if (ts_info->rx_ts_mask != ts_info->tx_ts_mask) { + dev_err(qmc_hdlc->dev, "tx and rx timeslots mismatch (0x%llx, 0x%llx)\n", + ts_info->rx_ts_mask, ts_info->tx_ts_mask); + return -EINVAL; + } + + ts_mask_avail = ts_info->rx_ts_mask_avail; + ts_mask = ts_info->rx_ts_mask; + map = 0; + bit = 0; + for (i = 0; i < 64; i++) { + if (ts_mask_avail & BIT_ULL(i)) { + if (ts_mask & BIT_ULL(i)) + map |= BIT_ULL(bit); + bit++; + } + } + + if (hweight64(ts_mask) != hweight64(map)) { + dev_err(qmc_hdlc->dev, "Cannot translate timeslots (0x%llx,0x%llx) -> 0x%llx\n", + ts_mask_avail, ts_mask, map); + return -EINVAL; + } + till here the block looks like copy of the block from previous function. It worth to make a separate function for it, I think. + if (map >= BIT_ULL(32)) { + dev_err(qmc_hdlc->dev, "Slot map out of 32bit (0x%llx,0x%llx) -> 0x%llx\n", + ts_mask_avail, ts_mask, map); + return -EINVAL; + } + + *slot_map = map; + return 0; +} + [...] I am not so sure. There are slighty differences between the two functions. The error messages and, in particular, the loop in qmc_hdlc_xlate_slot_map() is: --- 8< --- ts_mask_avail = ts_info->rx_ts_mask_avail; ts_mask = 0; map = slot_map; bit = 0; for (i = 0; i < 64; i++) { if (ts_mask_avail & BIT_ULL(i)) { if (map & BIT_ULL(bit)) ts_mask |= BIT_ULL(i); bit++; } } --- 8< --- whereas it is the following in qmc_hdlc_xlate_ts_info(): --- 8< --- ts_mask_avail = ts_info->rx_ts_mask_avail; ts_mask = ts_info->rx_ts_mask; map = 0; bit = 0; for (i = 0; i < 64; i++) { if (ts_mask_avail & BIT_ULL(i)) { if (ts_mask & BIT_ULL(i)) map |= BIT_ULL(bit); bit++; } } --- 8< --- ts_map and map initializations are not the same, i and bit are not used for the same purpose and the computed value is not computed based on the same information. With that pointed, I am not sure that having some common code for both function will be relevant. Your opinion ? I see. I'm just thinking if it's possible to use helpers from bitops.h and bitmap.h here to avoid open-coding common parts of the code. Best regards, Hervé
Re: [PATCH 3/4] net: wan: fsl_qmc_hdlc: Add runtime timeslots changes support
On 23/01/2024 16:49, Herve Codina wrote: QMC channels support runtime timeslots changes but nothing is done at the QMC HDLC driver to handle these changes. Use existing IFACE ioctl in order to configure the timeslots to use. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Acked-by: Jakub Kicinski --- drivers/net/wan/fsl_qmc_hdlc.c | 169 - 1 file changed, 168 insertions(+), 1 deletion(-) diff --git a/drivers/net/wan/fsl_qmc_hdlc.c b/drivers/net/wan/fsl_qmc_hdlc.c index 31b637ec8390..82019cd96365 100644 --- a/drivers/net/wan/fsl_qmc_hdlc.c +++ b/drivers/net/wan/fsl_qmc_hdlc.c @@ -32,6 +32,7 @@ struct qmc_hdlc { struct qmc_hdlc_desc tx_descs[8]; unsigned int tx_out; struct qmc_hdlc_desc rx_descs[4]; + u32 slot_map; }; static inline struct qmc_hdlc *netdev_to_qmc_hdlc(struct net_device *netdev) @@ -202,6 +203,162 @@ static netdev_tx_t qmc_hdlc_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } +static int qmc_hdlc_xlate_slot_map(struct qmc_hdlc *qmc_hdlc, + u32 slot_map, struct qmc_chan_ts_info *ts_info) +{ + u64 ts_mask_avail; + unsigned int bit; + unsigned int i; + u64 ts_mask; + u64 map; + + /* Tx and Rx masks must be identical */ + if (ts_info->rx_ts_mask_avail != ts_info->tx_ts_mask_avail) { + dev_err(qmc_hdlc->dev, "tx and rx available timeslots mismatch (0x%llx, 0x%llx)\n", + ts_info->rx_ts_mask_avail, ts_info->tx_ts_mask_avail); + return -EINVAL; + } + + ts_mask_avail = ts_info->rx_ts_mask_avail; + ts_mask = 0; + map = slot_map; + bit = 0; + for (i = 0; i < 64; i++) { + if (ts_mask_avail & BIT_ULL(i)) { + if (map & BIT_ULL(bit)) + ts_mask |= BIT_ULL(i); + bit++; + } + } + + if (hweight64(ts_mask) != hweight64(map)) { + dev_err(qmc_hdlc->dev, "Cannot translate timeslots 0x%llx -> (0x%llx,0x%llx)\n", + map, ts_mask_avail, ts_mask); + return -EINVAL; + } + + ts_info->tx_ts_mask = ts_mask; + ts_info->rx_ts_mask = ts_mask; + return 0; +} + +static int qmc_hdlc_xlate_ts_info(struct qmc_hdlc *qmc_hdlc, + const struct qmc_chan_ts_info *ts_info, u32 *slot_map) +{ + u64 ts_mask_avail; + unsigned int bit; + unsigned int i; + u64 ts_mask; + u64 map; + Starting from here ... + /* Tx and Rx masks must be identical */ + if (ts_info->rx_ts_mask_avail != ts_info->tx_ts_mask_avail) { + dev_err(qmc_hdlc->dev, "tx and rx available timeslots mismatch (0x%llx, 0x%llx)\n", + ts_info->rx_ts_mask_avail, ts_info->tx_ts_mask_avail); + return -EINVAL; + } + if (ts_info->rx_ts_mask != ts_info->tx_ts_mask) { + dev_err(qmc_hdlc->dev, "tx and rx timeslots mismatch (0x%llx, 0x%llx)\n", + ts_info->rx_ts_mask, ts_info->tx_ts_mask); + return -EINVAL; + } + + ts_mask_avail = ts_info->rx_ts_mask_avail; + ts_mask = ts_info->rx_ts_mask; + map = 0; + bit = 0; + for (i = 0; i < 64; i++) { + if (ts_mask_avail & BIT_ULL(i)) { + if (ts_mask & BIT_ULL(i)) + map |= BIT_ULL(bit); + bit++; + } + } + + if (hweight64(ts_mask) != hweight64(map)) { + dev_err(qmc_hdlc->dev, "Cannot translate timeslots (0x%llx,0x%llx) -> 0x%llx\n", + ts_mask_avail, ts_mask, map); + return -EINVAL; + } + till here the block looks like copy of the block from previous function. It worth to make a separate function for it, I think. + if (map >= BIT_ULL(32)) { + dev_err(qmc_hdlc->dev, "Slot map out of 32bit (0x%llx,0x%llx) -> 0x%llx\n", + ts_mask_avail, ts_mask, map); + return -EINVAL; + } + + *slot_map = map; + return 0; +} + +static int qmc_hdlc_set_iface(struct qmc_hdlc *qmc_hdlc, int if_iface, const te1_settings *te1) +{ + struct qmc_chan_ts_info ts_info; + int ret; + + ret = qmc_chan_get_ts_info(qmc_hdlc->qmc_chan, _info); + if (ret) { + dev_err(qmc_hdlc->dev, "get QMC channel ts info failed %d\n", ret); + return ret; + } + ret = qmc_hdlc_xlate_slot_map(qmc_hdlc, te1->slot_map, _info); + if (ret) + return ret; + + ret = qmc_chan_set_ts_info(qmc_hdlc->qmc_chan, _info); + if (ret) { + dev_err(qmc_hdlc->dev, "set QMC channel ts info failed %d\n", ret); + return ret; + } + + qmc_hdlc->slot_map =
Re: [PATCH 1/4] net: wan: Add support for QMC HDLC
On 23/01/2024 16:49, Herve Codina wrote: The QMC HDLC driver provides support for HDLC using the QMC (QUICC Multichannel Controller) to transfer the HDLC data. Signed-off-by: Herve Codina Reviewed-by: Christophe Leroy Acked-by: Jakub Kicinski --- drivers/net/wan/Kconfig| 12 + drivers/net/wan/Makefile | 1 + drivers/net/wan/fsl_qmc_hdlc.c | 422 + 3 files changed, 435 insertions(+) create mode 100644 drivers/net/wan/fsl_qmc_hdlc.c diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 7dda87756d3f..31ab2136cdf1 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -197,6 +197,18 @@ config FARSYNC To compile this driver as a module, choose M here: the module will be called farsync. +config FSL_QMC_HDLC + tristate "Freescale QMC HDLC support" + depends on HDLC + depends on CPM_QMC + help + HDLC support using the Freescale QUICC Multichannel Controller (QMC). + + To compile this driver as a module, choose M here: the + module will be called fsl_qmc_hdlc. + + If unsure, say N. + config FSL_UCC_HDLC tristate "Freescale QUICC Engine HDLC support" depends on HDLC diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 8119b49d1da9..00e9b7ee1e01 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_WANXL) += wanxl.o obj-$(CONFIG_PCI200SYN) += pci200syn.o obj-$(CONFIG_PC300TOO)+= pc300too.o obj-$(CONFIG_IXP4XX_HSS) += ixp4xx_hss.o +obj-$(CONFIG_FSL_QMC_HDLC) += fsl_qmc_hdlc.o obj-$(CONFIG_FSL_UCC_HDLC)+= fsl_ucc_hdlc.o obj-$(CONFIG_SLIC_DS26522)+= slic_ds26522.o diff --git a/drivers/net/wan/fsl_qmc_hdlc.c b/drivers/net/wan/fsl_qmc_hdlc.c new file mode 100644 index ..31b637ec8390 --- /dev/null +++ b/drivers/net/wan/fsl_qmc_hdlc.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Freescale QMC HDLC Device Driver + * + * Copyright 2023 CS GROUP France + * + * Author: Herve Codina + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct qmc_hdlc_desc { + struct net_device *netdev; + struct sk_buff *skb; /* NULL if the descriptor is not in use */ + dma_addr_t dma_addr; + size_t dma_size; +}; + +struct qmc_hdlc { + struct device *dev; + struct qmc_chan *qmc_chan; + struct net_device *netdev; + bool is_crc32; + spinlock_t tx_lock; /* Protect tx descriptors */ + struct qmc_hdlc_desc tx_descs[8]; + unsigned int tx_out; + struct qmc_hdlc_desc rx_descs[4]; +}; + +static inline struct qmc_hdlc *netdev_to_qmc_hdlc(struct net_device *netdev) +{ + return dev_to_hdlc(netdev)->priv; +} + +static int qmc_hdlc_recv_queue(struct qmc_hdlc *qmc_hdlc, struct qmc_hdlc_desc *desc, size_t size); + +#define QMC_HDLC_RX_ERROR_FLAGS (QMC_RX_FLAG_HDLC_OVF | \ +QMC_RX_FLAG_HDLC_UNA | \ +QMC_RX_FLAG_HDLC_ABORT | \ +QMC_RX_FLAG_HDLC_CRC) + +static void qmc_hcld_recv_complete(void *context, size_t length, unsigned int flags) +{ + struct qmc_hdlc_desc *desc = context; + struct net_device *netdev = desc->netdev; + struct qmc_hdlc *qmc_hdlc = netdev_to_qmc_hdlc(desc->netdev); a line above desc->netdev was stored in netdev. better to reuse it and make declaration part consistent with qmc_hcld_xmit_complete + int ret; + + dma_unmap_single(qmc_hdlc->dev, desc->dma_addr, desc->dma_size, DMA_FROM_DEVICE); + + if (flags & QMC_HDLC_RX_ERROR_FLAGS) { + netdev->stats.rx_errors++; + if (flags & QMC_RX_FLAG_HDLC_OVF) /* Data overflow */ + netdev->stats.rx_over_errors++; + if (flags & QMC_RX_FLAG_HDLC_UNA) /* bits received not multiple of 8 */ + netdev->stats.rx_frame_errors++; + if (flags & QMC_RX_FLAG_HDLC_ABORT) /* Received an abort sequence */ + netdev->stats.rx_frame_errors++; + if (flags & QMC_RX_FLAG_HDLC_CRC) /* CRC error */ + netdev->stats.rx_crc_errors++; + kfree_skb(desc->skb); + } else { + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += length; + + skb_put(desc->skb, length); + desc->skb->protocol = hdlc_type_trans(desc->skb, netdev); + netif_rx(desc->skb); + } + + /* Re-queue a transfer using the same descriptor */ + ret = qmc_hdlc_recv_queue(qmc_hdlc, desc, desc->dma_size); + if (ret) { + dev_err(qmc_hdlc->dev, "queue recv desc failed (%d)\n", ret); + netdev->stats.rx_errors++; + } +} + +static int qmc_hdlc_recv_queue(struct