Re: [revert 0d60d8df6f49] [net/net-next] [6.8-rc5] Build Failure

2024-02-29 Thread Vadim Fedorenko

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

2024-02-28 Thread Vadim Fedorenko

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

2024-01-24 Thread Vadim Fedorenko

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

2024-01-24 Thread Vadim Fedorenko

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

2024-01-24 Thread Vadim Fedorenko

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