summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/freescale
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r--drivers/net/ethernet/freescale/Makefile3
-rw-r--r--drivers/net/ethernet/freescale/fec.h82
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c531
-rw-r--r--drivers/net/ethernet/freescale/fman/fman.c108
-rw-r--r--drivers/net/ethernet/freescale/fman/fman_dtsec.c7
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mac-fcc.c2
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c110
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ptp.c33
8 files changed, 463 insertions, 413 deletions
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index 4097c58d17a7..cbe21dc7e37e 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -4,6 +4,9 @@
obj-$(CONFIG_FEC) += fec.o
fec-objs :=fec_main.o fec_ptp.o
+CFLAGS_fec_main.o := -D__CHECK_ENDIAN__
+CFLAGS_fec_ptp.o := -D__CHECK_ENDIAN__
+
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 99d33e2d35e6..195122e11f10 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -19,8 +19,7 @@
#include <linux/timecounter.h>
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
- defined(CONFIG_M520x) || defined(CONFIG_M532x) || \
- defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
+ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM)
/*
* Just figures, Motorola would have to change the offsets for
* registers in the same peripheral device on different models
@@ -65,6 +64,7 @@
#define FEC_R_FIFO_RSEM 0x194 /* Receive FIFO section empty threshold */
#define FEC_R_FIFO_RAEM 0x198 /* Receive FIFO almost empty threshold */
#define FEC_R_FIFO_RAFL 0x19c /* Receive FIFO almost full threshold */
+#define FEC_FTRL 0x1b0 /* Frame truncation receive length*/
#define FEC_RACC 0x1c4 /* Receive Accelerator function */
#define FEC_RCMR_1 0x1c8 /* Receive classification match ring 1 */
#define FEC_RCMR_2 0x1cc /* Receive classification match ring 2 */
@@ -190,28 +190,45 @@
/*
* Define the buffer descriptor structure.
+ *
+ * Evidently, ARM SoCs have the FEC block generated in a
+ * little endian mode so adjust endianness accordingly.
*/
-#if defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
+#if defined(CONFIG_ARM)
+#define fec32_to_cpu le32_to_cpu
+#define fec16_to_cpu le16_to_cpu
+#define cpu_to_fec32 cpu_to_le32
+#define cpu_to_fec16 cpu_to_le16
+#define __fec32 __le32
+#define __fec16 __le16
+
struct bufdesc {
- unsigned short cbd_datlen; /* Data length */
- unsigned short cbd_sc; /* Control and status info */
- unsigned long cbd_bufaddr; /* Buffer address */
+ __fec16 cbd_datlen; /* Data length */
+ __fec16 cbd_sc; /* Control and status info */
+ __fec32 cbd_bufaddr; /* Buffer address */
};
#else
+#define fec32_to_cpu be32_to_cpu
+#define fec16_to_cpu be16_to_cpu
+#define cpu_to_fec32 cpu_to_be32
+#define cpu_to_fec16 cpu_to_be16
+#define __fec32 __be32
+#define __fec16 __be16
+
struct bufdesc {
- unsigned short cbd_sc; /* Control and status info */
- unsigned short cbd_datlen; /* Data length */
- unsigned long cbd_bufaddr; /* Buffer address */
+ __fec16 cbd_sc; /* Control and status info */
+ __fec16 cbd_datlen; /* Data length */
+ __fec32 cbd_bufaddr; /* Buffer address */
};
#endif
struct bufdesc_ex {
struct bufdesc desc;
- unsigned long cbd_esc;
- unsigned long cbd_prot;
- unsigned long cbd_bdu;
- unsigned long ts;
- unsigned short res0[4];
+ __fec32 cbd_esc;
+ __fec32 cbd_prot;
+ __fec32 cbd_bdu;
+ __fec32 ts;
+ __fec16 res0[4];
};
/*
@@ -293,12 +310,6 @@ struct bufdesc_ex {
#define FEC_R_BUFF_SIZE(X) (((X) == 1) ? FEC_R_BUFF_SIZE_1 : \
(((X) == 2) ? \
FEC_R_BUFF_SIZE_2 : FEC_R_BUFF_SIZE_0))
-#define FEC_R_DES_ACTIVE(X) (((X) == 1) ? FEC_R_DES_ACTIVE_1 : \
- (((X) == 2) ? \
- FEC_R_DES_ACTIVE_2 : FEC_R_DES_ACTIVE_0))
-#define FEC_X_DES_ACTIVE(X) (((X) == 1) ? FEC_X_DES_ACTIVE_1 : \
- (((X) == 2) ? \
- FEC_X_DES_ACTIVE_2 : FEC_X_DES_ACTIVE_0))
#define FEC_DMA_CFG(X) (((X) == 2) ? FEC_DMA_CFG_2 : FEC_DMA_CFG_1)
@@ -364,6 +375,7 @@ struct bufdesc_ex {
#define FEC_ENET_TS_TIMER ((uint)0x00008000)
#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | FEC_ENET_TS_TIMER)
+#define FEC_NAPI_IMASK (FEC_ENET_MII | FEC_ENET_TS_TIMER)
#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
/* ENET interrupt coalescing macro define */
@@ -431,33 +443,35 @@ struct bufdesc_ex {
/* Controller supports RACC register */
#define FEC_QUIRK_HAS_RACC (1 << 12)
+struct bufdesc_prop {
+ int qid;
+ /* Address of Rx and Tx buffers */
+ struct bufdesc *base;
+ struct bufdesc *last;
+ struct bufdesc *cur;
+ void __iomem *reg_desc_active;
+ dma_addr_t dma;
+ unsigned short ring_size;
+ unsigned char dsize;
+ unsigned char dsize_log2;
+};
+
struct fec_enet_priv_tx_q {
- int index;
+ struct bufdesc_prop bd;
unsigned char *tx_bounce[TX_RING_SIZE];
struct sk_buff *tx_skbuff[TX_RING_SIZE];
- dma_addr_t bd_dma;
- struct bufdesc *tx_bd_base;
- uint tx_ring_size;
-
unsigned short tx_stop_threshold;
unsigned short tx_wake_threshold;
- struct bufdesc *cur_tx;
struct bufdesc *dirty_tx;
char *tso_hdrs;
dma_addr_t tso_hdrs_dma;
};
struct fec_enet_priv_rx_q {
- int index;
+ struct bufdesc_prop bd;
struct sk_buff *rx_skbuff[RX_RING_SIZE];
-
- dma_addr_t bd_dma;
- struct bufdesc *rx_bd_base;
- uint rx_ring_size;
-
- struct bufdesc *cur_rx;
};
/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and
@@ -497,8 +511,6 @@ struct fec_enet_private {
unsigned long work_ts;
unsigned long work_mdio;
- unsigned short bufdesc_size;
-
struct platform_device *pdev;
int dev_id;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 502da6f48f95..37c081583084 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -217,86 +217,38 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
#define IS_TSO_HEADER(txq, addr) \
((addr >= txq->tso_hdrs_dma) && \
- (addr < txq->tso_hdrs_dma + txq->tx_ring_size * TSO_HEADER_SIZE))
+ (addr < txq->tso_hdrs_dma + txq->bd.ring_size * TSO_HEADER_SIZE))
static int mii_cnt;
-static inline
-struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp,
- struct fec_enet_private *fep,
- int queue_id)
-{
- struct bufdesc *new_bd = bdp + 1;
- struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp + 1;
- struct fec_enet_priv_tx_q *txq = fep->tx_queue[queue_id];
- struct fec_enet_priv_rx_q *rxq = fep->rx_queue[queue_id];
- struct bufdesc_ex *ex_base;
- struct bufdesc *base;
- int ring_size;
-
- if (bdp >= txq->tx_bd_base) {
- base = txq->tx_bd_base;
- ring_size = txq->tx_ring_size;
- ex_base = (struct bufdesc_ex *)txq->tx_bd_base;
- } else {
- base = rxq->rx_bd_base;
- ring_size = rxq->rx_ring_size;
- ex_base = (struct bufdesc_ex *)rxq->rx_bd_base;
- }
-
- if (fep->bufdesc_ex)
- return (struct bufdesc *)((ex_new_bd >= (ex_base + ring_size)) ?
- ex_base : ex_new_bd);
- else
- return (new_bd >= (base + ring_size)) ?
- base : new_bd;
-}
-
-static inline
-struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp,
- struct fec_enet_private *fep,
- int queue_id)
-{
- struct bufdesc *new_bd = bdp - 1;
- struct bufdesc_ex *ex_new_bd = (struct bufdesc_ex *)bdp - 1;
- struct fec_enet_priv_tx_q *txq = fep->tx_queue[queue_id];
- struct fec_enet_priv_rx_q *rxq = fep->rx_queue[queue_id];
- struct bufdesc_ex *ex_base;
- struct bufdesc *base;
- int ring_size;
-
- if (bdp >= txq->tx_bd_base) {
- base = txq->tx_bd_base;
- ring_size = txq->tx_ring_size;
- ex_base = (struct bufdesc_ex *)txq->tx_bd_base;
- } else {
- base = rxq->rx_bd_base;
- ring_size = rxq->rx_ring_size;
- ex_base = (struct bufdesc_ex *)rxq->rx_bd_base;
- }
+static struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp,
+ struct bufdesc_prop *bd)
+{
+ return (bdp >= bd->last) ? bd->base
+ : (struct bufdesc *)(((unsigned)bdp) + bd->dsize);
+}
- if (fep->bufdesc_ex)
- return (struct bufdesc *)((ex_new_bd < ex_base) ?
- (ex_new_bd + ring_size) : ex_new_bd);
- else
- return (new_bd < base) ? (new_bd + ring_size) : new_bd;
+static struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp,
+ struct bufdesc_prop *bd)
+{
+ return (bdp <= bd->base) ? bd->last
+ : (struct bufdesc *)(((unsigned)bdp) - bd->dsize);
}
-static int fec_enet_get_bd_index(struct bufdesc *base, struct bufdesc *bdp,
- struct fec_enet_private *fep)
+static int fec_enet_get_bd_index(struct bufdesc *bdp,
+ struct bufdesc_prop *bd)
{
- return ((const char *)bdp - (const char *)base) / fep->bufdesc_size;
+ return ((const char *)bdp - (const char *)bd->base) >> bd->dsize_log2;
}
-static int fec_enet_get_free_txdesc_num(struct fec_enet_private *fep,
- struct fec_enet_priv_tx_q *txq)
+static int fec_enet_get_free_txdesc_num(struct fec_enet_priv_tx_q *txq)
{
int entries;
- entries = ((const char *)txq->dirty_tx -
- (const char *)txq->cur_tx) / fep->bufdesc_size - 1;
+ entries = (((const char *)txq->dirty_tx -
+ (const char *)txq->bd.cur) >> txq->bd.dsize_log2) - 1;
- return entries > 0 ? entries : entries + txq->tx_ring_size;
+ return entries >= 0 ? entries : entries + txq->bd.ring_size;
}
static void swap_buffer(void *bufaddr, int len)
@@ -329,18 +281,20 @@ static void fec_dump(struct net_device *ndev)
pr_info("Nr SC addr len SKB\n");
txq = fep->tx_queue[0];
- bdp = txq->tx_bd_base;
+ bdp = txq->bd.base;
do {
- pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n",
+ pr_info("%3u %c%c 0x%04x 0x%08x %4u %p\n",
index,
- bdp == txq->cur_tx ? 'S' : ' ',
+ bdp == txq->bd.cur ? 'S' : ' ',
bdp == txq->dirty_tx ? 'H' : ' ',
- bdp->cbd_sc, bdp->cbd_bufaddr, bdp->cbd_datlen,
+ fec16_to_cpu(bdp->cbd_sc),
+ fec32_to_cpu(bdp->cbd_bufaddr),
+ fec16_to_cpu(bdp->cbd_datlen),
txq->tx_skbuff[index]);
- bdp = fec_enet_get_nextdesc(bdp, fep, 0);
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
index++;
- } while (bdp != txq->tx_bd_base);
+ } while (bdp != txq->bd.base);
}
static inline bool is_ipv4_pkt(struct sk_buff *skb)
@@ -371,10 +325,9 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- struct bufdesc *bdp = txq->cur_tx;
+ struct bufdesc *bdp = txq->bd.cur;
struct bufdesc_ex *ebdp;
int nr_frags = skb_shinfo(skb)->nr_frags;
- unsigned short queue = skb_get_queue_mapping(skb);
int frag, frag_len;
unsigned short status;
unsigned int estatus = 0;
@@ -386,10 +339,10 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
for (frag = 0; frag < nr_frags; frag++) {
this_frag = &skb_shinfo(skb)->frags[frag];
- bdp = fec_enet_get_nextdesc(bdp, fep, queue);
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
ebdp = (struct bufdesc_ex *)bdp;
- status = bdp->cbd_sc;
+ status = fec16_to_cpu(bdp->cbd_sc);
status &= ~BD_ENET_TX_STATS;
status |= (BD_ENET_TX_TC | BD_ENET_TX_READY);
frag_len = skb_shinfo(skb)->frags[frag].size;
@@ -407,16 +360,16 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
if (fep->bufdesc_ex) {
if (fep->quirks & FEC_QUIRK_HAS_AVB)
- estatus |= FEC_TX_BD_FTYPE(queue);
+ estatus |= FEC_TX_BD_FTYPE(txq->bd.qid);
if (skb->ip_summed == CHECKSUM_PARTIAL)
estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
ebdp->cbd_bdu = 0;
- ebdp->cbd_esc = estatus;
+ ebdp->cbd_esc = cpu_to_fec32(estatus);
}
bufaddr = page_address(this_frag->page.p) + this_frag->page_offset;
- index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
+ index = fec_enet_get_bd_index(bdp, &txq->bd);
if (((unsigned long) bufaddr) & fep->tx_align ||
fep->quirks & FEC_QUIRK_SWAP_FRAME) {
memcpy(txq->tx_bounce[index], bufaddr, frag_len);
@@ -429,24 +382,27 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
addr = dma_map_single(&fep->pdev->dev, bufaddr, frag_len,
DMA_TO_DEVICE);
if (dma_mapping_error(&fep->pdev->dev, addr)) {
- dev_kfree_skb_any(skb);
if (net_ratelimit())
netdev_err(ndev, "Tx DMA memory map failed\n");
goto dma_mapping_error;
}
- bdp->cbd_bufaddr = addr;
- bdp->cbd_datlen = frag_len;
- bdp->cbd_sc = status;
+ bdp->cbd_bufaddr = cpu_to_fec32(addr);
+ bdp->cbd_datlen = cpu_to_fec16(frag_len);
+ /* Make sure the updates to rest of the descriptor are
+ * performed before transferring ownership.
+ */
+ wmb();
+ bdp->cbd_sc = cpu_to_fec16(status);
}
return bdp;
dma_mapping_error:
- bdp = txq->cur_tx;
+ bdp = txq->bd.cur;
for (i = 0; i < frag; i++) {
- bdp = fec_enet_get_nextdesc(bdp, fep, queue);
- dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
- bdp->cbd_datlen, DMA_TO_DEVICE);
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
+ dma_unmap_single(&fep->pdev->dev, fec32_to_cpu(bdp->cbd_bufaddr),
+ fec16_to_cpu(bdp->cbd_datlen), DMA_TO_DEVICE);
}
return ERR_PTR(-ENOMEM);
}
@@ -461,12 +417,11 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
dma_addr_t addr;
unsigned short status;
unsigned short buflen;
- unsigned short queue;
unsigned int estatus = 0;
unsigned int index;
int entries_free;
- entries_free = fec_enet_get_free_txdesc_num(fep, txq);
+ entries_free = fec_enet_get_free_txdesc_num(txq);
if (entries_free < MAX_SKB_FRAGS + 1) {
dev_kfree_skb_any(skb);
if (net_ratelimit())
@@ -481,17 +436,16 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
}
/* Fill in a Tx ring entry */
- bdp = txq->cur_tx;
+ bdp = txq->bd.cur;
last_bdp = bdp;
- status = bdp->cbd_sc;
+ status = fec16_to_cpu(bdp->cbd_sc);
status &= ~BD_ENET_TX_STATS;
/* Set buffer length and buffer pointer */
bufaddr = skb->data;
buflen = skb_headlen(skb);
- queue = skb_get_queue_mapping(skb);
- index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
+ index = fec_enet_get_bd_index(bdp, &txq->bd);
if (((unsigned long) bufaddr) & fep->tx_align ||
fep->quirks & FEC_QUIRK_SWAP_FRAME) {
memcpy(txq->tx_bounce[index], skb->data, buflen);
@@ -512,8 +466,12 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
if (nr_frags) {
last_bdp = fec_enet_txq_submit_frag_skb(txq, skb, ndev);
- if (IS_ERR(last_bdp))
+ if (IS_ERR(last_bdp)) {
+ dma_unmap_single(&fep->pdev->dev, addr,
+ buflen, DMA_TO_DEVICE);
+ dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
+ }
} else {
status |= (BD_ENET_TX_INTR | BD_ENET_TX_LAST);
if (fep->bufdesc_ex) {
@@ -523,6 +481,8 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
estatus |= BD_ENET_TX_TS;
}
}
+ bdp->cbd_bufaddr = cpu_to_fec32(addr);
+ bdp->cbd_datlen = cpu_to_fec16(buflen);
if (fep->bufdesc_ex) {
@@ -533,41 +493,43 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
if (fep->quirks & FEC_QUIRK_HAS_AVB)
- estatus |= FEC_TX_BD_FTYPE(queue);
+ estatus |= FEC_TX_BD_FTYPE(txq->bd.qid);
if (skb->ip_summed == CHECKSUM_PARTIAL)
estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
ebdp->cbd_bdu = 0;
- ebdp->cbd_esc = estatus;
+ ebdp->cbd_esc = cpu_to_fec32(estatus);
}
- index = fec_enet_get_bd_index(txq->tx_bd_base, last_bdp, fep);
+ index = fec_enet_get_bd_index(last_bdp, &txq->bd);
/* Save skb pointer */
txq->tx_skbuff[index] = skb;
- bdp->cbd_datlen = buflen;
- bdp->cbd_bufaddr = addr;
+ /* Make sure the updates to rest of the descriptor are performed before
+ * transferring ownership.
+ */
+ wmb();
/* Send it on its way. Tell FEC it's ready, interrupt when done,
* it's the last BD of the frame, and to put the CRC on the end.
*/
status |= (BD_ENET_TX_READY | BD_ENET_TX_TC);
- bdp->cbd_sc = status;
+ bdp->cbd_sc = cpu_to_fec16(status);
/* If this was the last BD in the ring, start at the beginning again. */
- bdp = fec_enet_get_nextdesc(last_bdp, fep, queue);
+ bdp = fec_enet_get_nextdesc(last_bdp, &txq->bd);
skb_tx_timestamp(skb);
/* Make sure the update to bdp and tx_skbuff are performed before
- * cur_tx.
+ * txq->bd.cur.
*/
wmb();
- txq->cur_tx = bdp;
+ txq->bd.cur = bdp;
/* Trigger transmission start */
- writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue));
+ writel(0, txq->bd.reg_desc_active);
return 0;
}
@@ -580,12 +542,11 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct bufdesc_ex *ebdp = container_of(bdp, struct bufdesc_ex, desc);
- unsigned short queue = skb_get_queue_mapping(skb);
unsigned short status;
unsigned int estatus = 0;
dma_addr_t addr;
- status = bdp->cbd_sc;
+ status = fec16_to_cpu(bdp->cbd_sc);
status &= ~BD_ENET_TX_STATS;
status |= (BD_ENET_TX_TC | BD_ENET_TX_READY);
@@ -607,16 +568,16 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
- bdp->cbd_datlen = size;
- bdp->cbd_bufaddr = addr;
+ bdp->cbd_datlen = cpu_to_fec16(size);
+ bdp->cbd_bufaddr = cpu_to_fec32(addr);
if (fep->bufdesc_ex) {
if (fep->quirks & FEC_QUIRK_HAS_AVB)
- estatus |= FEC_TX_BD_FTYPE(queue);
+ estatus |= FEC_TX_BD_FTYPE(txq->bd.qid);
if (skb->ip_summed == CHECKSUM_PARTIAL)
estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
ebdp->cbd_bdu = 0;
- ebdp->cbd_esc = estatus;
+ ebdp->cbd_esc = cpu_to_fec32(estatus);
}
/* Handle the last BD specially */
@@ -625,10 +586,10 @@ fec_enet_txq_put_data_tso(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb,
if (is_last) {
status |= BD_ENET_TX_INTR;
if (fep->bufdesc_ex)
- ebdp->cbd_esc |= BD_ENET_TX_INT;
+ ebdp->cbd_esc |= cpu_to_fec32(BD_ENET_TX_INT);
}
- bdp->cbd_sc = status;
+ bdp->cbd_sc = cpu_to_fec16(status);
return 0;
}
@@ -641,13 +602,12 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
struct fec_enet_private *fep = netdev_priv(ndev);
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
struct bufdesc_ex *ebdp = container_of(bdp, struct bufdesc_ex, desc);
- unsigned short queue = skb_get_queue_mapping(skb);
void *bufaddr;
unsigned long dmabuf;
unsigned short status;
unsigned int estatus = 0;
- status = bdp->cbd_sc;
+ status = fec16_to_cpu(bdp->cbd_sc);
status &= ~BD_ENET_TX_STATS;
status |= (BD_ENET_TX_TC | BD_ENET_TX_READY);
@@ -671,19 +631,19 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
}
}
- bdp->cbd_bufaddr = dmabuf;
- bdp->cbd_datlen = hdr_len;
+ bdp->cbd_bufaddr = cpu_to_fec32(dmabuf);
+ bdp->cbd_datlen = cpu_to_fec16(hdr_len);
if (fep->bufdesc_ex) {
if (fep->quirks & FEC_QUIRK_HAS_AVB)
- estatus |= FEC_TX_BD_FTYPE(queue);
+ estatus |= FEC_TX_BD_FTYPE(txq->bd.qid);
if (skb->ip_summed == CHECKSUM_PARTIAL)
estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
ebdp->cbd_bdu = 0;
- ebdp->cbd_esc = estatus;
+ ebdp->cbd_esc = cpu_to_fec32(estatus);
}
- bdp->cbd_sc = status;
+ bdp->cbd_sc = cpu_to_fec16(status);
return 0;
}
@@ -695,13 +655,12 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
struct fec_enet_private *fep = netdev_priv(ndev);
int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
int total_len, data_left;
- struct bufdesc *bdp = txq->cur_tx;
- unsigned short queue = skb_get_queue_mapping(skb);
+ struct bufdesc *bdp = txq->bd.cur;
struct tso_t tso;
unsigned int index = 0;
int ret;
- if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(fep, txq)) {
+ if (tso_count_descs(skb) >= fec_enet_get_free_txdesc_num(txq)) {
dev_kfree_skb_any(skb);
if (net_ratelimit())
netdev_err(ndev, "NOT enough BD for TSO!\n");
@@ -721,7 +680,7 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
while (total_len > 0) {
char *hdr;
- index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
+ index = fec_enet_get_bd_index(bdp, &txq->bd);
data_left = min_t(int, skb_shinfo(skb)->gso_size, total_len);
total_len -= data_left;
@@ -736,9 +695,8 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
int size;
size = min_t(int, tso.size, data_left);
- bdp = fec_enet_get_nextdesc(bdp, fep, queue);
- index = fec_enet_get_bd_index(txq->tx_bd_base,
- bdp, fep);
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
+ index = fec_enet_get_bd_index(bdp, &txq->bd);
ret = fec_enet_txq_put_data_tso(txq, skb, ndev,
bdp, index,
tso.data, size,
@@ -751,22 +709,22 @@ static int fec_enet_txq_submit_tso(struct fec_enet_priv_tx_q *txq,
tso_build_data(skb, &tso, size);
}
- bdp = fec_enet_get_nextdesc(bdp, fep, queue);
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
}
/* Save skb pointer */
txq->tx_skbuff[index] = skb;
skb_tx_timestamp(skb);
- txq->cur_tx = bdp;
+ txq->bd.cur = bdp;
/* Trigger transmission start */
if (!(fep->quirks & FEC_QUIRK_ERR007885) ||
- !readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
- !readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
- !readl(fep->hwp + FEC_X_DES_ACTIVE(queue)) ||
- !readl(fep->hwp + FEC_X_DES_ACTIVE(queue)))
- writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue));
+ !readl(txq->bd.reg_desc_active) ||
+ !readl(txq->bd.reg_desc_active) ||
+ !readl(txq->bd.reg_desc_active) ||
+ !readl(txq->bd.reg_desc_active))
+ writel(0, txq->bd.reg_desc_active);
return 0;
@@ -796,7 +754,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if (ret)
return ret;
- entries_free = fec_enet_get_free_txdesc_num(fep, txq);
+ entries_free = fec_enet_get_free_txdesc_num(txq);
if (entries_free <= txq->tx_stop_threshold)
netif_tx_stop_queue(nq);
@@ -817,45 +775,45 @@ static void fec_enet_bd_init(struct net_device *dev)
for (q = 0; q < fep->num_rx_queues; q++) {
/* Initialize the receive buffer descriptors. */
rxq = fep->rx_queue[q];
- bdp = rxq->rx_bd_base;
+ bdp = rxq->bd.base;
- for (i = 0; i < rxq->rx_ring_size; i++) {
+ for (i = 0; i < rxq->bd.ring_size; i++) {
/* Initialize the BD for every fragment in the page. */
if (bdp->cbd_bufaddr)
- bdp->cbd_sc = BD_ENET_RX_EMPTY;
+ bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY);
else
- bdp->cbd_sc = 0;
- bdp = fec_enet_get_nextdesc(bdp, fep, q);
+ bdp->cbd_sc = cpu_to_fec16(0);
+ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
}
/* Set the last buffer to wrap */
- bdp = fec_enet_get_prevdesc(bdp, fep, q);
- bdp->cbd_sc |= BD_SC_WRAP;
+ bdp = fec_enet_get_prevdesc(bdp, &rxq->bd);
+ bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);
- rxq->cur_rx = rxq->rx_bd_base;
+ rxq->bd.cur = rxq->bd.base;
}
for (q = 0; q < fep->num_tx_queues; q++) {
/* ...and the same for transmit */
txq = fep->tx_queue[q];
- bdp = txq->tx_bd_base;
- txq->cur_tx = bdp;
+ bdp = txq->bd.base;
+ txq->bd.cur = bdp;
- for (i = 0; i < txq->tx_ring_size; i++) {
+ for (i = 0; i < txq->bd.ring_size; i++) {
/* Initialize the BD for every fragment in the page. */
- bdp->cbd_sc = 0;
+ bdp->cbd_sc = cpu_to_fec16(0);
if (txq->tx_skbuff[i]) {
dev_kfree_skb_any(txq->tx_skbuff[i]);
txq->tx_skbuff[i] = NULL;
}
- bdp->cbd_bufaddr = 0;
- bdp = fec_enet_get_nextdesc(bdp, fep, q);
+ bdp->cbd_bufaddr = cpu_to_fec32(0);
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
}
/* Set the last buffer to wrap */
- bdp = fec_enet_get_prevdesc(bdp, fep, q);
- bdp->cbd_sc |= BD_SC_WRAP;
+ bdp = fec_enet_get_prevdesc(bdp, &txq->bd);
+ bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);
txq->dirty_tx = bdp;
}
}
@@ -866,7 +824,7 @@ static void fec_enet_active_rxring(struct net_device *ndev)
int i;
for (i = 0; i < fep->num_rx_queues; i++)
- writel(0, fep->hwp + FEC_R_DES_ACTIVE(i));
+ writel(0, fep->rx_queue[i]->bd.reg_desc_active);
}
static void fec_enet_enable_ring(struct net_device *ndev)
@@ -878,7 +836,7 @@ static void fec_enet_enable_ring(struct net_device *ndev)
for (i = 0; i < fep->num_rx_queues; i++) {
rxq = fep->rx_queue[i];
- writel(rxq->bd_dma, fep->hwp + FEC_R_DES_START(i));
+ writel(rxq->bd.dma, fep->hwp + FEC_R_DES_START(i));
writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE(i));
/* enable DMA1/2 */
@@ -889,7 +847,7 @@ static void fec_enet_enable_ring(struct net_device *ndev)
for (i = 0; i < fep->num_tx_queues; i++) {
txq = fep->tx_queue[i];
- writel(txq->bd_dma, fep->hwp + FEC_X_DES_START(i));
+ writel(txq->bd.dma, fep->hwp + FEC_X_DES_START(i));
/* enable DMA1/2 */
if (i)
@@ -907,7 +865,7 @@ static void fec_enet_reset_skb(struct net_device *ndev)
for (i = 0; i < fep->num_tx_queues; i++) {
txq = fep->tx_queue[i];
- for (j = 0; j < txq->tx_ring_size; j++) {
+ for (j = 0; j < txq->bd.ring_size; j++) {
if (txq->tx_skbuff[j]) {
dev_kfree_skb_any(txq->tx_skbuff[j]);
txq->tx_skbuff[j] = NULL;
@@ -947,8 +905,10 @@ fec_restart(struct net_device *ndev)
*/
if (fep->quirks & FEC_QUIRK_ENET_MAC) {
memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN);
- writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
- writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
+ writel((__force u32)cpu_to_be32(temp_mac[0]),
+ fep->hwp + FEC_ADDR_LOW);
+ writel((__force u32)cpu_to_be32(temp_mac[1]),
+ fep->hwp + FEC_ADDR_HIGH);
}
/* Clear any outstanding interrupt. */
@@ -984,6 +944,7 @@ fec_restart(struct net_device *ndev)
val &= ~FEC_RACC_OPTIONS;
writel(val, fep->hwp + FEC_RACC);
}
+ writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_FTRL);
#endif
/*
@@ -1217,25 +1178,27 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
bdp = txq->dirty_tx;
/* get next bdp of dirty_tx */
- bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
- while (bdp != READ_ONCE(txq->cur_tx)) {
- /* Order the load of cur_tx and cbd_sc */
+ while (bdp != READ_ONCE(txq->bd.cur)) {
+ /* Order the load of bd.cur and cbd_sc */
rmb();
- status = READ_ONCE(bdp->cbd_sc);
+ status = fec16_to_cpu(READ_ONCE(bdp->cbd_sc));
if (status & BD_ENET_TX_READY)
break;
- index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
+ index = fec_enet_get_bd_index(bdp, &txq->bd);
skb = txq->tx_skbuff[index];
txq->tx_skbuff[index] = NULL;
- if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr))
- dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
- bdp->cbd_datlen, DMA_TO_DEVICE);
- bdp->cbd_bufaddr = 0;
+ if (!IS_TSO_HEADER(txq, fec32_to_cpu(bdp->cbd_bufaddr)))
+ dma_unmap_single(&fep->pdev->dev,
+ fec32_to_cpu(bdp->cbd_bufaddr),
+ fec16_to_cpu(bdp->cbd_datlen),
+ DMA_TO_DEVICE);
+ bdp->cbd_bufaddr = cpu_to_fec32(0);
if (!skb) {
- bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
continue;
}
@@ -1264,7 +1227,7 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
struct skb_shared_hwtstamps shhwtstamps;
struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
- fec_enet_hwtstamp(fep, ebdp->ts, &shhwtstamps);
+ fec_enet_hwtstamp(fep, fec32_to_cpu(ebdp->ts), &shhwtstamps);
skb_tstamp_tx(skb, &shhwtstamps);
}
@@ -1284,21 +1247,21 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
txq->dirty_tx = bdp;
/* Update pointer to next buffer descriptor to be transmitted */
- bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
/* Since we have freed up a buffer, the ring is no longer full
*/
if (netif_queue_stopped(ndev)) {
- entries_free = fec_enet_get_free_txdesc_num(fep, txq);
+ entries_free = fec_enet_get_free_txdesc_num(txq);
if (entries_free >= txq->tx_wake_threshold)
netif_tx_wake_queue(nq);
}
}
/* ERR006538: Keep the transmitter going */
- if (bdp != txq->cur_tx &&
- readl(fep->hwp + FEC_X_DES_ACTIVE(queue_id)) == 0)
- writel(0, fep->hwp + FEC_X_DES_ACTIVE(queue_id));
+ if (bdp != txq->bd.cur &&
+ readl(txq->bd.reg_desc_active) == 0)
+ writel(0, txq->bd.reg_desc_active);
}
static void
@@ -1324,10 +1287,8 @@ fec_enet_new_rxbdp(struct net_device *ndev, struct bufdesc *bdp, struct sk_buff
if (off)
skb_reserve(skb, fep->rx_align + 1 - off);
- bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data,
- FEC_ENET_RX_FRSIZE - fep->rx_align,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(&fep->pdev->dev, bdp->cbd_bufaddr)) {
+ bdp->cbd_bufaddr = cpu_to_fec32(dma_map_single(&fep->pdev->dev, skb->data, FEC_ENET_RX_FRSIZE - fep->rx_align, DMA_FROM_DEVICE));
+ if (dma_mapping_error(&fep->pdev->dev, fec32_to_cpu(bdp->cbd_bufaddr))) {
if (net_ratelimit())
netdev_err(ndev, "Rx DMA memory map failed\n");
return -ENOMEM;
@@ -1349,7 +1310,8 @@ static bool fec_enet_copybreak(struct net_device *ndev, struct sk_buff **skb,
if (!new_skb)
return false;
- dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr,
+ dma_sync_single_for_cpu(&fep->pdev->dev,
+ fec32_to_cpu(bdp->cbd_bufaddr),
FEC_ENET_RX_FRSIZE - fep->rx_align,
DMA_FROM_DEVICE);
if (!swap)
@@ -1361,7 +1323,7 @@ static bool fec_enet_copybreak(struct net_device *ndev, struct sk_buff **skb,
return true;
}
-/* During a receive, the cur_rx points to the current incoming buffer.
+/* During a receive, the bd_rx.cur points to the current incoming buffer.
* When we update through the ring, if the next incoming buffer has
* not been given to the system, we just set the empty indicator,
* effectively tossing the packet.
@@ -1394,54 +1356,48 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
/* First, grab all of the stats for the incoming packet.
* These get messed up if we get called due to a busy condition.
*/
- bdp = rxq->cur_rx;
+ bdp = rxq->bd.cur;
- while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
+ while (!((status = fec16_to_cpu(bdp->cbd_sc)) & BD_ENET_RX_EMPTY)) {
if (pkt_received >= budget)
break;
pkt_received++;
- /* Since we have allocated space to hold a complete frame,
- * the last indicator should be set.
- */
- if ((status & BD_ENET_RX_LAST) == 0)
- netdev_err(ndev, "rcv is not +last\n");
-
writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
/* Check for errors. */
+ status ^= BD_ENET_RX_LAST;
if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
- BD_ENET_RX_CR | BD_ENET_RX_OV)) {
+ BD_ENET_RX_CR | BD_ENET_RX_OV | BD_ENET_RX_LAST |
+ BD_ENET_RX_CL)) {
ndev->stats.rx_errors++;
- if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
+ if (status & BD_ENET_RX_OV) {
+ /* FIFO overrun */
+ ndev->stats.rx_fifo_errors++;
+ goto rx_processing_done;
+ }
+ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH
+ | BD_ENET_RX_LAST)) {
/* Frame too long or too short. */
ndev->stats.rx_length_errors++;
+ if (status & BD_ENET_RX_LAST)
+ netdev_err(ndev, "rcv is not +last\n");
}
- if (status & BD_ENET_RX_NO) /* Frame alignment */
- ndev->stats.rx_frame_errors++;
if (status & BD_ENET_RX_CR) /* CRC Error */
ndev->stats.rx_crc_errors++;
- if (status & BD_ENET_RX_OV) /* FIFO overrun */
- ndev->stats.rx_fifo_errors++;
- }
-
- /* Report late collisions as a frame error.
- * On this error, the BD is closed, but we don't know what we
- * have in the buffer. So, just drop this frame on the floor.
- */
- if (status & BD_ENET_RX_CL) {
- ndev->stats.rx_errors++;
- ndev->stats.rx_frame_errors++;
+ /* Report late collisions as a frame error. */
+ if (status & (BD_ENET_RX_NO | BD_ENET_RX_CL))
+ ndev->stats.rx_frame_errors++;
goto rx_processing_done;
}
/* Process the incoming frame. */
ndev->stats.rx_packets++;
- pkt_len = bdp->cbd_datlen;
+ pkt_len = fec16_to_cpu(bdp->cbd_datlen);
ndev->stats.rx_bytes += pkt_len;
- index = fec_enet_get_bd_index(rxq->rx_bd_base, bdp, fep);
+ index = fec_enet_get_bd_index(bdp, &rxq->bd);
skb = rxq->rx_skbuff[index];
/* The packet length includes FCS, but we don't want to
@@ -1456,7 +1412,8 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
ndev->stats.rx_dropped++;
goto rx_processing_done;
}
- dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
+ dma_unmap_single(&fep->pdev->dev,
+ fec32_to_cpu(bdp->cbd_bufaddr),
FEC_ENET_RX_FRSIZE - fep->rx_align,
DMA_FROM_DEVICE);
}
@@ -1475,7 +1432,8 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
/* If this is a VLAN packet remove the VLAN Tag */
vlan_packet_rcvd = false;
if ((ndev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
- fep->bufdesc_ex && (ebdp->cbd_esc & BD_ENET_RX_VLAN)) {
+ fep->bufdesc_ex &&
+ (ebdp->cbd_esc & cpu_to_fec32(BD_ENET_RX_VLAN))) {
/* Push and remove the vlan tag */
struct vlan_hdr *vlan_header =
(struct vlan_hdr *) (data + ETH_HLEN);
@@ -1491,12 +1449,12 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
/* Get receive timestamp from the skb */
if (fep->hwts_rx_en && fep->bufdesc_ex)
- fec_enet_hwtstamp(fep, ebdp->ts,
+ fec_enet_hwtstamp(fep, fec32_to_cpu(ebdp->ts),
skb_hwtstamps(skb));
if (fep->bufdesc_ex &&
(fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
- if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) {
+ if (!(ebdp->cbd_esc & cpu_to_fec32(FLAG_RX_CSUM_ERROR))) {
/* don't check it */
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else {
@@ -1513,7 +1471,8 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
napi_gro_receive(&fep->napi, skb);
if (is_copybreak) {
- dma_sync_single_for_device(&fep->pdev->dev, bdp->cbd_bufaddr,
+ dma_sync_single_for_device(&fep->pdev->dev,
+ fec32_to_cpu(bdp->cbd_bufaddr),
FEC_ENET_RX_FRSIZE - fep->rx_align,
DMA_FROM_DEVICE);
} else {
@@ -1527,26 +1486,30 @@ rx_processing_done:
/* Mark the buffer empty */
status |= BD_ENET_RX_EMPTY;
- bdp->cbd_sc = status;
if (fep->bufdesc_ex) {
struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
- ebdp->cbd_esc = BD_ENET_RX_INT;
+ ebdp->cbd_esc = cpu_to_fec32(BD_ENET_RX_INT);
ebdp->cbd_prot = 0;
ebdp->cbd_bdu = 0;
}
+ /* Make sure the updates to rest of the descriptor are
+ * performed before transferring ownership.
+ */
+ wmb();
+ bdp->cbd_sc = cpu_to_fec16(status);
/* Update BD pointer to next entry */
- bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
+ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
/* Doing this here will keep the FEC running while we process
* incoming frames. On a heavily loaded network, we should be
* able to keep up at the expense of system resources.
*/
- writel(0, fep->hwp + FEC_R_DES_ACTIVE(queue_id));
+ writel(0, rxq->bd.reg_desc_active);
}
- rxq->cur_rx = bdp;
+ rxq->bd.cur = bdp;
return pkt_received;
}
@@ -1605,7 +1568,7 @@ fec_enet_interrupt(int irq, void *dev_id)
if (napi_schedule_prep(&fep->napi)) {
/* Disable the NAPI interrupts */
- writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);
+ writel(FEC_NAPI_IMASK, fep->hwp + FEC_IMASK);
__napi_schedule(&fep->napi);
}
}
@@ -2145,8 +2108,7 @@ static int fec_enet_get_regs_len(struct net_device *ndev)
/* List of registers that can be safety be read to dump them with ethtool */
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
- defined(CONFIG_M520x) || defined(CONFIG_M532x) || \
- defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
+ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM)
static u32 fec_enet_register_offset[] = {
FEC_IEVENT, FEC_IMASK, FEC_R_DES_ACTIVE_0, FEC_X_DES_ACTIVE_0,
FEC_ECNTRL, FEC_MII_DATA, FEC_MII_SPEED, FEC_MIB_CTRLSTAT, FEC_R_CNTRL,
@@ -2656,25 +2618,25 @@ static void fec_enet_free_buffers(struct net_device *ndev)
for (q = 0; q < fep->num_rx_queues; q++) {
rxq = fep->rx_queue[q];
- bdp = rxq->rx_bd_base;
- for (i = 0; i < rxq->rx_ring_size; i++) {
+ bdp = rxq->bd.base;
+ for (i = 0; i < rxq->bd.ring_size; i++) {
skb = rxq->rx_skbuff[i];
rxq->rx_skbuff[i] = NULL;
if (skb) {
dma_unmap_single(&fep->pdev->dev,
- bdp->cbd_bufaddr,
+ fec32_to_cpu(bdp->cbd_bufaddr),
FEC_ENET_RX_FRSIZE - fep->rx_align,
DMA_FROM_DEVICE);
dev_kfree_skb(skb);
}
- bdp = fec_enet_get_nextdesc(bdp, fep, q);
+ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
}
}
for (q = 0; q < fep->num_tx_queues; q++) {
txq = fep->tx_queue[q];
- bdp = txq->tx_bd_base;
- for (i = 0; i < txq->tx_ring_size; i++) {
+ bdp = txq->bd.base;
+ for (i = 0; i < txq->bd.ring_size; i++) {
kfree(txq->tx_bounce[i]);
txq->tx_bounce[i] = NULL;
skb = txq->tx_skbuff[i];
@@ -2694,7 +2656,7 @@ static void fec_enet_free_queue(struct net_device *ndev)
if (fep->tx_queue[i] && fep->tx_queue[i]->tso_hdrs) {
txq = fep->tx_queue[i];
dma_free_coherent(NULL,
- txq->tx_ring_size * TSO_HEADER_SIZE,
+ txq->bd.ring_size * TSO_HEADER_SIZE,
txq->tso_hdrs,
txq->tso_hdrs_dma);
}
@@ -2720,15 +2682,15 @@ static int fec_enet_alloc_queue(struct net_device *ndev)
}
fep->tx_queue[i] = txq;
- txq->tx_ring_size = TX_RING_SIZE;
- fep->total_tx_ring_size += fep->tx_queue[i]->tx_ring_size;
+ txq->bd.ring_size = TX_RING_SIZE;
+ fep->total_tx_ring_size += fep->tx_queue[i]->bd.ring_size;
txq->tx_stop_threshold = FEC_MAX_SKB_DESCS;
txq->tx_wake_threshold =
- (txq->tx_ring_size - txq->tx_stop_threshold) / 2;
+ (txq->bd.ring_size - txq->tx_stop_threshold) / 2;
txq->tso_hdrs = dma_alloc_coherent(NULL,
- txq->tx_ring_size * TSO_HEADER_SIZE,
+ txq->bd.ring_size * TSO_HEADER_SIZE,
&txq->tso_hdrs_dma,
GFP_KERNEL);
if (!txq->tso_hdrs) {
@@ -2745,8 +2707,8 @@ static int fec_enet_alloc_queue(struct net_device *ndev)
goto alloc_failed;
}
- fep->rx_queue[i]->rx_ring_size = RX_RING_SIZE;
- fep->total_rx_ring_size += fep->rx_queue[i]->rx_ring_size;
+ fep->rx_queue[i]->bd.ring_size = RX_RING_SIZE;
+ fep->total_rx_ring_size += fep->rx_queue[i]->bd.ring_size;
}
return ret;
@@ -2765,8 +2727,8 @@ fec_enet_alloc_rxq_buffers(struct net_device *ndev, unsigned int queue)
struct fec_enet_priv_rx_q *rxq;
rxq = fep->rx_queue[queue];
- bdp = rxq->rx_bd_base;
- for (i = 0; i < rxq->rx_ring_size; i++) {
+ bdp = rxq->bd.base;
+ for (i = 0; i < rxq->bd.ring_size; i++) {
skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
if (!skb)
goto err_alloc;
@@ -2777,19 +2739,19 @@ fec_enet_alloc_rxq_buffers(struct net_device *ndev, unsigned int queue)
}
rxq->rx_skbuff[i] = skb;
- bdp->cbd_sc = BD_ENET_RX_EMPTY;
+ bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY);
if (fep->bufdesc_ex) {
struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
- ebdp->cbd_esc = BD_ENET_RX_INT;
+ ebdp->cbd_esc = cpu_to_fec32(BD_ENET_RX_INT);
}
- bdp = fec_enet_get_nextdesc(bdp, fep, queue);
+ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
}
/* Set the last buffer to wrap. */
- bdp = fec_enet_get_prevdesc(bdp, fep, queue);
- bdp->cbd_sc |= BD_SC_WRAP;
+ bdp = fec_enet_get_prevdesc(bdp, &rxq->bd);
+ bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);
return 0;
err_alloc:
@@ -2806,26 +2768,26 @@ fec_enet_alloc_txq_buffers(struct net_device *ndev, unsigned int queue)
struct fec_enet_priv_tx_q *txq;
txq = fep->tx_queue[queue];
- bdp = txq->tx_bd_base;
- for (i = 0; i < txq->tx_ring_size; i++) {
+ bdp = txq->bd.base;
+ for (i = 0; i < txq->bd.ring_size; i++) {
txq->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
if (!txq->tx_bounce[i])
goto err_alloc;
- bdp->cbd_sc = 0;
- bdp->cbd_bufaddr = 0;
+ bdp->cbd_sc = cpu_to_fec16(0);
+ bdp->cbd_bufaddr = cpu_to_fec32(0);
if (fep->bufdesc_ex) {
struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
- ebdp->cbd_esc = BD_ENET_TX_INT;
+ ebdp->cbd_esc = cpu_to_fec32(BD_ENET_TX_INT);
}
- bdp = fec_enet_get_nextdesc(bdp, fep, queue);
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
}
/* Set the last buffer to wrap. */
- bdp = fec_enet_get_prevdesc(bdp, fep, queue);
- bdp->cbd_sc |= BD_SC_WRAP;
+ bdp = fec_enet_get_prevdesc(bdp, &txq->bd);
+ bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);
return 0;
@@ -3108,6 +3070,14 @@ static const struct net_device_ops fec_netdev_ops = {
.ndo_set_features = fec_set_features,
};
+static const unsigned short offset_des_active_rxq[] = {
+ FEC_R_DES_ACTIVE_0, FEC_R_DES_ACTIVE_1, FEC_R_DES_ACTIVE_2
+};
+
+static const unsigned short offset_des_active_txq[] = {
+ FEC_X_DES_ACTIVE_0, FEC_X_DES_ACTIVE_1, FEC_X_DES_ACTIVE_2
+};
+
/*
* XXX: We need to clean up on failure exits here.
*
@@ -3115,13 +3085,15 @@ static const struct net_device_ops fec_netdev_ops = {
static int fec_enet_init(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- struct fec_enet_priv_tx_q *txq;
- struct fec_enet_priv_rx_q *rxq;
struct bufdesc *cbd_base;
dma_addr_t bd_dma;
int bd_size;
unsigned int i;
+ unsigned dsize = fep->bufdesc_ex ? sizeof(struct bufdesc_ex) :
+ sizeof(struct bufdesc);
+ unsigned dsize_log2 = __fls(dsize);
+ WARN_ON(dsize != (1 << dsize_log2));
#if defined(CONFIG_ARM)
fep->rx_align = 0xf;
fep->tx_align = 0xf;
@@ -3132,12 +3104,7 @@ static int fec_enet_init(struct net_device *ndev)
fec_enet_alloc_queue(ndev);
- if (fep->bufdesc_ex)
- fep->bufdesc_size = sizeof(struct bufdesc_ex);
- else
- fep->bufdesc_size = sizeof(struct bufdesc);
- bd_size = (fep->total_tx_ring_size + fep->total_rx_ring_size) *
- fep->bufdesc_size;
+ bd_size = (fep->total_tx_ring_size + fep->total_rx_ring_size) * dsize;
/* Allocate memory for buffer descriptors. */
cbd_base = dmam_alloc_coherent(&fep->pdev->dev, bd_size, &bd_dma,
@@ -3155,33 +3122,35 @@ static int fec_enet_init(struct net_device *ndev)
/* Set receive and transmit descriptor base. */
for (i = 0; i < fep->num_rx_queues; i++) {
- rxq = fep->rx_queue[i];
- rxq->index = i;
- rxq->rx_bd_base = (struct bufdesc *)cbd_base;
- rxq->bd_dma = bd_dma;
- if (fep->bufdesc_ex) {
- bd_dma += sizeof(struct bufdesc_ex) * rxq->rx_ring_size;
- cbd_base = (struct bufdesc *)
- (((struct bufdesc_ex *)cbd_base) + rxq->rx_ring_size);
- } else {
- bd_dma += sizeof(struct bufdesc) * rxq->rx_ring_size;
- cbd_base += rxq->rx_ring_size;
- }
+ struct fec_enet_priv_rx_q *rxq = fep->rx_queue[i];
+ unsigned size = dsize * rxq->bd.ring_size;
+
+ rxq->bd.qid = i;
+ rxq->bd.base = cbd_base;
+ rxq->bd.cur = cbd_base;
+ rxq->bd.dma = bd_dma;
+ rxq->bd.dsize = dsize;
+ rxq->bd.dsize_log2 = dsize_log2;
+ rxq->bd.reg_desc_active = fep->hwp + offset_des_active_rxq[i];
+ bd_dma += size;
+ cbd_base = (struct bufdesc *)(((void *)cbd_base) + size);
+ rxq->bd.last = (struct bufdesc *)(((void *)cbd_base) - dsize);
}
for (i = 0; i < fep->num_tx_queues; i++) {
- txq = fep->tx_queue[i];
- txq->index = i;
- txq->tx_bd_base = (struct bufdesc *)cbd_base;
- txq->bd_dma = bd_dma;
- if (fep->bufdesc_ex) {
- bd_dma += sizeof(struct bufdesc_ex) * txq->tx_ring_size;
- cbd_base = (struct bufdesc *)
- (((struct bufdesc_ex *)cbd_base) + txq->tx_ring_size);
- } else {
- bd_dma += sizeof(struct bufdesc) * txq->tx_ring_size;
- cbd_base += txq->tx_ring_size;
- }
+ struct fec_enet_priv_tx_q *txq = fep->tx_queue[i];
+ unsigned size = dsize * txq->bd.ring_size;
+
+ txq->bd.qid = i;
+ txq->bd.base = cbd_base;
+ txq->bd.cur = cbd_base;
+ txq->bd.dma = bd_dma;
+ txq->bd.dsize = dsize;
+ txq->bd.dsize_log2 = dsize_log2;
+ txq->bd.reg_desc_active = fep->hwp + offset_des_active_txq[i];
+ bd_dma += size;
+ cbd_base = (struct bufdesc *)(((void *)cbd_base) + size);
+ txq->bd.last = (struct bufdesc *)(((void *)cbd_base) - dsize);
}
@@ -3222,6 +3191,7 @@ static int fec_enet_init(struct net_device *ndev)
static void fec_reset_phy(struct platform_device *pdev)
{
int err, phy_reset;
+ bool active_high = false;
int msec = 1;
struct device_node *np = pdev->dev.of_node;
@@ -3237,14 +3207,17 @@ static void fec_reset_phy(struct platform_device *pdev)
if (!gpio_is_valid(phy_reset))
return;
+ active_high = of_property_read_bool(np, "phy-reset-active-high");
+
err = devm_gpio_request_one(&pdev->dev, phy_reset,
- GPIOF_OUT_INIT_LOW, "phy-reset");
+ active_high ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
+ "phy-reset");
if (err) {
dev_err(&pdev->dev, "failed to get phy-reset-gpios: %d\n", err);
return;
}
msleep(msec);
- gpio_set_value_cansleep(phy_reset, 1);
+ gpio_set_value_cansleep(phy_reset, !active_high);
}
#else /* CONFIG_OF */
static void fec_reset_phy(struct platform_device *pdev)
diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c
index 623aa1c8ebc6..ea83712a6d62 100644
--- a/drivers/net/ethernet/freescale/fman/fman.c
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -35,6 +35,7 @@
#include "fman.h"
#include "fman_muram.h"
+#include <linux/fsl/guts.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/module.h>
@@ -1871,6 +1872,90 @@ err_fm_state:
return -EINVAL;
}
+static int fman_reset(struct fman *fman)
+{
+ u32 count;
+ int err = 0;
+
+ if (fman->state->rev_info.major < 6) {
+ iowrite32be(FPM_RSTC_FM_RESET, &fman->fpm_regs->fm_rstc);
+ /* Wait for reset completion */
+ count = 100;
+ do {
+ udelay(1);
+ } while (((ioread32be(&fman->fpm_regs->fm_rstc)) &
+ FPM_RSTC_FM_RESET) && --count);
+ if (count == 0)
+ err = -EBUSY;
+
+ goto _return;
+ } else {
+ struct device_node *guts_node;
+ struct ccsr_guts __iomem *guts_regs;
+ u32 devdisr2, reg;
+
+ /* Errata A007273 */
+ guts_node =
+ of_find_compatible_node(NULL, NULL,
+ "fsl,qoriq-device-config-2.0");
+ if (!guts_node) {
+ dev_err(fman->dev, "%s: Couldn't find guts node\n",
+ __func__);
+ goto guts_node;
+ }
+
+ guts_regs = of_iomap(guts_node, 0);
+ if (!guts_regs) {
+ dev_err(fman->dev, "%s: Couldn't map %s regs\n",
+ __func__, guts_node->full_name);
+ goto guts_regs;
+ }
+#define FMAN1_ALL_MACS_MASK 0xFCC00000
+#define FMAN2_ALL_MACS_MASK 0x000FCC00
+ /* Read current state */
+ devdisr2 = ioread32be(&guts_regs->devdisr2);
+ if (fman->dts_params.id == 0)
+ reg = devdisr2 & ~FMAN1_ALL_MACS_MASK;
+ else
+ reg = devdisr2 & ~FMAN2_ALL_MACS_MASK;
+
+ /* Enable all MACs */
+ iowrite32be(reg, &guts_regs->devdisr2);
+
+ /* Perform FMan reset */
+ iowrite32be(FPM_RSTC_FM_RESET, &fman->fpm_regs->fm_rstc);
+
+ /* Wait for reset completion */
+ count = 100;
+ do {
+ udelay(1);
+ } while (((ioread32be(&fman->fpm_regs->fm_rstc)) &
+ FPM_RSTC_FM_RESET) && --count);
+ if (count == 0) {
+ iounmap(guts_regs);
+ of_node_put(guts_node);
+ err = -EBUSY;
+ goto _return;
+ }
+
+ /* Restore devdisr2 value */
+ iowrite32be(devdisr2, &guts_regs->devdisr2);
+
+ iounmap(guts_regs);
+ of_node_put(guts_node);
+
+ goto _return;
+
+guts_regs:
+ of_node_put(guts_node);
+guts_node:
+ dev_dbg(fman->dev, "%s: Didn't perform FManV3 reset due to Errata A007273!\n",
+ __func__);
+ }
+_return:
+ return err;
+}
+
static int fman_init(struct fman *fman)
{
struct fman_cfg *cfg = NULL;
@@ -1914,22 +1999,9 @@ static int fman_init(struct fman *fman)
fman->liodn_base[i] = liodn_base;
}
- /* FMan Reset (supported only for FMan V2) */
- if (fman->state->rev_info.major >= 6) {
- /* Errata A007273 */
- dev_dbg(fman->dev, "%s: FManV3 reset is not supported!\n",
- __func__);
- } else {
- iowrite32be(FPM_RSTC_FM_RESET, &fman->fpm_regs->fm_rstc);
- /* Wait for reset completion */
- count = 100;
- do {
- udelay(1);
- } while (((ioread32be(&fman->fpm_regs->fm_rstc)) &
- FPM_RSTC_FM_RESET) && --count);
- if (count == 0)
- return -EBUSY;
- }
+ err = fman_reset(fman);
+ if (err)
+ return err;
if (ioread32be(&fman->qmi_regs->fmqm_gs) & QMI_GS_HALT_NOT_BUSY) {
resume(fman->fpm_regs);
@@ -2791,6 +2863,8 @@ static struct fman *read_dts_node(struct platform_device *of_dev)
goto fman_free;
}
+ fman->dev = &of_dev->dev;
+
return fman;
fman_node_put:
@@ -2845,8 +2919,6 @@ static int fman_probe(struct platform_device *of_dev)
dev_set_drvdata(dev, fman);
- fman->dev = dev;
-
dev_dbg(dev, "FMan%d probed\n", fman->dts_params.id);
return 0;
diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c
index 7c92eb854925..c88918c4c5f3 100644
--- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c
+++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c
@@ -932,15 +932,14 @@ int dtsec_set_tx_pause_frames(struct fman_mac *dtsec,
if (!is_init_done(dtsec->dtsec_drv_param))
return -EINVAL;
- /* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 Errata workaround */
- if (dtsec->fm_rev_info.major == 2)
- if (pause_time <= 320) {
+ if (pause_time) {
+ /* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 Errata workaround */
+ if (dtsec->fm_rev_info.major == 2 && pause_time <= 320) {
pr_warn("pause-time: %d illegal.Should be > 320\n",
pause_time);
return -EINVAL;
}
- if (pause_time) {
ptv = ioread32be(&regs->ptv);
ptv &= PTV_PTE_MASK;
ptv |= pause_time & PTV_PT_MASK;
diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
index 52e0091b4fb2..1ba359f17ec6 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
@@ -552,7 +552,7 @@ static void tx_restart(struct net_device *dev)
cbd_t __iomem *prev_bd;
cbd_t __iomem *last_tx_bd;
- last_tx_bd = fep->tx_bd_base + ((fpi->tx_ring - 1) * sizeof(cbd_t));
+ last_tx_bd = fep->tx_bd_base + (fpi->tx_ring - 1);
/* get the current bd held in TBPTR and scan back from this point */
recheck_bd = curr_tbptr = (cbd_t __iomem *)
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 2aa7b401cc3b..d2f917af539f 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -1111,8 +1111,10 @@ static void __gfar_detect_errata_85xx(struct gfar_private *priv)
if ((SVR_SOC_VER(svr) == SVR_8548) && (SVR_REV(svr) == 0x20))
priv->errata |= GFAR_ERRATA_12;
+ /* P2020/P1010 Rev 1; MPC8548 Rev 2 */
if (((SVR_SOC_VER(svr) == SVR_P2020) && (SVR_REV(svr) < 0x20)) ||
- ((SVR_SOC_VER(svr) == SVR_P2010) && (SVR_REV(svr) < 0x20)))
+ ((SVR_SOC_VER(svr) == SVR_P2010) && (SVR_REV(svr) < 0x20)) ||
+ ((SVR_SOC_VER(svr) == SVR_8548) && (SVR_REV(svr) < 0x31)))
priv->errata |= GFAR_ERRATA_76; /* aka eTSEC 20 */
}
#endif
@@ -2322,6 +2324,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct txfcb *fcb = NULL;
struct txbd8 *txbdp, *txbdp_start, *base, *txbdp_tstamp = NULL;
u32 lstatus;
+ skb_frag_t *frag;
int i, rq = 0;
int do_tstamp, do_csum, do_vlan;
u32 bufaddr;
@@ -2389,52 +2392,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
txbdp = txbdp_start = tx_queue->cur_tx;
lstatus = be32_to_cpu(txbdp->lstatus);
- /* Time stamp insertion requires one additional TxBD */
- if (unlikely(do_tstamp))
- txbdp_tstamp = txbdp = next_txbd(txbdp, base,
- tx_queue->tx_ring_size);
-
- if (nr_frags == 0) {
- if (unlikely(do_tstamp)) {
- u32 lstatus_ts = be32_to_cpu(txbdp_tstamp->lstatus);
-
- lstatus_ts |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
- txbdp_tstamp->lstatus = cpu_to_be32(lstatus_ts);
- } else {
- lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
- }
- } else {
- /* Place the fragment addresses and lengths into the TxBDs */
- for (i = 0; i < nr_frags; i++) {
- unsigned int frag_len;
- /* Point at the next BD, wrapping as needed */
- txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size);
-
- frag_len = skb_shinfo(skb)->frags[i].size;
-
- lstatus = be32_to_cpu(txbdp->lstatus) | frag_len |
- BD_LFLAG(TXBD_READY);
-
- /* Handle the last BD specially */
- if (i == nr_frags - 1)
- lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
-
- bufaddr = skb_frag_dma_map(priv->dev,
- &skb_shinfo(skb)->frags[i],
- 0,
- frag_len,
- DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(priv->dev, bufaddr)))
- goto dma_map_err;
-
- /* set the TxBD length and buffer pointer */
- txbdp->bufPtr = cpu_to_be32(bufaddr);
- txbdp->lstatus = cpu_to_be32(lstatus);
- }
-
- lstatus = be32_to_cpu(txbdp_start->lstatus);
- }
-
/* Add TxPAL between FCB and frame if required */
if (unlikely(do_tstamp)) {
skb_push(skb, GMAC_TXPAL_LEN);
@@ -2469,12 +2426,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (do_vlan)
gfar_tx_vlan(skb, fcb);
- /* Setup tx hardware time stamping if requested */
- if (unlikely(do_tstamp)) {
- skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
- fcb->ptp = 1;
- }
-
bufaddr = dma_map_single(priv->dev, skb->data, skb_headlen(skb),
DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(priv->dev, bufaddr)))
@@ -2482,6 +2433,46 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
txbdp_start->bufPtr = cpu_to_be32(bufaddr);
+ /* Time stamp insertion requires one additional TxBD */
+ if (unlikely(do_tstamp))
+ txbdp_tstamp = txbdp = next_txbd(txbdp, base,
+ tx_queue->tx_ring_size);
+
+ if (likely(!nr_frags)) {
+ lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
+ } else {
+ u32 lstatus_start = lstatus;
+
+ /* Place the fragment addresses and lengths into the TxBDs */
+ frag = &skb_shinfo(skb)->frags[0];
+ for (i = 0; i < nr_frags; i++, frag++) {
+ unsigned int size;
+
+ /* Point at the next BD, wrapping as needed */
+ txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size);
+
+ size = skb_frag_size(frag);
+
+ lstatus = be32_to_cpu(txbdp->lstatus) | size |
+ BD_LFLAG(TXBD_READY);
+
+ /* Handle the last BD specially */
+ if (i == nr_frags - 1)
+ lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
+
+ bufaddr = skb_frag_dma_map(priv->dev, frag, 0,
+ size, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(priv->dev, bufaddr)))
+ goto dma_map_err;
+
+ /* set the TxBD length and buffer pointer */
+ txbdp->bufPtr = cpu_to_be32(bufaddr);
+ txbdp->lstatus = cpu_to_be32(lstatus);
+ }
+
+ lstatus = lstatus_start;
+ }
+
/* If time stamping is requested one additional TxBD must be set up. The
* first TxBD points to the FCB and must have a data length of
* GMAC_FCB_LEN. The second TxBD points to the actual frame data with
@@ -2492,12 +2483,19 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
bufaddr = be32_to_cpu(txbdp_start->bufPtr);
bufaddr += fcb_len;
+
lstatus_ts |= BD_LFLAG(TXBD_READY) |
(skb_headlen(skb) - fcb_len);
+ if (!nr_frags)
+ lstatus_ts |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
txbdp_tstamp->bufPtr = cpu_to_be32(bufaddr);
txbdp_tstamp->lstatus = cpu_to_be32(lstatus_ts);
lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | GMAC_FCB_LEN;
+
+ /* Setup tx hardware time stamping */
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ fcb->ptp = 1;
} else {
lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb);
}
@@ -2710,7 +2708,7 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
~0x7UL);
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
- shhwtstamps.hwtstamp = ns_to_ktime(*ns);
+ shhwtstamps.hwtstamp = ns_to_ktime(be64_to_cpu(*ns));
skb_pull(skb, GMAC_FCB_LEN + GMAC_TXPAL_LEN);
skb_tstamp_tx(skb, &shhwtstamps);
gfar_clear_txbd_status(bdp);
@@ -2942,7 +2940,7 @@ static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus,
/* change offset to the other half */
rxb->page_offset ^= GFAR_RXB_TRUESIZE;
- atomic_inc(&page->_count);
+ page_ref_inc(page);
return true;
}
@@ -3039,7 +3037,7 @@ static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb)
u64 *ns = (u64 *) skb->data;
memset(shhwtstamps, 0, sizeof(*shhwtstamps));
- shhwtstamps->hwtstamp = ns_to_ktime(*ns);
+ shhwtstamps->hwtstamp = ns_to_ktime(be64_to_cpu(*ns));
}
if (priv->padding)
diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c
index b40fba929d65..57798814160d 100644
--- a/drivers/net/ethernet/freescale/gianfar_ptp.c
+++ b/drivers/net/ethernet/freescale/gianfar_ptp.c
@@ -422,19 +422,6 @@ static struct ptp_clock_info ptp_gianfar_caps = {
.enable = ptp_gianfar_enable,
};
-/* OF device tree */
-
-static int get_of_u32(struct device_node *node, char *str, u32 *val)
-{
- int plen;
- const u32 *prop = of_get_property(node, str, &plen);
-
- if (!prop || plen != sizeof(*prop))
- return -1;
- *val = *prop;
- return 0;
-}
-
static int gianfar_ptp_probe(struct platform_device *dev)
{
struct device_node *node = dev->dev.of_node;
@@ -452,15 +439,21 @@ static int gianfar_ptp_probe(struct platform_device *dev)
etsects->caps = ptp_gianfar_caps;
- if (get_of_u32(node, "fsl,cksel", &etsects->cksel))
+ if (of_property_read_u32(node, "fsl,cksel", &etsects->cksel))
etsects->cksel = DEFAULT_CKSEL;
- if (get_of_u32(node, "fsl,tclk-period", &etsects->tclk_period) ||
- get_of_u32(node, "fsl,tmr-prsc", &etsects->tmr_prsc) ||
- get_of_u32(node, "fsl,tmr-add", &etsects->tmr_add) ||
- get_of_u32(node, "fsl,tmr-fiper1", &etsects->tmr_fiper1) ||
- get_of_u32(node, "fsl,tmr-fiper2", &etsects->tmr_fiper2) ||
- get_of_u32(node, "fsl,max-adj", &etsects->caps.max_adj)) {
+ if (of_property_read_u32(node,
+ "fsl,tclk-period", &etsects->tclk_period) ||
+ of_property_read_u32(node,
+ "fsl,tmr-prsc", &etsects->tmr_prsc) ||
+ of_property_read_u32(node,
+ "fsl,tmr-add", &etsects->tmr_add) ||
+ of_property_read_u32(node,
+ "fsl,tmr-fiper1", &etsects->tmr_fiper1) ||
+ of_property_read_u32(node,
+ "fsl,tmr-fiper2", &etsects->tmr_fiper2) ||
+ of_property_read_u32(node,
+ "fsl,max-adj", &etsects->caps.max_adj)) {
pr_err("device tree node missing required elements\n");
goto no_node;
}
OpenPOWER on IntegriCloud