2024-03-07 11:46:44

by Herve Codina

[permalink] [raw]
Subject: [PATCH v7 0/5] Add support for QMC HDLC

Hi,

This series introduces the QMC HDLC support.

Patches were previously sent as part of a full feature series and were
previously reviewed in that context:
"Add support for QMC HDLC, framer infrastructure and PEF2256 framer" [1]

In order to ease the merge, the full feature series has been split and
needed parts were merged in v6.8-rc1:
- "Prepare the PowerQUICC QMC and TSA for the HDLC QMC driver" [2]
- "Add support for framer infrastructure and PEF2256 framer" [3]

This series contains patches related to the QMC HDLC part (QMC HDLC
driver):
- Introduce the QMC HDLC driver (patches 1 and 2)
- Add timeslots change support in QMC HDLC (patch 3)
- Add framer support as a framer consumer in QMC HDLC (patch 4)

Compare to the original full feature series, a modification was done on
patch 3 in order to use a coherent prefix in the commit title.

I kept the patches unsquashed as they were previously sent and reviewed.
Of course, I can squash them if needed.

Compared to the previous iteration:
https://lore.kernel.org/linux-kernel/[email protected]/
this v7 series mainly:
- Rename a variable.
- Fix reverse xmas tree declarations.
- Add 'Acked-by' tag.

Best regards,
Hervé

[1]: https://lore.kernel.org/linux-kernel/[email protected]/
[2]: https://lore.kernel.org/linux-kernel/[email protected]/
[3]: https://lore.kernel.org/linux-kernel/[email protected]/

Changes v6 -> v7
- Patch 1
Fix reverse xmas tree declarations splitting declaration and
initialization.

- Patch 2
No changes

- Patch 3
Add 'Acked-by: Yury Norov <[email protected]>'

- Patch 4
Rename array32 variable to slot_array.

- Patch 5
No changes

Changes v5 -> v6
- Patch 1
Add missing header file inclusion.
Rework loop in qmc_hdlc_open() error handler.
Add 'Reviewed-by: Andy Shevchenko <[email protected]>'

- Patch 2
No changes.

- Patch 3
Avoid breaking API calls in kernel-doc to improve readability.
Remove Andy's credit. Keep only his signed-off-by.

- Patch 4 and 5
Add 'Reviewed-by: Andy Shevchenko <[email protected]>'.

Changes v4 -> v5
- Patch 1
Update QMC_HDLC_RX_ERROR_FLAGS to improve readability.
Display an error message after releasing resources instead of
before.
Use 'struct device *dev' in probe().
Use dev_err_probe() in probe().
Do not print a message on -ENOMEM.
Use guard() and scoped_guard().

- Patch 3
Use '(). See' constructing in kernel-doc instead of '() (See ...'
Add 'Co-developed-by: Herve Codina <[email protected]>'

- Patch 4
Use 'struct device *dev' in probe().
Use dev_err_probe() in probe().
Use '%64pb' instead of '%*pb' in printk formats.

- Patch 5
Use 'struct device *dev' in probe().
Use guard()

Changes v3 -> v4
- Patch 1
Remove of.h and of_platform.h includes, add mod_devicetable.h.
Add a blank line in the includes list.

- Path 2
No changes.

- v3 patches 3 and 4 removed

- Patch 3 (new patch in v4)
Introduce bitmap_{scatter,gather}() based on the original patch done
by Andy Shevchenko.
Address comments already done on the original patch:
https://lore.kernel.org/lkml/[email protected]/
- Removed the returned values.
- Used 'unsigned int' for all indexes.
- Added a 'visual' description of the operations in kernel-doc.
- Described the relationship between bitmap_scatter() and
bitmap_gather().
- Moved bitmap_{scatter,gather}() to the bitmap.h file.
- Improved bitmap_{scatter,gather}() test.
- Reworked the commit log.

- Patch 4 (v3 patch 5)
Use bitmap_{scatter,gather}()

- Patches 5 (v3 patch 6)
No changes.

Changes v2 -> v3
- Patch 1
Remove 'inline' function specifier from .c file.
Fix a bug introduced when added WARN_ONCE(). The warn condition must
be desc->skb (descriptor used) instead of !desc->skb.
Remove a lock/unlock section locking the entire qmc_hdlc_xmit()
function.

- Patch 5
Use bitmap_from_u64() everywhere instead of bitmap_from_arr32() and
bitmap_from_arr64().

Changes v1 -> v2
- Patch 1
Use the same qmc_hdlc initialisation in qmc_hcld_recv_complete()
than the one present in qmc_hcld_xmit_complete().
Use WARN_ONCE()

- Patch 3 (new patch in v2)
Make bitmap_onto() available to users

- Patch 4 (new patch in v2)
Introduce bitmap_off()

- Patch 5 (patch 3 in v1)
Use bitmap_*() functions

- Patch 6 (patch 4 in v1)
No changes

Changes compare to the full feature series:
- Patch 3
Use 'net: wan: fsl_qmc_hdlc:' as commit title prefix

Patches extracted:
- Patch 1 : full feature series patch 7
- Patch 2 : full feature series patch 8
- Patch 3 : full feature series patch 20
- Patch 4 : full feature series patch 27

Andy Shevchenko (1):
lib/bitmap: Introduce bitmap_scatter() and bitmap_gather() helpers

Herve Codina (4):
net: wan: Add support for QMC HDLC
MAINTAINERS: Add the Freescale QMC HDLC driver entry
net: wan: fsl_qmc_hdlc: Add runtime timeslots changes support
net: wan: fsl_qmc_hdlc: Add framer support

MAINTAINERS | 7 +
drivers/net/wan/Kconfig | 12 +
drivers/net/wan/Makefile | 1 +
drivers/net/wan/fsl_qmc_hdlc.c | 797 +++++++++++++++++++++++++++++++++
include/linux/bitmap.h | 101 +++++
lib/test_bitmap.c | 42 ++
6 files changed, 960 insertions(+)
create mode 100644 drivers/net/wan/fsl_qmc_hdlc.c

--
2.43.0



2024-03-07 11:47:43

by Herve Codina

[permalink] [raw]
Subject: [PATCH v7 3/5] lib/bitmap: Introduce bitmap_scatter() and bitmap_gather() helpers

From: Andy Shevchenko <[email protected]>

These helpers scatters or gathers a bitmap with the help of the mask
position bits parameter.

bitmap_scatter() does the following:
src: 0000000001011010
||||||
+------+|||||
| +----+||||
| |+----+|||
| || +-+||
| || | ||
mask: ...v..vv...v..vv
...0..11...0..10
dst: 0000001100000010

and bitmap_gather() performs this one:
mask: ...v..vv...v..vv
src: 0000001100000010
^ ^^ ^ 0
| || | 10
| || > 010
| |+--> 1010
| +--> 11010
+----> 011010
dst: 0000000000011010

bitmap_gather() can the seen as the reverse bitmap_scatter() operation.

Signed-off-by: Andy Shevchenko <[email protected]>
Link: https://lore.kernel.org/lkml/[email protected]/
Co-developed-by: Herve Codina <[email protected]>
Signed-off-by: Herve Codina <[email protected]>
Acked-by: Yury Norov <[email protected]>
---
include/linux/bitmap.h | 101 +++++++++++++++++++++++++++++++++++++++++
lib/test_bitmap.c | 42 +++++++++++++++++
2 files changed, 143 insertions(+)

diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index 99451431e4d6..049ba20911c5 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -62,6 +62,8 @@ struct device;
* bitmap_shift_left(dst, src, n, nbits) *dst = *src << n
* bitmap_cut(dst, src, first, n, nbits) Cut n bits from first, copy rest
* bitmap_replace(dst, old, new, mask, nbits) *dst = (*old & ~(*mask)) | (*new & *mask)
+ * bitmap_scatter(dst, src, mask, nbits) *dst = map(dense, sparse)(src)
+ * bitmap_gather(dst, src, mask, nbits) *dst = map(sparse, dense)(src)
* bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src)
* bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit)
* bitmap_onto(dst, orig, relmap, nbits) *dst = orig relative to relmap
@@ -487,6 +489,105 @@ static inline void bitmap_replace(unsigned long *dst,
__bitmap_replace(dst, old, new, mask, nbits);
}

+/**
+ * bitmap_scatter - Scatter a bitmap according to the given mask
+ * @dst: scattered bitmap
+ * @src: gathered bitmap
+ * @mask: mask representing bits to assign to in the scattered bitmap
+ * @nbits: number of bits in each of these bitmaps
+ *
+ * Scatters bitmap with sequential bits according to the given @mask.
+ *
+ * Example:
+ * If @src bitmap = 0x005a, with @mask = 0x1313, @dst will be 0x0302.
+ *
+ * Or in binary form
+ * @src @mask @dst
+ * 0000000001011010 0001001100010011 0000001100000010
+ *
+ * (Bits 0, 1, 2, 3, 4, 5 are copied to the bits 0, 1, 4, 8, 9, 12)
+ *
+ * A more 'visual' description of the operation:
+ * src: 0000000001011010
+ * ||||||
+ * +------+|||||
+ * | +----+||||
+ * | |+----+|||
+ * | || +-+||
+ * | || | ||
+ * mask: ...v..vv...v..vv
+ * ...0..11...0..10
+ * dst: 0000001100000010
+ *
+ * A relationship exists between bitmap_scatter() and bitmap_gather().
+ * bitmap_gather() can be seen as the 'reverse' bitmap_scatter() operation.
+ * See bitmap_scatter() for details related to this relationship.
+ */
+static inline void bitmap_scatter(unsigned long *dst, const unsigned long *src,
+ const unsigned long *mask, unsigned int nbits)
+{
+ unsigned int n = 0;
+ unsigned int bit;
+
+ bitmap_zero(dst, nbits);
+
+ for_each_set_bit(bit, mask, nbits)
+ __assign_bit(bit, dst, test_bit(n++, src));
+}
+
+/**
+ * bitmap_gather - Gather a bitmap according to given mask
+ * @dst: gathered bitmap
+ * @src: scattered bitmap
+ * @mask: mask representing bits to extract from in the scattered bitmap
+ * @nbits: number of bits in each of these bitmaps
+ *
+ * Gathers bitmap with sparse bits according to the given @mask.
+ *
+ * Example:
+ * If @src bitmap = 0x0302, with @mask = 0x1313, @dst will be 0x001a.
+ *
+ * Or in binary form
+ * @src @mask @dst
+ * 0000001100000010 0001001100010011 0000000000011010
+ *
+ * (Bits 0, 1, 4, 8, 9, 12 are copied to the bits 0, 1, 2, 3, 4, 5)
+ *
+ * A more 'visual' description of the operation:
+ * mask: ...v..vv...v..vv
+ * src: 0000001100000010
+ * ^ ^^ ^ 0
+ * | || | 10
+ * | || > 010
+ * | |+--> 1010
+ * | +--> 11010
+ * +----> 011010
+ * dst: 0000000000011010
+ *
+ * A relationship exists between bitmap_gather() and bitmap_scatter(). See
+ * bitmap_scatter() for the bitmap scatter detailed operations.
+ * Suppose scattered computed using bitmap_scatter(scattered, src, mask, n).
+ * The operation bitmap_gather(result, scattered, mask, n) leads to a result
+ * equal or equivalent to src.
+ *
+ * The result can be 'equivalent' because bitmap_scatter() and bitmap_gather()
+ * are not bijective.
+ * The result and src values are equivalent in that sense that a call to
+ * bitmap_scatter(res, src, mask, n) and a call to
+ * bitmap_scatter(res, result, mask, n) will lead to the same res value.
+ */
+static inline void bitmap_gather(unsigned long *dst, const unsigned long *src,
+ const unsigned long *mask, unsigned int nbits)
+{
+ unsigned int n = 0;
+ unsigned int bit;
+
+ bitmap_zero(dst, nbits);
+
+ for_each_set_bit(bit, mask, nbits)
+ __assign_bit(n++, dst, test_bit(bit, src));
+}
+
static inline void bitmap_next_set_region(unsigned long *bitmap,
unsigned int *rs, unsigned int *re,
unsigned int end)
diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c
index 65f22c2578b0..6b2b33579f56 100644
--- a/lib/test_bitmap.c
+++ b/lib/test_bitmap.c
@@ -380,6 +380,47 @@ static void __init test_replace(void)
expect_eq_bitmap(bmap, exp3_1_0, nbits);
}

+static const unsigned long sg_mask[] __initconst = {
+ BITMAP_FROM_U64(0x000000000000035aULL),
+};
+
+static const unsigned long sg_src[] __initconst = {
+ BITMAP_FROM_U64(0x0000000000000667ULL),
+};
+
+static const unsigned long sg_gather_exp[] __initconst = {
+ BITMAP_FROM_U64(0x0000000000000029ULL),
+};
+
+static const unsigned long sg_scatter_exp[] __initconst = {
+ BITMAP_FROM_U64(0x000000000000021aULL),
+};
+
+static void __init test_bitmap_sg(void)
+{
+ unsigned int nbits = 64;
+ DECLARE_BITMAP(bmap_gather, 100);
+ DECLARE_BITMAP(bmap_scatter, 100);
+ DECLARE_BITMAP(bmap_tmp, 100);
+ DECLARE_BITMAP(bmap_res, 100);
+
+ /* Simple gather call */
+ bitmap_zero(bmap_gather, 100);
+ bitmap_gather(bmap_gather, sg_src, sg_mask, nbits);
+ expect_eq_bitmap(sg_gather_exp, bmap_gather, nbits);
+
+ /* Simple scatter call */
+ bitmap_zero(bmap_scatter, 100);
+ bitmap_scatter(bmap_scatter, sg_src, sg_mask, nbits);
+ expect_eq_bitmap(sg_scatter_exp, bmap_scatter, nbits);
+
+ /* Scatter/gather relationship */
+ bitmap_zero(bmap_tmp, 100);
+ bitmap_gather(bmap_tmp, bmap_scatter, sg_mask, nbits);
+ bitmap_scatter(bmap_res, bmap_tmp, sg_mask, nbits);
+ expect_eq_bitmap(bmap_scatter, bmap_res, nbits);
+}
+
#define PARSE_TIME 0x1
#define NO_LEN 0x2

@@ -1252,6 +1293,7 @@ static void __init selftest(void)
test_copy();
test_bitmap_region();
test_replace();
+ test_bitmap_sg();
test_bitmap_arr32();
test_bitmap_arr64();
test_bitmap_parse();
--
2.43.0


2024-03-07 11:48:20

by Herve Codina

[permalink] [raw]
Subject: [PATCH v7 4/5] net: wan: fsl_qmc_hdlc: Add runtime timeslots changes support

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 <[email protected]>
Reviewed-by: Christophe Leroy <[email protected]>
Acked-by: Jakub Kicinski <[email protected]>
Reviewed-by: Andy Shevchenko <[email protected]>
---
drivers/net/wan/fsl_qmc_hdlc.c | 151 ++++++++++++++++++++++++++++++++-
1 file changed, 150 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wan/fsl_qmc_hdlc.c b/drivers/net/wan/fsl_qmc_hdlc.c
index 5fd7ed325f5b..57935b48a848 100644
--- a/drivers/net/wan/fsl_qmc_hdlc.c
+++ b/drivers/net/wan/fsl_qmc_hdlc.c
@@ -10,6 +10,7 @@
#include <linux/array_size.h>
#include <linux/bug.h>
#include <linux/cleanup.h>
+#include <linux/bitmap.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -39,6 +40,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 struct qmc_hdlc *netdev_to_qmc_hdlc(struct net_device *netdev)
@@ -209,6 +211,144 @@ 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)
+{
+ DECLARE_BITMAP(ts_mask_avail, 64);
+ DECLARE_BITMAP(ts_mask, 64);
+ DECLARE_BITMAP(map, 64);
+
+ /* Tx and Rx available 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;
+ }
+
+ bitmap_from_u64(ts_mask_avail, ts_info->rx_ts_mask_avail);
+ bitmap_from_u64(map, slot_map);
+ bitmap_scatter(ts_mask, map, ts_mask_avail, 64);
+
+ if (bitmap_weight(ts_mask, 64) != bitmap_weight(map, 64)) {
+ dev_err(qmc_hdlc->dev, "Cannot translate timeslots %64pb -> (%64pb, %64pb)\n",
+ map, ts_mask_avail, ts_mask);
+ return -EINVAL;
+ }
+
+ bitmap_to_arr64(&ts_info->tx_ts_mask, ts_mask, 64);
+ ts_info->rx_ts_mask = ts_info->tx_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)
+{
+ DECLARE_BITMAP(ts_mask_avail, 64);
+ DECLARE_BITMAP(ts_mask, 64);
+ DECLARE_BITMAP(map, 64);
+ u32 slot_array[2];
+
+ /* Tx and Rx masks and available 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;
+ }
+
+ bitmap_from_u64(ts_mask_avail, ts_info->rx_ts_mask_avail);
+ bitmap_from_u64(ts_mask, ts_info->rx_ts_mask);
+ bitmap_gather(map, ts_mask, ts_mask_avail, 64);
+
+ if (bitmap_weight(ts_mask, 64) != bitmap_weight(map, 64)) {
+ dev_err(qmc_hdlc->dev, "Cannot translate timeslots (%64pb, %64pb) -> %64pb\n",
+ ts_mask_avail, ts_mask, map);
+ return -EINVAL;
+ }
+
+ bitmap_to_arr32(slot_array, map, 64);
+ if (slot_array[1]) {
+ dev_err(qmc_hdlc->dev, "Slot map out of 32bit (%64pb, %64pb) -> %64pb\n",
+ ts_mask_avail, ts_mask, map);
+ return -EINVAL;
+ }
+
+ *slot_map = slot_array[0];
+ 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, &ts_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, &ts_info);
+ if (ret)
+ return ret;
+
+ ret = qmc_chan_set_ts_info(qmc_hdlc->qmc_chan, &ts_info);
+ if (ret) {
+ dev_err(qmc_hdlc->dev, "set QMC channel ts info failed %d\n", ret);
+ return ret;
+ }
+
+ qmc_hdlc->slot_map = te1->slot_map;
+
+ return 0;
+}
+
+static int qmc_hdlc_ioctl(struct net_device *netdev, struct if_settings *ifs)
+{
+ struct qmc_hdlc *qmc_hdlc = netdev_to_qmc_hdlc(netdev);
+ te1_settings te1;
+
+ switch (ifs->type) {
+ case IF_GET_IFACE:
+ ifs->type = IF_IFACE_E1;
+ if (ifs->size < sizeof(te1)) {
+ if (!ifs->size)
+ return 0; /* only type requested */
+
+ ifs->size = sizeof(te1); /* data size wanted */
+ return -ENOBUFS;
+ }
+
+ memset(&te1, 0, sizeof(te1));
+
+ /* Update slot_map */
+ te1.slot_map = qmc_hdlc->slot_map;
+
+ if (copy_to_user(ifs->ifs_ifsu.te1, &te1, sizeof(te1)))
+ return -EFAULT;
+ return 0;
+
+ case IF_IFACE_E1:
+ case IF_IFACE_T1:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (netdev->flags & IFF_UP)
+ return -EBUSY;
+
+ if (copy_from_user(&te1, ifs->ifs_ifsu.te1, sizeof(te1)))
+ return -EFAULT;
+
+ return qmc_hdlc_set_iface(qmc_hdlc, ifs->type, &te1);
+
+ default:
+ return hdlc_ioctl(netdev, ifs);
+ }
+}
+
static int qmc_hdlc_open(struct net_device *netdev)
{
struct qmc_hdlc *qmc_hdlc = netdev_to_qmc_hdlc(netdev);
@@ -332,12 +472,13 @@ static const struct net_device_ops qmc_hdlc_netdev_ops = {
.ndo_open = qmc_hdlc_open,
.ndo_stop = qmc_hdlc_close,
.ndo_start_xmit = hdlc_start_xmit,
- .ndo_siocwandev = hdlc_ioctl,
+ .ndo_siocwandev = qmc_hdlc_ioctl,
};

static int qmc_hdlc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct qmc_chan_ts_info ts_info;
struct qmc_hdlc *qmc_hdlc;
struct qmc_chan_info info;
hdlc_device *hdlc;
@@ -363,6 +504,14 @@ static int qmc_hdlc_probe(struct platform_device *pdev)
return dev_err_probe(dev, -EINVAL, "QMC chan mode %d is not QMC_HDLC\n",
info.mode);

+ ret = qmc_chan_get_ts_info(qmc_hdlc->qmc_chan, &ts_info);
+ if (ret)
+ return dev_err_probe(dev, ret, "get QMC channel ts info failed\n");
+
+ ret = qmc_hdlc_xlate_ts_info(qmc_hdlc, &ts_info, &qmc_hdlc->slot_map);
+ if (ret)
+ return ret;
+
qmc_hdlc->netdev = alloc_hdlcdev(qmc_hdlc);
if (!qmc_hdlc->netdev)
return -ENOMEM;
--
2.43.0


2024-03-11 21:12:05

by Jakub Kicinski

[permalink] [raw]
Subject: Re: [PATCH v7 0/5] Add support for QMC HDLC

On Thu, 7 Mar 2024 12:39:03 +0100 Herve Codina wrote:
> This series introduces the QMC HDLC support.
>
> Patches were previously sent as part of a full feature series and were
> previously reviewed in that context:
> "Add support for QMC HDLC, framer infrastructure and PEF2256 framer" [1]
>
> In order to ease the merge, the full feature series has been split and
> needed parts were merged in v6.8-rc1:
> - "Prepare the PowerQUICC QMC and TSA for the HDLC QMC driver" [2]
> - "Add support for framer infrastructure and PEF2256 framer" [3]
>
> This series contains patches related to the QMC HDLC part (QMC HDLC
> driver):
> - Introduce the QMC HDLC driver (patches 1 and 2)
> - Add timeslots change support in QMC HDLC (patch 3)
> - Add framer support as a framer consumer in QMC HDLC (patch 4)
>
> Compare to the original full feature series, a modification was done on
> patch 3 in order to use a coherent prefix in the commit title.
>
> I kept the patches unsquashed as they were previously sent and reviewed.
> Of course, I can squash them if needed.

Applied, thank you!