#define QTNF_MAX_MAC           3
 
+#define HBM_FRAME_META_MAGIC_PATTERN_S 0xAB
+#define HBM_FRAME_META_MAGIC_PATTERN_E 0xBA
+
+struct qtnf_frame_meta_info {
+       u8 magic_s;
+       u8 ifidx;
+       u8 macid;
+       u8 magic_e;
+} __packed;
+
 enum qtnf_fw_state {
        QTNF_FW_STATE_DETACHED,
        QTNF_FW_STATE_BOOT_DONE,
        int (*control_tx)(struct qtnf_bus *, struct sk_buff *);
 
        /* data xfer methods */
-       int (*data_tx)(struct qtnf_bus *, struct sk_buff *);
+       int (*data_tx)(struct qtnf_bus *bus, struct sk_buff *skb,
+                      unsigned int macid, unsigned int vifid);
        void (*data_tx_timeout)(struct qtnf_bus *, struct net_device *);
+       void (*data_tx_use_meta_set)(struct qtnf_bus *bus, bool use_meta);
        void (*data_rx_start)(struct qtnf_bus *);
        void (*data_rx_stop)(struct qtnf_bus *);
 };
        enum qtnf_fw_state fw_state;
        u32 chip;
        u32 chiprev;
-       const struct qtnf_bus_ops *bus_ops;
+       struct qtnf_bus_ops *bus_ops;
        struct qtnf_wmac *mac[QTNF_MAX_MAC];
        struct qtnf_qlink_transport trans;
        struct qtnf_hw_info hw_info;
        bus->bus_ops->stop(bus);
 }
 
-static inline int qtnf_bus_data_tx(struct qtnf_bus *bus, struct sk_buff *skb)
+static inline int qtnf_bus_data_tx(struct qtnf_bus *bus, struct sk_buff *skb,
+                                  unsigned int macid, unsigned int vifid)
 {
-       return bus->bus_ops->data_tx(bus, skb);
+       return bus->bus_ops->data_tx(bus, skb, macid, vifid);
 }
 
 static inline void
 
 
 static struct dentry *qtnf_debugfs_dir;
 
-struct qtnf_frame_meta_info {
-       u8 magic_s;
-       u8 ifidx;
-       u8 macid;
-       u8 magic_e;
-} __packed;
-
 struct qtnf_wmac *qtnf_core_get_mac(const struct qtnf_bus *bus, u8 macid)
 {
        struct qtnf_wmac *mac = NULL;
                return NETDEV_TX_OK;
        }
 
-       return qtnf_bus_data_tx(mac->bus, skb);
+       return qtnf_bus_data_tx(mac->bus, skb, mac->macid, vif->vifid);
 }
 
 /* Netdev handler for getting stats.
        dev->tx_queue_len = 100;
        dev->ethtool_ops = &qtnf_ethtool_ops;
 
+       if (mac->bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE)
+               dev->needed_tailroom = sizeof(struct qtnf_frame_meta_info);
+
        qdev_vif = netdev_priv(dev);
        *((void **)qdev_vif) = vif;
 
                goto error;
        }
 
+       if ((bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE) &&
+           bus->bus_ops->data_tx_use_meta_set)
+               bus->bus_ops->data_tx_use_meta_set(bus, true);
+
        if (bus->hw_info.num_mac > QTNF_MAX_MAC) {
                pr_err("no support for number of MACs=%u\n",
                       bus->hw_info.num_mac);
 
 static inline int qtnf_is_frame_meta_magic_valid(struct qtnf_frame_meta_info *m)
 {
-       return m->magic_s == 0xAB && m->magic_e == 0xBA;
+       return m->magic_s == HBM_FRAME_META_MAGIC_PATTERN_S &&
+               m->magic_e == HBM_FRAME_META_MAGIC_PATTERN_E;
 }
 
 struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb)
 
        return 1;
 }
 
-static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb)
+static int qtnf_pcie_skb_send(struct qtnf_bus *bus, struct sk_buff *skb)
 {
        struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus);
        struct qtnf_pcie_bus_priv *priv = &ps->base;
        return NETDEV_TX_OK;
 }
 
+static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb,
+                            unsigned int macid, unsigned int vifid)
+{
+       return qtnf_pcie_skb_send(bus, skb);
+}
+
+static int qtnf_pcie_data_tx_meta(struct qtnf_bus *bus, struct sk_buff *skb,
+                                 unsigned int macid, unsigned int vifid)
+{
+       struct qtnf_frame_meta_info *meta;
+       int tail_need = sizeof(*meta) - skb_tailroom(skb);
+       int ret;
+
+       if (tail_need > 0 && pskb_expand_head(skb, 0, tail_need, GFP_ATOMIC)) {
+               skb->dev->stats.tx_dropped++;
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
+       }
+
+       meta = skb_put(skb, sizeof(*meta));
+       meta->magic_s = HBM_FRAME_META_MAGIC_PATTERN_S;
+       meta->magic_e = HBM_FRAME_META_MAGIC_PATTERN_E;
+       meta->macid = macid;
+       meta->ifidx = vifid;
+
+       ret = qtnf_pcie_skb_send(bus, skb);
+       if (unlikely(ret == NETDEV_TX_BUSY))
+               __skb_trim(skb, skb->len - sizeof(*meta));
+
+       return ret;
+}
+
 static irqreturn_t qtnf_pcie_pearl_interrupt(int irq, void *data)
 {
        struct qtnf_bus *bus = (struct qtnf_bus *)data;
        qtnf_disable_hdp_irqs(ps);
 }
 
-static const struct qtnf_bus_ops qtnf_pcie_pearl_bus_ops = {
+static void qtnf_pearl_tx_use_meta_info_set(struct qtnf_bus *bus, bool use_meta)
+{
+       if (use_meta)
+               bus->bus_ops->data_tx = qtnf_pcie_data_tx_meta;
+       else
+               bus->bus_ops->data_tx = qtnf_pcie_data_tx;
+}
+
+static struct qtnf_bus_ops qtnf_pcie_pearl_bus_ops = {
        /* control path methods */
        .control_tx     = qtnf_pcie_control_tx,
 
        /* data path methods */
        .data_tx                = qtnf_pcie_data_tx,
        .data_tx_timeout        = qtnf_pcie_data_tx_timeout,
+       .data_tx_use_meta_set   = qtnf_pearl_tx_use_meta_info_set,
        .data_rx_start          = qtnf_pcie_data_rx_start,
        .data_rx_stop           = qtnf_pcie_data_rx_stop,
 };
        memcpy(pdata, pblk, len);
        hdr->crc = cpu_to_le32(~crc32(0, pdata, len));
 
-       ret = qtnf_pcie_data_tx(bus, skb);
+       ret = qtnf_pcie_skb_send(bus, skb);
 
        return (ret == NETDEV_TX_OK) ? len : 0;
 }
 
        return 1;
 }
 
-static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb)
+static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb,
+                            unsigned int macid, unsigned int vifid)
 {
        struct qtnf_pcie_topaz_state *ts = (void *)get_bus_priv(bus);
        struct qtnf_pcie_bus_priv *priv = &ts->base;
        napi_disable(&bus->mux_napi);
 }
 
-static const struct qtnf_bus_ops qtnf_pcie_topaz_bus_ops = {
+static struct qtnf_bus_ops qtnf_pcie_topaz_bus_ops = {
        /* control path methods */
        .control_tx     = qtnf_pcie_control_tx,