These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / net / ethernet / apm / xgene / xgene_enet_main.c
index 40d3530..d0ae1a6 100644 (file)
@@ -28,6 +28,9 @@
 #define RES_RING_CSR   1
 #define RES_RING_CMD   2
 
+static const struct of_device_id xgene_enet_of_match[];
+static const struct acpi_device_id xgene_enet_acpi_match[];
+
 static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool)
 {
        struct xgene_enet_raw_desc16 *raw_desc;
@@ -48,6 +51,7 @@ static int xgene_enet_refill_bufpool(struct xgene_enet_desc_ring *buf_pool,
 {
        struct sk_buff *skb;
        struct xgene_enet_raw_desc16 *raw_desc;
+       struct xgene_enet_pdata *pdata;
        struct net_device *ndev;
        struct device *dev;
        dma_addr_t dma_addr;
@@ -58,6 +62,7 @@ static int xgene_enet_refill_bufpool(struct xgene_enet_desc_ring *buf_pool,
 
        ndev = buf_pool->ndev;
        dev = ndev_to_dev(buf_pool->ndev);
+       pdata = netdev_priv(ndev);
        bufdatalen = BUF_LEN_CODE_2K | (SKB_BUFFER_SIZE & GENMASK(11, 0));
        len = XGENE_ENET_MAX_MTU;
 
@@ -82,7 +87,7 @@ static int xgene_enet_refill_bufpool(struct xgene_enet_desc_ring *buf_pool,
                tail = (tail + 1) & slots;
        }
 
-       iowrite32(nbuf, buf_pool->cmd);
+       pdata->ring_ops->wr_cmd(buf_pool, nbuf);
        buf_pool->tail = tail;
 
        return 0;
@@ -102,26 +107,16 @@ static u8 xgene_enet_hdr_len(const void *data)
        return (eth->h_proto == htons(ETH_P_8021Q)) ? VLAN_ETH_HLEN : ETH_HLEN;
 }
 
-static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring)
-{
-       u32 __iomem *cmd_base = ring->cmd_base;
-       u32 ring_state, num_msgs;
-
-       ring_state = ioread32(&cmd_base[1]);
-       num_msgs = ring_state & CREATE_MASK(NUMMSGSINQ_POS, NUMMSGSINQ_LEN);
-
-       return num_msgs >> NUMMSGSINQ_POS;
-}
-
 static void xgene_enet_delete_bufpool(struct xgene_enet_desc_ring *buf_pool)
 {
+       struct xgene_enet_pdata *pdata = netdev_priv(buf_pool->ndev);
        struct xgene_enet_raw_desc16 *raw_desc;
        u32 slots = buf_pool->slots - 1;
        u32 tail = buf_pool->tail;
        u32 userinfo;
        int i, len;
 
-       len = xgene_enet_ring_len(buf_pool);
+       len = pdata->ring_ops->len(buf_pool);
        for (i = 0; i < len; i++) {
                tail = (tail - 1) & slots;
                raw_desc = &buf_pool->raw_desc16[tail];
@@ -131,7 +126,7 @@ static void xgene_enet_delete_bufpool(struct xgene_enet_desc_ring *buf_pool)
                dev_kfree_skb_any(buf_pool->rx_skb[userinfo]);
        }
 
-       iowrite32(-len, buf_pool->cmd);
+       pdata->ring_ops->wr_cmd(buf_pool, -len);
        buf_pool->tail = tail;
 }
 
@@ -152,18 +147,27 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
 {
        struct sk_buff *skb;
        struct device *dev;
+       skb_frag_t *frag;
+       dma_addr_t *frag_dma_addr;
        u16 skb_index;
        u8 status;
-       int ret = 0;
+       int i, ret = 0;
 
        skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0));
        skb = cp_ring->cp_skb[skb_index];
+       frag_dma_addr = &cp_ring->frag_dma_addr[skb_index * MAX_SKB_FRAGS];
 
        dev = ndev_to_dev(cp_ring->ndev);
        dma_unmap_single(dev, GET_VAL(DATAADDR, le64_to_cpu(raw_desc->m1)),
-                        GET_VAL(BUFDATALEN, le64_to_cpu(raw_desc->m1)),
+                        skb_headlen(skb),
                         DMA_TO_DEVICE);
 
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+               frag = &skb_shinfo(skb)->frags[i];
+               dma_unmap_page(dev, frag_dma_addr[i], skb_frag_size(frag),
+                              DMA_TO_DEVICE);
+       }
+
        /* Checking for error */
        status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
        if (unlikely(status > 2)) {
@@ -184,12 +188,16 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
 
 static u64 xgene_enet_work_msg(struct sk_buff *skb)
 {
+       struct net_device *ndev = skb->dev;
+       struct xgene_enet_pdata *pdata = netdev_priv(ndev);
        struct iphdr *iph;
-       u8 l3hlen, l4hlen = 0;
-       u8 csum_enable = 0;
-       u8 proto = 0;
-       u8 ethhdr;
-       u64 hopinfo;
+       u8 l3hlen = 0, l4hlen = 0;
+       u8 ethhdr, proto = 0, csum_enable = 0;
+       u64 hopinfo = 0;
+       u32 hdr_len, mss = 0;
+       u32 i, len, nr_frags;
+
+       ethhdr = xgene_enet_hdr_len(skb->data);
 
        if (unlikely(skb->protocol != htons(ETH_P_IP)) &&
            unlikely(skb->protocol != htons(ETH_P_8021Q)))
@@ -206,14 +214,40 @@ static u64 xgene_enet_work_msg(struct sk_buff *skb)
                l4hlen = tcp_hdrlen(skb) >> 2;
                csum_enable = 1;
                proto = TSO_IPPROTO_TCP;
+               if (ndev->features & NETIF_F_TSO) {
+                       hdr_len = ethhdr + ip_hdrlen(skb) + tcp_hdrlen(skb);
+                       mss = skb_shinfo(skb)->gso_size;
+
+                       if (skb_is_nonlinear(skb)) {
+                               len = skb_headlen(skb);
+                               nr_frags = skb_shinfo(skb)->nr_frags;
+
+                               for (i = 0; i < 2 && i < nr_frags; i++)
+                                       len += skb_shinfo(skb)->frags[i].size;
+
+                               /* HW requires header must reside in 3 buffer */
+                               if (unlikely(hdr_len > len)) {
+                                       if (skb_linearize(skb))
+                                               return 0;
+                               }
+                       }
+
+                       if (!mss || ((skb->len - hdr_len) <= mss))
+                               goto out;
+
+                       if (mss != pdata->mss) {
+                               pdata->mss = mss;
+                               pdata->mac_ops->set_mss(pdata);
+                       }
+                       hopinfo |= SET_BIT(ET);
+               }
        } else if (iph->protocol == IPPROTO_UDP) {
                l4hlen = UDP_HDR_SIZE;
                csum_enable = 1;
        }
 out:
        l3hlen = ip_hdrlen(skb) >> 2;
-       ethhdr = xgene_enet_hdr_len(skb->data);
-       hopinfo = SET_VAL(TCPHDR, l4hlen) |
+       hopinfo |= SET_VAL(TCPHDR, l4hlen) |
                  SET_VAL(IPHDR, l3hlen) |
                  SET_VAL(ETHHDR, ethhdr) |
                  SET_VAL(EC, csum_enable) |
@@ -224,35 +258,172 @@ out:
        return hopinfo;
 }
 
+static u16 xgene_enet_encode_len(u16 len)
+{
+       return (len == BUFLEN_16K) ? 0 : len;
+}
+
+static void xgene_set_addr_len(__le64 *desc, u32 idx, dma_addr_t addr, u32 len)
+{
+       desc[idx ^ 1] = cpu_to_le64(SET_VAL(DATAADDR, addr) |
+                                   SET_VAL(BUFDATALEN, len));
+}
+
+static __le64 *xgene_enet_get_exp_bufs(struct xgene_enet_desc_ring *ring)
+{
+       __le64 *exp_bufs;
+
+       exp_bufs = &ring->exp_bufs[ring->exp_buf_tail * MAX_EXP_BUFFS];
+       memset(exp_bufs, 0, sizeof(__le64) * MAX_EXP_BUFFS);
+       ring->exp_buf_tail = (ring->exp_buf_tail + 1) & ((ring->slots / 2) - 1);
+
+       return exp_bufs;
+}
+
+static dma_addr_t *xgene_get_frag_dma_array(struct xgene_enet_desc_ring *ring)
+{
+       return &ring->cp_ring->frag_dma_addr[ring->tail * MAX_SKB_FRAGS];
+}
+
 static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring,
                                    struct sk_buff *skb)
 {
        struct device *dev = ndev_to_dev(tx_ring->ndev);
+       struct xgene_enet_pdata *pdata = netdev_priv(tx_ring->ndev);
        struct xgene_enet_raw_desc *raw_desc;
-       dma_addr_t dma_addr;
+       __le64 *exp_desc = NULL, *exp_bufs = NULL;
+       dma_addr_t dma_addr, pbuf_addr, *frag_dma_addr;
+       skb_frag_t *frag;
        u16 tail = tx_ring->tail;
        u64 hopinfo;
+       u32 len, hw_len;
+       u8 ll = 0, nv = 0, idx = 0;
+       bool split = false;
+       u32 size, offset, ell_bytes = 0;
+       u32 i, fidx, nr_frags, count = 1;
 
        raw_desc = &tx_ring->raw_desc[tail];
+       tail = (tail + 1) & (tx_ring->slots - 1);
        memset(raw_desc, 0, sizeof(struct xgene_enet_raw_desc));
 
-       dma_addr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE);
+       hopinfo = xgene_enet_work_msg(skb);
+       if (!hopinfo)
+               return -EINVAL;
+       raw_desc->m3 = cpu_to_le64(SET_VAL(HENQNUM, tx_ring->dst_ring_num) |
+                                  hopinfo);
+
+       len = skb_headlen(skb);
+       hw_len = xgene_enet_encode_len(len);
+
+       dma_addr = dma_map_single(dev, skb->data, len, DMA_TO_DEVICE);
        if (dma_mapping_error(dev, dma_addr)) {
                netdev_err(tx_ring->ndev, "DMA mapping error\n");
                return -EINVAL;
        }
 
        /* Hardware expects descriptor in little endian format */
-       raw_desc->m0 = cpu_to_le64(tail);
        raw_desc->m1 = cpu_to_le64(SET_VAL(DATAADDR, dma_addr) |
-                                  SET_VAL(BUFDATALEN, skb->len) |
+                                  SET_VAL(BUFDATALEN, hw_len) |
                                   SET_BIT(COHERENT));
-       hopinfo = xgene_enet_work_msg(skb);
-       raw_desc->m3 = cpu_to_le64(SET_VAL(HENQNUM, tx_ring->dst_ring_num) |
-                                  hopinfo);
-       tx_ring->cp_ring->cp_skb[tail] = skb;
 
-       return 0;
+       if (!skb_is_nonlinear(skb))
+               goto out;
+
+       /* scatter gather */
+       nv = 1;
+       exp_desc = (void *)&tx_ring->raw_desc[tail];
+       tail = (tail + 1) & (tx_ring->slots - 1);
+       memset(exp_desc, 0, sizeof(struct xgene_enet_raw_desc));
+
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       for (i = nr_frags; i < 4 ; i++)
+               exp_desc[i ^ 1] = cpu_to_le64(LAST_BUFFER);
+
+       frag_dma_addr = xgene_get_frag_dma_array(tx_ring);
+
+       for (i = 0, fidx = 0; split || (fidx < nr_frags); i++) {
+               if (!split) {
+                       frag = &skb_shinfo(skb)->frags[fidx];
+                       size = skb_frag_size(frag);
+                       offset = 0;
+
+                       pbuf_addr = skb_frag_dma_map(dev, frag, 0, size,
+                                                    DMA_TO_DEVICE);
+                       if (dma_mapping_error(dev, pbuf_addr))
+                               return -EINVAL;
+
+                       frag_dma_addr[fidx] = pbuf_addr;
+                       fidx++;
+
+                       if (size > BUFLEN_16K)
+                               split = true;
+               }
+
+               if (size > BUFLEN_16K) {
+                       len = BUFLEN_16K;
+                       size -= BUFLEN_16K;
+               } else {
+                       len = size;
+                       split = false;
+               }
+
+               dma_addr = pbuf_addr + offset;
+               hw_len = xgene_enet_encode_len(len);
+
+               switch (i) {
+               case 0:
+               case 1:
+               case 2:
+                       xgene_set_addr_len(exp_desc, i, dma_addr, hw_len);
+                       break;
+               case 3:
+                       if (split || (fidx != nr_frags)) {
+                               exp_bufs = xgene_enet_get_exp_bufs(tx_ring);
+                               xgene_set_addr_len(exp_bufs, idx, dma_addr,
+                                                  hw_len);
+                               idx++;
+                               ell_bytes += len;
+                       } else {
+                               xgene_set_addr_len(exp_desc, i, dma_addr,
+                                                  hw_len);
+                       }
+                       break;
+               default:
+                       xgene_set_addr_len(exp_bufs, idx, dma_addr, hw_len);
+                       idx++;
+                       ell_bytes += len;
+                       break;
+               }
+
+               if (split)
+                       offset += BUFLEN_16K;
+       }
+       count++;
+
+       if (idx) {
+               ll = 1;
+               dma_addr = dma_map_single(dev, exp_bufs,
+                                         sizeof(u64) * MAX_EXP_BUFFS,
+                                         DMA_TO_DEVICE);
+               if (dma_mapping_error(dev, dma_addr)) {
+                       dev_kfree_skb_any(skb);
+                       return -EINVAL;
+               }
+               i = ell_bytes >> LL_BYTES_LSB_LEN;
+               exp_desc[2] = cpu_to_le64(SET_VAL(DATAADDR, dma_addr) |
+                                         SET_VAL(LL_BYTES_MSB, i) |
+                                         SET_VAL(LL_LEN, idx));
+               raw_desc->m2 = cpu_to_le64(SET_VAL(LL_BYTES_LSB, ell_bytes));
+       }
+
+out:
+       raw_desc->m0 = cpu_to_le64(SET_VAL(LL, ll) | SET_VAL(NV, nv) |
+                                  SET_VAL(USERINFO, tx_ring->tail));
+       tx_ring->cp_ring->cp_skb[tx_ring->tail] = skb;
+       pdata->tx_level += count;
+       tx_ring->tail = tail;
+
+       return count;
 }
 
 static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
@@ -260,29 +431,32 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
 {
        struct xgene_enet_pdata *pdata = netdev_priv(ndev);
        struct xgene_enet_desc_ring *tx_ring = pdata->tx_ring;
-       struct xgene_enet_desc_ring *cp_ring = tx_ring->cp_ring;
-       u32 tx_level, cq_level;
+       u32 tx_level = pdata->tx_level;
+       int count;
+
+       if (tx_level < pdata->txc_level)
+               tx_level += ((typeof(pdata->tx_level))~0U);
 
-       tx_level = xgene_enet_ring_len(tx_ring);
-       cq_level = xgene_enet_ring_len(cp_ring);
-       if (unlikely(tx_level > pdata->tx_qcnt_hi ||
-                    cq_level > pdata->cp_qcnt_hi)) {
+       if ((tx_level - pdata->txc_level) > pdata->tx_qcnt_hi) {
                netif_stop_queue(ndev);
                return NETDEV_TX_BUSY;
        }
 
-       if (xgene_enet_setup_tx_desc(tx_ring, skb)) {
+       if (skb_padto(skb, XGENE_MIN_ENET_FRAME_SIZE))
+               return NETDEV_TX_OK;
+
+       count = xgene_enet_setup_tx_desc(tx_ring, skb);
+       if (count <= 0) {
                dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
-       iowrite32(1, tx_ring->cmd);
        skb_tx_timestamp(skb);
-       tx_ring->tail = (tx_ring->tail + 1) & (tx_ring->slots - 1);
 
        pdata->stats.tx_packets++;
        pdata->stats.tx_bytes += skb->len;
 
+       pdata->ring_ops->wr_cmd(tx_ring, count);
        return NETDEV_TX_OK;
 }
 
@@ -331,7 +505,7 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
 
        /* strip off CRC as HW isn't doing this */
        datalen = GET_VAL(BUFDATALEN, le64_to_cpu(raw_desc->m1));
-       datalen -= 4;
+       datalen = (datalen & DATALEN_MASK) - 4;
        prefetch(skb->data - NET_IP_ALIGN);
        skb_put(skb, datalen);
 
@@ -363,42 +537,64 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
                                   int budget)
 {
        struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev);
-       struct xgene_enet_raw_desc *raw_desc;
+       struct xgene_enet_raw_desc *raw_desc, *exp_desc;
        u16 head = ring->head;
        u16 slots = ring->slots - 1;
-       int ret, count = 0;
+       int ret, desc_count, count = 0, processed = 0;
+       bool is_completion;
 
        do {
                raw_desc = &ring->raw_desc[head];
+               desc_count = 0;
+               is_completion = false;
+               exp_desc = NULL;
                if (unlikely(xgene_enet_is_desc_slot_empty(raw_desc)))
                        break;
 
                /* read fpqnum field after dataaddr field */
                dma_rmb();
-               if (is_rx_desc(raw_desc))
+               if (GET_BIT(NV, le64_to_cpu(raw_desc->m0))) {
+                       head = (head + 1) & slots;
+                       exp_desc = &ring->raw_desc[head];
+
+                       if (unlikely(xgene_enet_is_desc_slot_empty(exp_desc))) {
+                               head = (head - 1) & slots;
+                               break;
+                       }
+                       dma_rmb();
+                       count++;
+                       desc_count++;
+               }
+               if (is_rx_desc(raw_desc)) {
                        ret = xgene_enet_rx_frame(ring, raw_desc);
-               else
+               } else {
                        ret = xgene_enet_tx_completion(ring, raw_desc);
+                       is_completion = true;
+               }
                xgene_enet_mark_desc_slot_empty(raw_desc);
+               if (exp_desc)
+                       xgene_enet_mark_desc_slot_empty(exp_desc);
 
                head = (head + 1) & slots;
                count++;
+               desc_count++;
+               processed++;
+               if (is_completion)
+                       pdata->txc_level += desc_count;
 
                if (ret)
                        break;
        } while (--budget);
 
        if (likely(count)) {
-               iowrite32(-count, ring->cmd);
+               pdata->ring_ops->wr_cmd(ring, -count);
                ring->head = head;
 
-               if (netif_queue_stopped(ring->ndev)) {
-                       if (xgene_enet_ring_len(ring) < pdata->cp_qcnt_low)
-                               netif_wake_queue(ring->ndev);
-               }
+               if (netif_queue_stopped(ring->ndev))
+                       netif_start_queue(ring->ndev);
        }
 
-       return count;
+       return processed;
 }
 
 static int xgene_enet_napi(struct napi_struct *napi, const int budget)
@@ -500,10 +696,10 @@ static int xgene_enet_open(struct net_device *ndev)
        mac_ops->tx_enable(pdata);
        mac_ops->rx_enable(pdata);
 
+       xgene_enet_napi_enable(pdata);
        ret = xgene_enet_register_irq(ndev);
        if (ret)
                return ret;
-       xgene_enet_napi_enable(pdata);
 
        if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
                phy_start(pdata->phy_dev);
@@ -527,13 +723,13 @@ static int xgene_enet_close(struct net_device *ndev)
        else
                cancel_delayed_work_sync(&pdata->link_work);
 
-       xgene_enet_napi_disable(pdata);
-       xgene_enet_free_irq(ndev);
-       xgene_enet_process_ring(pdata->rx_ring, -1);
-
        mac_ops->tx_disable(pdata);
        mac_ops->rx_disable(pdata);
 
+       xgene_enet_free_irq(ndev);
+       xgene_enet_napi_disable(pdata);
+       xgene_enet_process_ring(pdata->rx_ring, -1);
+
        return 0;
 }
 
@@ -545,7 +741,7 @@ static void xgene_enet_delete_ring(struct xgene_enet_desc_ring *ring)
        pdata = netdev_priv(ring->ndev);
        dev = ndev_to_dev(ring->ndev);
 
-       xgene_enet_clear_ring(ring);
+       pdata->ring_ops->clear(ring);
        dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
 }
 
@@ -598,15 +794,17 @@ static int xgene_enet_get_ring_size(struct device *dev,
 
 static void xgene_enet_free_desc_ring(struct xgene_enet_desc_ring *ring)
 {
+       struct xgene_enet_pdata *pdata;
        struct device *dev;
 
        if (!ring)
                return;
 
        dev = ndev_to_dev(ring->ndev);
+       pdata = netdev_priv(ring->ndev);
 
        if (ring->desc_addr) {
-               xgene_enet_clear_ring(ring);
+               pdata->ring_ops->clear(ring);
                dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma);
        }
        devm_kfree(dev, ring);
@@ -637,6 +835,25 @@ static void xgene_enet_free_desc_rings(struct xgene_enet_pdata *pdata)
        }
 }
 
+static bool is_irq_mbox_required(struct xgene_enet_pdata *pdata,
+                                struct xgene_enet_desc_ring *ring)
+{
+       if ((pdata->enet_id == XGENE_ENET2) &&
+           (xgene_enet_ring_owner(ring->id) == RING_OWNER_CPU)) {
+               return true;
+       }
+
+       return false;
+}
+
+static void __iomem *xgene_enet_ring_cmd_base(struct xgene_enet_pdata *pdata,
+                                             struct xgene_enet_desc_ring *ring)
+{
+       u8 num_ring_id_shift = pdata->ring_ops->num_ring_id_shift;
+
+       return pdata->ring_cmd_addr + (ring->num << num_ring_id_shift);
+}
+
 static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring(
                        struct net_device *ndev, u32 ring_num,
                        enum xgene_enet_ring_cfgsize cfgsize, u32 ring_id)
@@ -668,9 +885,20 @@ static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring(
        }
        ring->size = size;
 
-       ring->cmd_base = pdata->ring_cmd_addr + (ring->num << 6);
+       if (is_irq_mbox_required(pdata, ring)) {
+               ring->irq_mbox_addr = dma_zalloc_coherent(dev, INTR_MBOX_SIZE,
+                               &ring->irq_mbox_dma, GFP_KERNEL);
+               if (!ring->irq_mbox_addr) {
+                       dma_free_coherent(dev, size, ring->desc_addr,
+                                         ring->dma);
+                       devm_kfree(dev, ring);
+                       return NULL;
+               }
+       }
+
+       ring->cmd_base = xgene_enet_ring_cmd_base(pdata, ring);
        ring->cmd = ring->cmd_base + INC_DEC_CMD_ADDR;
-       ring = xgene_enet_setup_ring(ring);
+       ring = pdata->ring_ops->setup(ring);
        netdev_dbg(ndev, "ring info: num=%d  size=%d  id=%d  slots=%d\n",
                   ring->num, ring->size, ring->id, ring->slots);
 
@@ -682,20 +910,44 @@ static u16 xgene_enet_get_ring_id(enum xgene_ring_owner owner, u8 bufnum)
        return (owner << 6) | (bufnum & GENMASK(5, 0));
 }
 
+static enum xgene_ring_owner xgene_derive_ring_owner(struct xgene_enet_pdata *p)
+{
+       enum xgene_ring_owner owner;
+
+       if (p->enet_id == XGENE_ENET1) {
+               switch (p->phy_mode) {
+               case PHY_INTERFACE_MODE_SGMII:
+                       owner = RING_OWNER_ETH0;
+                       break;
+               default:
+                       owner = (!p->port_id) ? RING_OWNER_ETH0 :
+                                               RING_OWNER_ETH1;
+                       break;
+               }
+       } else {
+               owner = (!p->port_id) ? RING_OWNER_ETH0 : RING_OWNER_ETH1;
+       }
+
+       return owner;
+}
+
 static int xgene_enet_create_desc_rings(struct net_device *ndev)
 {
        struct xgene_enet_pdata *pdata = netdev_priv(ndev);
        struct device *dev = ndev_to_dev(ndev);
        struct xgene_enet_desc_ring *rx_ring, *tx_ring, *cp_ring;
        struct xgene_enet_desc_ring *buf_pool = NULL;
+       enum xgene_ring_owner owner;
+       dma_addr_t dma_exp_bufs;
        u8 cpu_bufnum = pdata->cpu_bufnum;
        u8 eth_bufnum = pdata->eth_bufnum;
        u8 bp_bufnum = pdata->bp_bufnum;
        u16 ring_num = pdata->ring_num;
        u16 ring_id;
-       int ret;
+       int ret, size;
 
        /* allocate rx descriptor ring */
+       owner = xgene_derive_ring_owner(pdata);
        ring_id = xgene_enet_get_ring_id(RING_OWNER_CPU, cpu_bufnum++);
        rx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
                                              RING_CFGSIZE_16KB, ring_id);
@@ -705,7 +957,8 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
        }
 
        /* allocate buffer pool for receiving packets */
-       ring_id = xgene_enet_get_ring_id(RING_OWNER_ETH0, bp_bufnum++);
+       owner = xgene_derive_ring_owner(pdata);
+       ring_id = xgene_enet_get_ring_id(owner, bp_bufnum++);
        buf_pool = xgene_enet_create_desc_ring(ndev, ring_num++,
                                               RING_CFGSIZE_2KB, ring_id);
        if (!buf_pool) {
@@ -734,13 +987,23 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
        pdata->rx_ring = rx_ring;
 
        /* allocate tx descriptor ring */
-       ring_id = xgene_enet_get_ring_id(RING_OWNER_ETH0, eth_bufnum++);
+       owner = xgene_derive_ring_owner(pdata);
+       ring_id = xgene_enet_get_ring_id(owner, eth_bufnum++);
        tx_ring = xgene_enet_create_desc_ring(ndev, ring_num++,
                                              RING_CFGSIZE_16KB, ring_id);
        if (!tx_ring) {
                ret = -ENOMEM;
                goto err;
        }
+
+       size = (tx_ring->slots / 2) * sizeof(__le64) * MAX_EXP_BUFFS;
+       tx_ring->exp_bufs = dma_zalloc_coherent(dev, size, &dma_exp_bufs,
+                                               GFP_KERNEL);
+       if (!tx_ring->exp_bufs) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
        pdata->tx_ring = tx_ring;
 
        if (!pdata->cq_cnt) {
@@ -765,12 +1028,20 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
                ret = -ENOMEM;
                goto err;
        }
+
+       size = sizeof(dma_addr_t) * MAX_SKB_FRAGS;
+       cp_ring->frag_dma_addr = devm_kcalloc(dev, tx_ring->slots,
+                                             size, GFP_KERNEL);
+       if (!cp_ring->frag_dma_addr) {
+               devm_kfree(dev, cp_ring->cp_skb);
+               ret = -ENOMEM;
+               goto err;
+       }
+
        pdata->tx_ring->cp_ring = cp_ring;
        pdata->tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring);
 
-       pdata->tx_qcnt_hi = pdata->tx_ring->slots / 2;
-       pdata->cp_qcnt_hi = pdata->rx_ring->slots / 2;
-       pdata->cp_qcnt_low = pdata->cp_qcnt_hi / 2;
+       pdata->tx_qcnt_hi = pdata->tx_ring->slots - 128;
 
        return 0;
 
@@ -818,55 +1089,80 @@ static const struct net_device_ops xgene_ndev_ops = {
        .ndo_set_mac_address = xgene_enet_set_mac_address,
 };
 
-static int xgene_get_port_id(struct device *dev, struct xgene_enet_pdata *pdata)
+#ifdef CONFIG_ACPI
+static int xgene_get_port_id_acpi(struct device *dev,
+                                 struct xgene_enet_pdata *pdata)
 {
-       u32 id = 0;
-       int ret;
+       acpi_status status;
+       u64 temp;
 
-       ret = device_property_read_u32(dev, "port-id", &id);
-       if (!ret && id > 1) {
-               dev_err(dev, "Incorrect port-id specified\n");
-               return -ENODEV;
+       status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_SUN", NULL, &temp);
+       if (ACPI_FAILURE(status)) {
+               pdata->port_id = 0;
+       } else {
+               pdata->port_id = temp;
        }
 
-       pdata->port_id = id;
-
        return 0;
 }
+#endif
 
-static int xgene_get_mac_address(struct device *dev,
-                                unsigned char *addr)
+static int xgene_get_port_id_dt(struct device *dev, struct xgene_enet_pdata *pdata)
 {
+       u32 id = 0;
        int ret;
 
-       ret = device_property_read_u8_array(dev, "local-mac-address", addr, 6);
-       if (ret)
-               ret = device_property_read_u8_array(dev, "mac-address",
-                                                   addr, 6);
-       if (ret)
-               return -ENODEV;
+       ret = of_property_read_u32(dev->of_node, "port-id", &id);
+       if (ret) {
+               pdata->port_id = 0;
+               ret = 0;
+       } else {
+               pdata->port_id = id & BIT(0);
+       }
 
-       return ETH_ALEN;
+       return ret;
 }
 
-static int xgene_get_phy_mode(struct device *dev)
+static int xgene_get_tx_delay(struct xgene_enet_pdata *pdata)
 {
-       int i, ret;
-       char *modestr;
+       struct device *dev = &pdata->pdev->dev;
+       int delay, ret;
 
-       ret = device_property_read_string(dev, "phy-connection-type",
-                                         (const char **)&modestr);
-       if (ret)
-               ret = device_property_read_string(dev, "phy-mode",
-                                                 (const char **)&modestr);
-       if (ret)
-               return -ENODEV;
+       ret = of_property_read_u32(dev->of_node, "tx-delay", &delay);
+       if (ret) {
+               pdata->tx_delay = 4;
+               return 0;
+       }
 
-       for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) {
-               if (!strcasecmp(modestr, phy_modes(i)))
-                       return i;
+       if (delay < 0 || delay > 7) {
+               dev_err(dev, "Invalid tx-delay specified\n");
+               return -EINVAL;
        }
-       return -ENODEV;
+
+       pdata->tx_delay = delay;
+
+       return 0;
+}
+
+static int xgene_get_rx_delay(struct xgene_enet_pdata *pdata)
+{
+       struct device *dev = &pdata->pdev->dev;
+       int delay, ret;
+
+       ret = of_property_read_u32(dev->of_node, "rx-delay", &delay);
+       if (ret) {
+               pdata->rx_delay = 2;
+               return 0;
+       }
+
+       if (delay < 0 || delay > 7) {
+               dev_err(dev, "Invalid rx-delay specified\n");
+               return -EINVAL;
+       }
+
+       pdata->rx_delay = delay;
+
+       return 0;
 }
 
 static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
@@ -876,7 +1172,8 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
        struct device *dev;
        struct resource *res;
        void __iomem *base_addr;
-       int ret;
+       u32 offset;
+       int ret = 0;
 
        pdev = pdata->pdev;
        dev = &pdev->dev;
@@ -917,16 +1214,21 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
                return -ENOMEM;
        }
 
-       ret = xgene_get_port_id(dev, pdata);
+       if (dev->of_node)
+               ret = xgene_get_port_id_dt(dev, pdata);
+#ifdef CONFIG_ACPI
+       else
+               ret = xgene_get_port_id_acpi(dev, pdata);
+#endif
        if (ret)
                return ret;
 
-       if (xgene_get_mac_address(dev, ndev->dev_addr) != ETH_ALEN)
+       if (!device_get_mac_address(dev, ndev->dev_addr, ETH_ALEN))
                eth_hw_addr_random(ndev);
 
        memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
 
-       pdata->phy_mode = xgene_get_phy_mode(dev);
+       pdata->phy_mode = device_get_phy_mode(dev);
        if (pdata->phy_mode < 0) {
                dev_err(dev, "Unable to get phy-connection-type\n");
                return pdata->phy_mode;
@@ -938,6 +1240,14 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
                return -ENODEV;
        }
 
+       ret = xgene_get_tx_delay(pdata);
+       if (ret)
+               return ret;
+
+       ret = xgene_get_rx_delay(pdata);
+       if (ret)
+               return ret;
+
        ret = platform_get_irq(pdev, 0);
        if (ret <= 0) {
                dev_err(dev, "Unable to get ENET Rx IRQ\n");
@@ -949,27 +1259,35 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
        if (pdata->phy_mode != PHY_INTERFACE_MODE_RGMII) {
                ret = platform_get_irq(pdev, 1);
                if (ret <= 0) {
-                       dev_err(dev, "Unable to get ENET Tx completion IRQ\n");
-                       ret = ret ? : -ENXIO;
-                       return ret;
+                       pdata->cq_cnt = 0;
+                       dev_info(dev, "Unable to get Tx completion IRQ,"
+                                "using Rx IRQ instead\n");
+               } else {
+                       pdata->cq_cnt = XGENE_MAX_TXC_RINGS;
+                       pdata->txc_irq = ret;
                }
-               pdata->txc_irq = ret;
        }
 
        pdata->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(pdata->clk)) {
                /* Firmware may have set up the clock already. */
-               pdata->clk = NULL;
+               dev_info(dev, "clocks have been setup already\n");
        }
 
-       base_addr = pdata->base_addr - (pdata->port_id * MAC_OFFSET);
+       if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII)
+               base_addr = pdata->base_addr - (pdata->port_id * MAC_OFFSET);
+       else
+               base_addr = pdata->base_addr;
        pdata->eth_csr_addr = base_addr + BLOCK_ETH_CSR_OFFSET;
        pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET;
        pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET;
        if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII ||
            pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
                pdata->mcx_mac_addr = pdata->base_addr + BLOCK_ETH_MAC_OFFSET;
-               pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET;
+               offset = (pdata->enet_id == XGENE_ENET1) ?
+                         BLOCK_ETH_MAC_CSR_OFFSET :
+                         X2_BLOCK_ETH_MAC_CSR_OFFSET;
+               pdata->mcx_mac_csr_addr = base_addr + offset;
        } else {
                pdata->mcx_mac_addr = base_addr + BLOCK_AXG_MAC_OFFSET;
                pdata->mcx_mac_csr_addr = base_addr + BLOCK_AXG_MAC_CSR_OFFSET;
@@ -1024,33 +1342,59 @@ static void xgene_enet_setup_ops(struct xgene_enet_pdata *pdata)
                pdata->mac_ops = &xgene_sgmac_ops;
                pdata->port_ops = &xgene_sgport_ops;
                pdata->rm = RM1;
-               pdata->cq_cnt = XGENE_MAX_TXC_RINGS;
                break;
        default:
                pdata->mac_ops = &xgene_xgmac_ops;
                pdata->port_ops = &xgene_xgport_ops;
                pdata->rm = RM0;
-               pdata->cq_cnt = XGENE_MAX_TXC_RINGS;
                break;
        }
 
-       switch (pdata->port_id) {
-       case 0:
-               pdata->cpu_bufnum = START_CPU_BUFNUM_0;
-               pdata->eth_bufnum = START_ETH_BUFNUM_0;
-               pdata->bp_bufnum = START_BP_BUFNUM_0;
-               pdata->ring_num = START_RING_NUM_0;
-               break;
-       case 1:
-               pdata->cpu_bufnum = START_CPU_BUFNUM_1;
-               pdata->eth_bufnum = START_ETH_BUFNUM_1;
-               pdata->bp_bufnum = START_BP_BUFNUM_1;
-               pdata->ring_num = START_RING_NUM_1;
-               break;
-       default:
-               break;
+       if (pdata->enet_id == XGENE_ENET1) {
+               switch (pdata->port_id) {
+               case 0:
+                       pdata->cpu_bufnum = START_CPU_BUFNUM_0;
+                       pdata->eth_bufnum = START_ETH_BUFNUM_0;
+                       pdata->bp_bufnum = START_BP_BUFNUM_0;
+                       pdata->ring_num = START_RING_NUM_0;
+                       break;
+               case 1:
+                       if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
+                               pdata->cpu_bufnum = XG_START_CPU_BUFNUM_1;
+                               pdata->eth_bufnum = XG_START_ETH_BUFNUM_1;
+                               pdata->bp_bufnum = XG_START_BP_BUFNUM_1;
+                               pdata->ring_num = XG_START_RING_NUM_1;
+                       } else {
+                               pdata->cpu_bufnum = START_CPU_BUFNUM_1;
+                               pdata->eth_bufnum = START_ETH_BUFNUM_1;
+                               pdata->bp_bufnum = START_BP_BUFNUM_1;
+                               pdata->ring_num = START_RING_NUM_1;
+                       }
+                       break;
+               default:
+                       break;
+               }
+               pdata->ring_ops = &xgene_ring1_ops;
+       } else {
+               switch (pdata->port_id) {
+               case 0:
+                       pdata->cpu_bufnum = X2_START_CPU_BUFNUM_0;
+                       pdata->eth_bufnum = X2_START_ETH_BUFNUM_0;
+                       pdata->bp_bufnum = X2_START_BP_BUFNUM_0;
+                       pdata->ring_num = X2_START_RING_NUM_0;
+                       break;
+               case 1:
+                       pdata->cpu_bufnum = X2_START_CPU_BUFNUM_1;
+                       pdata->eth_bufnum = X2_START_ETH_BUFNUM_1;
+                       pdata->bp_bufnum = X2_START_BP_BUFNUM_1;
+                       pdata->ring_num = X2_START_RING_NUM_1;
+                       break;
+               default:
+                       break;
+               }
+               pdata->rm = RM0;
+               pdata->ring_ops = &xgene_ring2_ops;
        }
-
 }
 
 static void xgene_enet_napi_add(struct xgene_enet_pdata *pdata)
@@ -1086,6 +1430,7 @@ static int xgene_enet_probe(struct platform_device *pdev)
        struct xgene_enet_pdata *pdata;
        struct device *dev = &pdev->dev;
        struct xgene_mac_ops *mac_ops;
+       const struct of_device_id *of_id;
        int ret;
 
        ndev = alloc_etherdev(sizeof(struct xgene_enet_pdata));
@@ -1102,7 +1447,26 @@ static int xgene_enet_probe(struct platform_device *pdev)
        xgene_enet_set_ethtool_ops(ndev);
        ndev->features |= NETIF_F_IP_CSUM |
                          NETIF_F_GSO |
-                         NETIF_F_GRO;
+                         NETIF_F_GRO |
+                         NETIF_F_SG;
+
+       of_id = of_match_device(xgene_enet_of_match, &pdev->dev);
+       if (of_id) {
+               pdata->enet_id = (enum xgene_enet_id)of_id->data;
+       }
+#ifdef CONFIG_ACPI
+       else {
+               const struct acpi_device_id *acpi_id;
+
+               acpi_id = acpi_match_device(xgene_enet_acpi_match, &pdev->dev);
+               if (acpi_id)
+                       pdata->enet_id = (enum xgene_enet_id) acpi_id->driver_data;
+       }
+#endif
+       if (!pdata->enet_id) {
+               free_netdev(ndev);
+               return -ENODEV;
+       }
 
        ret = xgene_enet_get_resources(pdata);
        if (ret)
@@ -1110,11 +1474,11 @@ static int xgene_enet_probe(struct platform_device *pdev)
 
        xgene_enet_setup_ops(pdata);
 
-       ret = register_netdev(ndev);
-       if (ret) {
-               netdev_err(ndev, "Failed to register netdev\n");
-               goto err;
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
+               ndev->features |= NETIF_F_TSO;
+               pdata->mss = XGENE_ENET_MSS;
        }
+       ndev->hw_features = ndev->features;
 
        ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
        if (ret) {
@@ -1122,18 +1486,27 @@ static int xgene_enet_probe(struct platform_device *pdev)
                goto err;
        }
 
+       ret = register_netdev(ndev);
+       if (ret) {
+               netdev_err(ndev, "Failed to register netdev\n");
+               goto err;
+       }
+
        ret = xgene_enet_init_hw(pdata);
        if (ret)
                goto err;
 
-       xgene_enet_napi_add(pdata);
        mac_ops = pdata->mac_ops;
-       if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
                ret = xgene_enet_mdio_config(pdata);
-       else
+               if (ret)
+                       goto err;
+       } else {
                INIT_DELAYED_WORK(&pdata->link_work, mac_ops->link_state);
+       }
 
-       return ret;
+       xgene_enet_napi_add(pdata);
+       return 0;
 err:
        unregister_netdev(ndev);
        free_netdev(ndev);
@@ -1154,9 +1527,10 @@ static int xgene_enet_remove(struct platform_device *pdev)
        mac_ops->tx_disable(pdata);
 
        xgene_enet_napi_del(pdata);
-       xgene_enet_mdio_remove(pdata);
-       xgene_enet_delete_desc_rings(pdata);
+       if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+               xgene_enet_mdio_remove(pdata);
        unregister_netdev(ndev);
+       xgene_enet_delete_desc_rings(pdata);
        pdata->port_ops->shutdown(pdata);
        free_netdev(ndev);
 
@@ -1165,9 +1539,12 @@ static int xgene_enet_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id xgene_enet_acpi_match[] = {
-       { "APMC0D05", },
-       { "APMC0D30", },
-       { "APMC0D31", },
+       { "APMC0D05", XGENE_ENET1},
+       { "APMC0D30", XGENE_ENET1},
+       { "APMC0D31", XGENE_ENET1},
+       { "APMC0D3F", XGENE_ENET1},
+       { "APMC0D26", XGENE_ENET2},
+       { "APMC0D25", XGENE_ENET2},
        { }
 };
 MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
@@ -1175,9 +1552,11 @@ MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
 
 #ifdef CONFIG_OF
 static const struct of_device_id xgene_enet_of_match[] = {
-       {.compatible = "apm,xgene-enet",},
-       {.compatible = "apm,xgene1-sgenet",},
-       {.compatible = "apm,xgene1-xgenet",},
+       {.compatible = "apm,xgene-enet",    .data = (void *)XGENE_ENET1},
+       {.compatible = "apm,xgene1-sgenet", .data = (void *)XGENE_ENET1},
+       {.compatible = "apm,xgene1-xgenet", .data = (void *)XGENE_ENET1},
+       {.compatible = "apm,xgene2-sgenet", .data = (void *)XGENE_ENET2},
+       {.compatible = "apm,xgene2-xgenet", .data = (void *)XGENE_ENET2},
        {},
 };