Currently, the buffer descriptor (BD) fields cannot be correctly accessed by a little endian processor. This patch fixes the issue by making the access of BDs to be portable among different cpu architectures.
Use portable data types for the Rx/Tx buffer descriptor fields. Use portable I/O accessors to insure that the big endian BDs are correctly accessed by little endian cpus too, and to insure proper sync with the H/W. Removed the redundant RTXBD "volatile" type, as proper synchronization around BD data accesses is provided by the I/O accessors now. The "sparse" tool was also used to verify the correctness of these changes. Cc: Scott Wood <scottw...@freescale.com> Signed-off-by: Claudiu Manoil <claudiu.man...@freescale.com> --- v2: * used portable I/O accessors (in_be/out_be) * replaced macro usage * retested on p1020 (ping, tftp) drivers/net/tsec.c | 108 ++++++++++++++++++++++++++++++++--------------------- include/tsec.h | 22 +++++------ 2 files changed, 76 insertions(+), 54 deletions(-) diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 289229a..b48e595 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -28,13 +28,30 @@ DECLARE_GLOBAL_DATA_PTR; static uint rx_idx; /* index of the current RX buffer */ static uint tx_idx; /* index of the current TX buffer */ -typedef volatile struct rtxbd { - txbd8_t txbd[TX_BUF_CNT]; - rxbd8_t rxbd[PKTBUFSRX]; -} RTXBD; - #ifdef __GNUC__ -static RTXBD rtx __attribute__ ((aligned(8))); +static struct txbd8 txbd[TX_BUF_CNT] __aligned(8); +static struct rxbd8 rxbd[PKTBUFSRX] __aligned(8); + +static inline u16 read_txbd_stat(uint idx) +{ + return in_be16((u16 __iomem *)&txbd[idx].status); +} + +static inline void write_txbd_stat(uint idx, u16 status) +{ + out_be16((u16 __iomem *)&txbd[idx].status, status); +} + +static inline u16 read_rxbd_stat(uint idx) +{ + return in_be16((u16 __iomem *)&rxbd[idx].status); +} + +static inline void write_rxbd_stat(uint idx, u16 status) +{ + out_be16((u16 __iomem *)&rxbd[idx].status, status); +} + #else #error "rtx must be 64-bit aligned" #endif @@ -275,10 +292,11 @@ void redundant_init(struct eth_device *dev) clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); do { + uint16_t status; tsec_send(dev, (void *)pkt, sizeof(pkt)); /* Wait for buffer to be received */ - for (t = 0; rtx.rxbd[rx_idx].status & RXBD_EMPTY; t++) { + for (t = 0; read_rxbd_stat(rx_idx) & RXBD_EMPTY; t++) { if (t >= 10 * TOUT_LOOP) { printf("%s: tsec: rx error\n", dev->name); break; @@ -288,9 +306,11 @@ void redundant_init(struct eth_device *dev) if (!memcmp(pkt, (void *)NetRxPackets[rx_idx], sizeof(pkt))) fail = 0; - rtx.rxbd[rx_idx].length = 0; - rtx.rxbd[rx_idx].status = - RXBD_EMPTY | (((rx_idx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); + out_be16((u16 __iomem *)&rxbd[rx_idx].length, 0); + status = RXBD_EMPTY; + if ((rx_idx + 1) == PKTBUFSRX) + status |= RXBD_WRAP; + write_rxbd_stat(rx_idx, status); rx_idx = (rx_idx + 1) % PKTBUFSRX; if (in_be32(®s->ievent) & IEVENT_BSY) { @@ -319,9 +339,10 @@ void redundant_init(struct eth_device *dev) */ static void startup_tsec(struct eth_device *dev) { - int i; struct tsec_private *priv = (struct tsec_private *)dev->priv; struct tsec __iomem *regs = priv->regs; + uint16_t status; + int i; /* reset the indices to zero */ rx_idx = 0; @@ -331,24 +352,26 @@ static void startup_tsec(struct eth_device *dev) #endif /* Point to the buffer descriptors */ - out_be32(®s->tbase, (unsigned int)(&rtx.txbd[tx_idx])); - out_be32(®s->rbase, (unsigned int)(&rtx.rxbd[rx_idx])); + out_be32(®s->tbase, (u32)&txbd[0]); + out_be32(®s->rbase, (u32)&rxbd[0]); /* Initialize the Rx Buffer descriptors */ for (i = 0; i < PKTBUFSRX; i++) { - rtx.rxbd[i].status = RXBD_EMPTY; - rtx.rxbd[i].length = 0; - rtx.rxbd[i].bufptr = (uint) NetRxPackets[i]; + write_rxbd_stat(i, RXBD_EMPTY); + out_be16((u16 __iomem *)&rxbd[i].length, 0); + out_be32((u32 __iomem *)&rxbd[i].bufptr, (u32)NetRxPackets[i]); } - rtx.rxbd[PKTBUFSRX - 1].status |= RXBD_WRAP; + status = read_rxbd_stat(PKTBUFSRX - 1); + write_rxbd_stat(PKTBUFSRX - 1, status | RXBD_WRAP); /* Initialize the TX Buffer Descriptors */ for (i = 0; i < TX_BUF_CNT; i++) { - rtx.txbd[i].status = 0; - rtx.txbd[i].length = 0; - rtx.txbd[i].bufptr = 0; + write_txbd_stat(i, 0); + out_be16((u16 __iomem *)&txbd[i].length, 0); + out_be32((u32 __iomem *)&txbd[i].bufptr, 0); } - rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP; + status = read_txbd_stat(TX_BUF_CNT - 1); + write_txbd_stat(TX_BUF_CNT - 1, status | TXBD_WRAP); #ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129 svr = get_svr(); @@ -372,29 +395,31 @@ static void startup_tsec(struct eth_device *dev) */ static int tsec_send(struct eth_device *dev, void *packet, int length) { - int i; - int result = 0; struct tsec_private *priv = (struct tsec_private *)dev->priv; struct tsec __iomem *regs = priv->regs; + uint16_t status; + int result = 0; + int i; /* Find an empty buffer descriptor */ - for (i = 0; rtx.txbd[tx_idx].status & TXBD_READY; i++) { + for (i = 0; read_txbd_stat(tx_idx) & TXBD_READY; i++) { if (i >= TOUT_LOOP) { debug("%s: tsec: tx buffers full\n", dev->name); return result; } } - rtx.txbd[tx_idx].bufptr = (uint) packet; - rtx.txbd[tx_idx].length = length; - rtx.txbd[tx_idx].status |= - (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT); + out_be32((u32 __iomem *)&txbd[tx_idx].bufptr, (u32)packet); + out_be16((u16 __iomem *)&txbd[tx_idx].length, length); + status = read_txbd_stat(tx_idx); + write_txbd_stat(tx_idx, status | + (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT)); /* Tell the DMA to go */ out_be32(®s->tstat, TSTAT_CLEAR_THALT); /* Wait for buffer to be transmitted */ - for (i = 0; rtx.txbd[tx_idx].status & TXBD_READY; i++) { + for (i = 0; read_txbd_stat(tx_idx) & TXBD_READY; i++) { if (i >= TOUT_LOOP) { debug("%s: tsec: tx error\n", dev->name); return result; @@ -402,34 +427,33 @@ static int tsec_send(struct eth_device *dev, void *packet, int length) } tx_idx = (tx_idx + 1) % TX_BUF_CNT; - result = rtx.txbd[tx_idx].status & TXBD_STATS; + result = read_txbd_stat(tx_idx) & TXBD_STATS; return result; } static int tsec_recv(struct eth_device *dev) { - int length; struct tsec_private *priv = (struct tsec_private *)dev->priv; struct tsec __iomem *regs = priv->regs; - while (!(rtx.rxbd[rx_idx].status & RXBD_EMPTY)) { - - length = rtx.rxbd[rx_idx].length; + while (!(read_rxbd_stat(rx_idx) & RXBD_EMPTY)) { + int length = in_be16((u16 __iomem *)&rxbd[rx_idx].length); + uint16_t status = read_rxbd_stat(rx_idx); /* Send the packet up if there were no errors */ - if (!(rtx.rxbd[rx_idx].status & RXBD_STATS)) { + if (!(status & RXBD_STATS)) NetReceive(NetRxPackets[rx_idx], length - 4); - } else { - printf("Got error %x\n", - (rtx.rxbd[rx_idx].status & RXBD_STATS)); - } + else + printf("Got error %x\n", (status & RXBD_STATS)); - rtx.rxbd[rx_idx].length = 0; + out_be16((u16 __iomem *)&rxbd[rx_idx].length, 0); + status = RXBD_EMPTY; /* Set the wrap bit if this is the last element in the list */ - rtx.rxbd[rx_idx].status = - RXBD_EMPTY | (((rx_idx + 1) == PKTBUFSRX) ? RXBD_WRAP : 0); + if ((rx_idx + 1) == PKTBUFSRX) + status |= RXBD_WRAP; + write_rxbd_stat(rx_idx, status); rx_idx = (rx_idx + 1) % PKTBUFSRX; } diff --git a/include/tsec.h b/include/tsec.h index 6bc43ef..95054be 100644 --- a/include/tsec.h +++ b/include/tsec.h @@ -198,19 +198,17 @@ #define RXBD_TRUNCATED 0x0001 #define RXBD_STATS 0x003f -typedef struct txbd8 -{ - ushort status; /* Status Fields */ - ushort length; /* Buffer length */ - uint bufptr; /* Buffer Pointer */ -} txbd8_t; +struct txbd8 { + uint16_t status; /* Status Fields */ + uint16_t length; /* Buffer length */ + uint32_t bufptr; /* Buffer Pointer */ +}; -typedef struct rxbd8 -{ - ushort status; /* Status Fields */ - ushort length; /* Buffer Length */ - uint bufptr; /* Buffer Pointer */ -} rxbd8_t; +struct rxbd8 { + uint16_t status; /* Status Fields */ + uint16_t length; /* Buffer Length */ + uint32_t bufptr; /* Buffer Pointer */ +}; typedef struct rmon_mib { -- 1.7.11.7 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot