Skip to content

Commit

Permalink
net: ethernet: stmmac: change dma descriptors to __le32
Browse files Browse the repository at this point in the history
The stmmac driver does not take into account the processor may be big
endian when writing the DMA descriptors. This causes the ethernet
interface not to be initialised correctly when running a big-endian
kernel. Change the descriptors for DMA to use __le32 and ensure they are
suitably swapped before writing. Tested successfully on the
Cubieboard2.

Signed-off-by: Michael Weiser <michael.weiser@gmx.de>
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: Alexandre Torgue <alexandre.torgue@st.com>
Cc: netdev@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Michael Weiser authored and David S. Miller committed Nov 16, 2016
1 parent 4780566 commit f8be0d7
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 181 deletions.
55 changes: 29 additions & 26 deletions drivers/net/ethernet/stmicro/stmmac/chain_mode.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
unsigned int entry = priv->cur_tx;
struct dma_desc *desc = priv->dma_tx + entry;
unsigned int nopaged_len = skb_headlen(skb);
unsigned int bmax;
unsigned int bmax, des2;
unsigned int i = 1, len;

if (priv->plat->enh_desc)
Expand All @@ -44,11 +44,12 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)

len = nopaged_len - bmax;

desc->des2 = dma_map_single(priv->device, skb->data,
bmax, DMA_TO_DEVICE);
if (dma_mapping_error(priv->device, desc->des2))
des2 = dma_map_single(priv->device, skb->data,
bmax, DMA_TO_DEVICE);
desc->des2 = cpu_to_le32(des2);
if (dma_mapping_error(priv->device, des2))
return -1;
priv->tx_skbuff_dma[entry].buf = desc->des2;
priv->tx_skbuff_dma[entry].buf = des2;
priv->tx_skbuff_dma[entry].len = bmax;
/* do not close the descriptor and do not set own bit */
priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE,
Expand All @@ -60,25 +61,27 @@ static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc = priv->dma_tx + entry;

if (len > bmax) {
desc->des2 = dma_map_single(priv->device,
(skb->data + bmax * i),
bmax, DMA_TO_DEVICE);
if (dma_mapping_error(priv->device, desc->des2))
des2 = dma_map_single(priv->device,
(skb->data + bmax * i),
bmax, DMA_TO_DEVICE);
desc->des2 = cpu_to_le32(des2);
if (dma_mapping_error(priv->device, des2))
return -1;
priv->tx_skbuff_dma[entry].buf = desc->des2;
priv->tx_skbuff_dma[entry].buf = des2;
priv->tx_skbuff_dma[entry].len = bmax;
priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
STMMAC_CHAIN_MODE, 1,
false);
len -= bmax;
i++;
} else {
desc->des2 = dma_map_single(priv->device,
(skb->data + bmax * i), len,
DMA_TO_DEVICE);
if (dma_mapping_error(priv->device, desc->des2))
des2 = dma_map_single(priv->device,
(skb->data + bmax * i), len,
DMA_TO_DEVICE);
desc->des2 = cpu_to_le32(des2);
if (dma_mapping_error(priv->device, des2))
return -1;
priv->tx_skbuff_dma[entry].buf = desc->des2;
priv->tx_skbuff_dma[entry].buf = des2;
priv->tx_skbuff_dma[entry].len = len;
/* last descriptor can be set now */
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
Expand Down Expand Up @@ -119,19 +122,19 @@ static void stmmac_init_dma_chain(void *des, dma_addr_t phy_addr,
struct dma_extended_desc *p = (struct dma_extended_desc *)des;
for (i = 0; i < (size - 1); i++) {
dma_phy += sizeof(struct dma_extended_desc);
p->basic.des3 = (unsigned int)dma_phy;
p->basic.des3 = cpu_to_le32((unsigned int)dma_phy);
p++;
}
p->basic.des3 = (unsigned int)phy_addr;
p->basic.des3 = cpu_to_le32((unsigned int)phy_addr);

} else {
struct dma_desc *p = (struct dma_desc *)des;
for (i = 0; i < (size - 1); i++) {
dma_phy += sizeof(struct dma_desc);
p->des3 = (unsigned int)dma_phy;
p->des3 = cpu_to_le32((unsigned int)dma_phy);
p++;
}
p->des3 = (unsigned int)phy_addr;
p->des3 = cpu_to_le32((unsigned int)phy_addr);
}
}

Expand All @@ -144,10 +147,10 @@ static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
* 1588-2002 time stamping is enabled, hence reinitialize it
* to keep explicit chaining in the descriptor.
*/
p->des3 = (unsigned int)(priv->dma_rx_phy +
(((priv->dirty_rx) + 1) %
DMA_RX_SIZE) *
sizeof(struct dma_desc));
p->des3 = cpu_to_le32((unsigned int)(priv->dma_rx_phy +
(((priv->dirty_rx) + 1) %
DMA_RX_SIZE) *
sizeof(struct dma_desc)));
}

static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
Expand All @@ -161,9 +164,9 @@ static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
* 1588-2002 time stamping is enabled, hence reinitialize it
* to keep explicit chaining in the descriptor.
*/
p->des3 = (unsigned int)((priv->dma_tx_phy +
((priv->dirty_tx + 1) % DMA_TX_SIZE))
* sizeof(struct dma_desc));
p->des3 = cpu_to_le32((unsigned int)((priv->dma_tx_phy +
((priv->dirty_tx + 1) % DMA_TX_SIZE))
* sizeof(struct dma_desc)));
}

const struct stmmac_mode_ops chain_mode_ops = {
Expand Down
20 changes: 10 additions & 10 deletions drivers/net/ethernet/stmicro/stmmac/descs.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
#define TDES0_ERROR_SUMMARY BIT(15)
#define TDES0_IP_HEADER_ERROR BIT(16)
#define TDES0_TIME_STAMP_STATUS BIT(17)
#define TDES0_OWN BIT(31)
#define TDES0_OWN ((u32)BIT(31)) /* silence sparse */
/* TDES1 */
#define TDES1_BUFFER1_SIZE_MASK GENMASK(10, 0)
#define TDES1_BUFFER2_SIZE_MASK GENMASK(21, 11)
Expand Down Expand Up @@ -130,7 +130,7 @@
#define ETDES0_FIRST_SEGMENT BIT(28)
#define ETDES0_LAST_SEGMENT BIT(29)
#define ETDES0_INTERRUPT BIT(30)
#define ETDES0_OWN BIT(31)
#define ETDES0_OWN ((u32)BIT(31)) /* silence sparse */
/* TDES1 */
#define ETDES1_BUFFER1_SIZE_MASK GENMASK(12, 0)
#define ETDES1_BUFFER2_SIZE_MASK GENMASK(28, 16)
Expand Down Expand Up @@ -166,19 +166,19 @@

/* Basic descriptor structure for normal and alternate descriptors */
struct dma_desc {
unsigned int des0;
unsigned int des1;
unsigned int des2;
unsigned int des3;
__le32 des0;
__le32 des1;
__le32 des2;
__le32 des3;
};

/* Extended descriptor structure (e.g. >= databook 3.50a) */
struct dma_extended_desc {
struct dma_desc basic; /* Basic descriptors */
unsigned int des4; /* Extended Status */
unsigned int des5; /* Reserved */
unsigned int des6; /* Tx/Rx Timestamp Low */
unsigned int des7; /* Tx/Rx Timestamp High */
__le32 des4; /* Extended Status */
__le32 des5; /* Reserved */
__le32 des6; /* Tx/Rx Timestamp Low */
__le32 des7; /* Tx/Rx Timestamp High */
};

/* Transmit checksum insertion control */
Expand Down
48 changes: 26 additions & 22 deletions drivers/net/ethernet/stmicro/stmmac/descs_com.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,91 +35,95 @@
/* Enhanced descriptors */
static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end)
{
p->des1 |= ((BUF_SIZE_8KiB - 1) << ERDES1_BUFFER2_SIZE_SHIFT)
& ERDES1_BUFFER2_SIZE_MASK;
p->des1 |= cpu_to_le32(((BUF_SIZE_8KiB - 1)
<< ERDES1_BUFFER2_SIZE_SHIFT)
& ERDES1_BUFFER2_SIZE_MASK);

if (end)
p->des1 |= ERDES1_END_RING;
p->des1 |= cpu_to_le32(ERDES1_END_RING);
}

static inline void enh_desc_end_tx_desc_on_ring(struct dma_desc *p, int end)
{
if (end)
p->des0 |= ETDES0_END_RING;
p->des0 |= cpu_to_le32(ETDES0_END_RING);
else
p->des0 &= ~ETDES0_END_RING;
p->des0 &= cpu_to_le32(~ETDES0_END_RING);
}

static inline void enh_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
{
if (unlikely(len > BUF_SIZE_4KiB)) {
p->des1 |= (((len - BUF_SIZE_4KiB) << ETDES1_BUFFER2_SIZE_SHIFT)
p->des1 |= cpu_to_le32((((len - BUF_SIZE_4KiB)
<< ETDES1_BUFFER2_SIZE_SHIFT)
& ETDES1_BUFFER2_SIZE_MASK) | (BUF_SIZE_4KiB
& ETDES1_BUFFER1_SIZE_MASK);
& ETDES1_BUFFER1_SIZE_MASK));
} else
p->des1 |= (len & ETDES1_BUFFER1_SIZE_MASK);
p->des1 |= cpu_to_le32((len & ETDES1_BUFFER1_SIZE_MASK));
}

/* Normal descriptors */
static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end)
{
p->des1 |= ((BUF_SIZE_2KiB - 1) << RDES1_BUFFER2_SIZE_SHIFT)
& RDES1_BUFFER2_SIZE_MASK;
p->des1 |= cpu_to_le32(((BUF_SIZE_2KiB - 1)
<< RDES1_BUFFER2_SIZE_SHIFT)
& RDES1_BUFFER2_SIZE_MASK);

if (end)
p->des1 |= RDES1_END_RING;
p->des1 |= cpu_to_le32(RDES1_END_RING);
}

static inline void ndesc_end_tx_desc_on_ring(struct dma_desc *p, int end)
{
if (end)
p->des1 |= TDES1_END_RING;
p->des1 |= cpu_to_le32(TDES1_END_RING);
else
p->des1 &= ~TDES1_END_RING;
p->des1 &= cpu_to_le32(~TDES1_END_RING);
}

static inline void norm_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
{
if (unlikely(len > BUF_SIZE_2KiB)) {
unsigned int buffer1 = (BUF_SIZE_2KiB - 1)
& TDES1_BUFFER1_SIZE_MASK;
p->des1 |= ((((len - buffer1) << TDES1_BUFFER2_SIZE_SHIFT)
& TDES1_BUFFER2_SIZE_MASK) | buffer1);
p->des1 |= cpu_to_le32((((len - buffer1)
<< TDES1_BUFFER2_SIZE_SHIFT)
& TDES1_BUFFER2_SIZE_MASK) | buffer1);
} else
p->des1 |= (len & TDES1_BUFFER1_SIZE_MASK);
p->des1 |= cpu_to_le32((len & TDES1_BUFFER1_SIZE_MASK));
}

/* Specific functions used for Chain mode */

/* Enhanced descriptors */
static inline void ehn_desc_rx_set_on_chain(struct dma_desc *p)
{
p->des1 |= ERDES1_SECOND_ADDRESS_CHAINED;
p->des1 |= cpu_to_le32(ERDES1_SECOND_ADDRESS_CHAINED);
}

static inline void enh_desc_end_tx_desc_on_chain(struct dma_desc *p)
{
p->des0 |= ETDES0_SECOND_ADDRESS_CHAINED;
p->des0 |= cpu_to_le32(ETDES0_SECOND_ADDRESS_CHAINED);
}

static inline void enh_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
{
p->des1 |= (len & ETDES1_BUFFER1_SIZE_MASK);
p->des1 |= cpu_to_le32(len & ETDES1_BUFFER1_SIZE_MASK);
}

/* Normal descriptors */
static inline void ndesc_rx_set_on_chain(struct dma_desc *p, int end)
{
p->des1 |= RDES1_SECOND_ADDRESS_CHAINED;
p->des1 |= cpu_to_le32(RDES1_SECOND_ADDRESS_CHAINED);
}

static inline void ndesc_tx_set_on_chain(struct dma_desc *p)
{
p->des1 |= TDES1_SECOND_ADDRESS_CHAINED;
p->des1 |= cpu_to_le32(TDES1_SECOND_ADDRESS_CHAINED);
}

static inline void norm_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
{
p->des1 |= len & TDES1_BUFFER1_SIZE_MASK;
p->des1 |= cpu_to_le32(len & TDES1_BUFFER1_SIZE_MASK);
}
#endif /* __DESC_COM_H__ */
Loading

0 comments on commit f8be0d7

Please sign in to comment.