Skip to content

Commit

Permalink
Merge branch 'sun4i-emac-big-endian'
Browse files Browse the repository at this point in the history
Michael Weiser says:

====================
sun4i-emac: Fixes for running a big-endian kernel on Cubieboard2

the following patches are what remains to be fixed in order to allow running a
big-endian kernel on the Cubieboard2.

The first patch fixes up endianness problems with DMA descriptors in
the stmmac driver preventing it from working correctly when runnning a
big-endian kernel.

The second patch adds the ability to enable diagnostic messages in the
sun4i-emac driver which were instrumental in finding the problem fixed
by patch number three: Endianness confusion caused by dual-purpose I/O
register usage in sun4i-emac.

All of these have been tested successfully on a Cubieboard2 DualCard.

Changes since v4:
- Rebased to current master
- Removed already applied patches to sunxi-mmc and sunxi-Kconfig

Changes since v3:
- Rebased sunxi-mmc patch against Ulf's mmc.git/next
- Changed Kconfig change to enable big-endian support only for sun7i
  devices

Changes since v2:
- Fixed typo in stmmac patch causing a build failure
- Added sun4i-emac patches

Changes since v1:
- Fixed checkpatch niggles
- Added respective Cc:s
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Nov 16, 2016
2 parents 4780566 + 934d004 commit 92547f2
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 183 deletions.
25 changes: 23 additions & 2 deletions drivers/net/ethernet/allwinner/sun4i-emac.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@

#define EMAC_MAX_FRAME_LEN 0x0600

#define EMAC_DEFAULT_MSG_ENABLE 0x0000
static int debug = -1; /* defaults above */;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "debug message flags");

/* Transmit timeout, default 5 seconds. */
static int watchdog = 5000;
module_param(watchdog, int, 0400);
Expand Down Expand Up @@ -225,11 +230,27 @@ static void emac_get_drvinfo(struct net_device *dev,
strlcpy(info->bus_info, dev_name(&dev->dev), sizeof(info->bus_info));
}

static u32 emac_get_msglevel(struct net_device *dev)
{
struct emac_board_info *db = netdev_priv(dev);

return db->msg_enable;
}

static void emac_set_msglevel(struct net_device *dev, u32 value)
{
struct emac_board_info *db = netdev_priv(dev);

db->msg_enable = value;
}

static const struct ethtool_ops emac_ethtool_ops = {
.get_drvinfo = emac_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
.get_msglevel = emac_get_msglevel,
.set_msglevel = emac_set_msglevel,
};

static unsigned int emac_setup(struct net_device *ndev)
Expand Down Expand Up @@ -571,8 +592,7 @@ static void emac_rx(struct net_device *dev)
/* A packet ready now & Get status/length */
good_packet = true;

emac_inblk_32bit(db->membase + EMAC_RX_IO_DATA_REG,
&rxhdr, sizeof(rxhdr));
rxhdr = readl(db->membase + EMAC_RX_IO_DATA_REG);

if (netif_msg_rx_status(db))
dev_dbg(db->dev, "rxhdr: %x\n", *((int *)(&rxhdr)));
Expand Down Expand Up @@ -804,6 +824,7 @@ static int emac_probe(struct platform_device *pdev)
db->dev = &pdev->dev;
db->ndev = ndev;
db->pdev = pdev;
db->msg_enable = netif_msg_init(debug, EMAC_DEFAULT_MSG_ENABLE);

spin_lock_init(&db->lock);

Expand Down
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 92547f2

Please sign in to comment.