Commit 2a446c51 authored by David S. Miller's avatar David S. Miller

Merge branch 'ftgmac100-rework-batch4-misc'

Benjamin Herrenschmidt says:

====================
ftgmac100: Rework batch 4 - Misc

This is v2 of the fourth batch of updates to the ftgmac100 driver.

This is a bunch of misc cleanups and fixes, such as properly
disabling HW checksum generation on AST2400 where it's known
to be broken and some chip init updates.

This also adds the ability to turn HW checksum on/off and
configure the ring sizes via ethtool.

v2 Fixes patch 1/10 (NETIF_F_HW_CSUM conversion)

The next (and last) batch will add a few more "features" such
as netpoll, multicast/promist, vlan offload...
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents f221dcd9 bd3e4fde
...@@ -42,18 +42,16 @@ vic: interrupt-controller@1e6c0080 { ...@@ -42,18 +42,16 @@ vic: interrupt-controller@1e6c0080 {
}; };
mac0: ethernet@1e660000 { mac0: ethernet@1e660000 {
compatible = "faraday,ftgmac100"; compatible = "aspeed,ast2400-mac", "faraday,ftgmac100";
reg = <0x1e660000 0x180>; reg = <0x1e660000 0x180>;
interrupts = <2>; interrupts = <2>;
no-hw-checksum;
status = "disabled"; status = "disabled";
}; };
mac1: ethernet@1e680000 { mac1: ethernet@1e680000 {
compatible = "faraday,ftgmac100"; compatible = "aspeed,ast2400-mac", "faraday,ftgmac100";
reg = <0x1e680000 0x180>; reg = <0x1e680000 0x180>;
interrupts = <3>; interrupts = <3>;
no-hw-checksum;
status = "disabled"; status = "disabled";
}; };
......
...@@ -33,18 +33,16 @@ vic: interrupt-controller@1e6c0080 { ...@@ -33,18 +33,16 @@ vic: interrupt-controller@1e6c0080 {
}; };
mac0: ethernet@1e660000 { mac0: ethernet@1e660000 {
compatible = "faraday,ftgmac100"; compatible = "aspeed,ast2500-mac", "faraday,ftgmac100";
reg = <0x1e660000 0x180>; reg = <0x1e660000 0x180>;
interrupts = <2>; interrupts = <2>;
no-hw-checksum;
status = "disabled"; status = "disabled";
}; };
mac1: ethernet@1e680000 { mac1: ethernet@1e680000 {
compatible = "faraday,ftgmac100"; compatible = "aspeed,ast2500-mac", "faraday,ftgmac100";
reg = <0x1e680000 0x180>; reg = <0x1e680000 0x180>;
interrupts = <3>; interrupts = <3>;
no-hw-checksum;
status = "disabled"; status = "disabled";
}; };
......
...@@ -40,8 +40,15 @@ ...@@ -40,8 +40,15 @@
#define DRV_NAME "ftgmac100" #define DRV_NAME "ftgmac100"
#define DRV_VERSION "0.7" #define DRV_VERSION "0.7"
#define RX_QUEUE_ENTRIES 256 /* must be power of 2 */ /* Arbitrary values, I am not sure the HW has limits */
#define TX_QUEUE_ENTRIES 512 /* must be power of 2 */ #define MAX_RX_QUEUE_ENTRIES 1024
#define MAX_TX_QUEUE_ENTRIES 1024
#define MIN_RX_QUEUE_ENTRIES 32
#define MIN_TX_QUEUE_ENTRIES 32
/* Defaults */
#define DEF_RX_QUEUE_ENTRIES 128
#define DEF_TX_QUEUE_ENTRIES 128
#define MAX_PKT_SIZE 1536 #define MAX_PKT_SIZE 1536
#define RX_BUF_SIZE MAX_PKT_SIZE /* must be smaller than 0x3fff */ #define RX_BUF_SIZE MAX_PKT_SIZE /* must be smaller than 0x3fff */
...@@ -49,30 +56,32 @@ ...@@ -49,30 +56,32 @@
/* Min number of tx ring entries before stopping queue */ /* Min number of tx ring entries before stopping queue */
#define TX_THRESHOLD (MAX_SKB_FRAGS + 1) #define TX_THRESHOLD (MAX_SKB_FRAGS + 1)
struct ftgmac100_descs {
struct ftgmac100_rxdes rxdes[RX_QUEUE_ENTRIES];
struct ftgmac100_txdes txdes[TX_QUEUE_ENTRIES];
};
struct ftgmac100 { struct ftgmac100 {
/* Registers */ /* Registers */
struct resource *res; struct resource *res;
void __iomem *base; void __iomem *base;
struct ftgmac100_descs *descs;
dma_addr_t descs_dma_addr;
/* Rx ring */ /* Rx ring */
struct sk_buff *rx_skbs[RX_QUEUE_ENTRIES]; unsigned int rx_q_entries;
struct ftgmac100_rxdes *rxdes;
dma_addr_t rxdes_dma;
struct sk_buff **rx_skbs;
unsigned int rx_pointer; unsigned int rx_pointer;
u32 rxdes0_edorr_mask; u32 rxdes0_edorr_mask;
/* Tx ring */ /* Tx ring */
struct sk_buff *tx_skbs[TX_QUEUE_ENTRIES]; unsigned int tx_q_entries;
struct ftgmac100_txdes *txdes;
dma_addr_t txdes_dma;
struct sk_buff **tx_skbs;
unsigned int tx_clean_pointer; unsigned int tx_clean_pointer;
unsigned int tx_pointer; unsigned int tx_pointer;
u32 txdes0_edotr_mask; u32 txdes0_edotr_mask;
/* Used to signal the reset task of ring change request */
unsigned int new_rx_q_entries;
unsigned int new_tx_q_entries;
/* Scratch page to use when rx skb alloc fails */ /* Scratch page to use when rx skb alloc fails */
void *rx_scratch; void *rx_scratch;
dma_addr_t rx_scratch_dma; dma_addr_t rx_scratch_dma;
...@@ -92,31 +101,9 @@ struct ftgmac100 { ...@@ -92,31 +101,9 @@ struct ftgmac100 {
/* Misc */ /* Misc */
bool need_mac_restart; bool need_mac_restart;
bool is_aspeed;
}; };
static void ftgmac100_set_rx_ring_base(struct ftgmac100 *priv, dma_addr_t addr)
{
iowrite32(addr, priv->base + FTGMAC100_OFFSET_RXR_BADR);
}
static void ftgmac100_set_rx_buffer_size(struct ftgmac100 *priv,
unsigned int size)
{
size = FTGMAC100_RBSR_SIZE(size);
iowrite32(size, priv->base + FTGMAC100_OFFSET_RBSR);
}
static void ftgmac100_set_normal_prio_tx_ring_base(struct ftgmac100 *priv,
dma_addr_t addr)
{
iowrite32(addr, priv->base + FTGMAC100_OFFSET_NPTXR_BADR);
}
static void ftgmac100_txdma_normal_prio_start_polling(struct ftgmac100 *priv)
{
iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD);
}
static int ftgmac100_reset_mac(struct ftgmac100 *priv, u32 maccr) static int ftgmac100_reset_mac(struct ftgmac100 *priv, u32 maccr)
{ {
struct net_device *netdev = priv->netdev; struct net_device *netdev = priv->netdev;
...@@ -174,7 +161,7 @@ static int ftgmac100_reset_and_config_mac(struct ftgmac100 *priv) ...@@ -174,7 +161,7 @@ static int ftgmac100_reset_and_config_mac(struct ftgmac100 *priv)
return ftgmac100_reset_mac(priv, maccr); return ftgmac100_reset_mac(priv, maccr);
} }
static void ftgmac100_set_mac(struct ftgmac100 *priv, const unsigned char *mac) static void ftgmac100_write_mac_addr(struct ftgmac100 *priv, const u8 *mac)
{ {
unsigned int maddr = mac[0] << 8 | mac[1]; unsigned int maddr = mac[0] << 8 | mac[1];
unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
...@@ -183,7 +170,7 @@ static void ftgmac100_set_mac(struct ftgmac100 *priv, const unsigned char *mac) ...@@ -183,7 +170,7 @@ static void ftgmac100_set_mac(struct ftgmac100 *priv, const unsigned char *mac)
iowrite32(laddr, priv->base + FTGMAC100_OFFSET_MAC_LADR); iowrite32(laddr, priv->base + FTGMAC100_OFFSET_MAC_LADR);
} }
static void ftgmac100_setup_mac(struct ftgmac100 *priv) static void ftgmac100_initial_mac(struct ftgmac100 *priv)
{ {
u8 mac[ETH_ALEN]; u8 mac[ETH_ALEN];
unsigned int m; unsigned int m;
...@@ -227,26 +214,67 @@ static int ftgmac100_set_mac_addr(struct net_device *dev, void *p) ...@@ -227,26 +214,67 @@ static int ftgmac100_set_mac_addr(struct net_device *dev, void *p)
return ret; return ret;
eth_commit_mac_addr_change(dev, p); eth_commit_mac_addr_change(dev, p);
ftgmac100_set_mac(netdev_priv(dev), dev->dev_addr); ftgmac100_write_mac_addr(netdev_priv(dev), dev->dev_addr);
return 0; return 0;
} }
static void ftgmac100_init_hw(struct ftgmac100 *priv) static void ftgmac100_init_hw(struct ftgmac100 *priv)
{ {
/* setup ring buffer base registers */ u32 reg, rfifo_sz, tfifo_sz;
ftgmac100_set_rx_ring_base(priv,
priv->descs_dma_addr +
offsetof(struct ftgmac100_descs, rxdes));
ftgmac100_set_normal_prio_tx_ring_base(priv,
priv->descs_dma_addr +
offsetof(struct ftgmac100_descs, txdes));
ftgmac100_set_rx_buffer_size(priv, RX_BUF_SIZE); /* Clear stale interrupts */
reg = ioread32(priv->base + FTGMAC100_OFFSET_ISR);
iowrite32(reg, priv->base + FTGMAC100_OFFSET_ISR);
iowrite32(FTGMAC100_APTC_RXPOLL_CNT(1), priv->base + FTGMAC100_OFFSET_APTC); /* Setup RX ring buffer base */
iowrite32(priv->rxdes_dma, priv->base + FTGMAC100_OFFSET_RXR_BADR);
ftgmac100_set_mac(priv, priv->netdev->dev_addr); /* Setup TX ring buffer base */
iowrite32(priv->txdes_dma, priv->base + FTGMAC100_OFFSET_NPTXR_BADR);
/* Configure RX buffer size */
iowrite32(FTGMAC100_RBSR_SIZE(RX_BUF_SIZE),
priv->base + FTGMAC100_OFFSET_RBSR);
/* Set RX descriptor autopoll */
iowrite32(FTGMAC100_APTC_RXPOLL_CNT(1),
priv->base + FTGMAC100_OFFSET_APTC);
/* Write MAC address */
ftgmac100_write_mac_addr(priv, priv->netdev->dev_addr);
/* Configure descriptor sizes and increase burst sizes according
* to values in Aspeed SDK. The FIFO arbitration is enabled and
* the thresholds set based on the recommended values in the
* AST2400 specification.
*/
iowrite32(FTGMAC100_DBLAC_RXDES_SIZE(2) | /* 2*8 bytes RX descs */
FTGMAC100_DBLAC_TXDES_SIZE(2) | /* 2*8 bytes TX descs */
FTGMAC100_DBLAC_RXBURST_SIZE(3) | /* 512 bytes max RX bursts */
FTGMAC100_DBLAC_TXBURST_SIZE(3) | /* 512 bytes max TX bursts */
FTGMAC100_DBLAC_RX_THR_EN | /* Enable fifo threshold arb */
FTGMAC100_DBLAC_RXFIFO_HTHR(6) | /* 6/8 of FIFO high threshold */
FTGMAC100_DBLAC_RXFIFO_LTHR(2), /* 2/8 of FIFO low threshold */
priv->base + FTGMAC100_OFFSET_DBLAC);
/* Interrupt mitigation configured for 1 interrupt/packet. HW interrupt
* mitigation doesn't seem to provide any benefit with NAPI so leave
* it at that.
*/
iowrite32(FTGMAC100_ITC_RXINT_THR(1) |
FTGMAC100_ITC_TXINT_THR(1),
priv->base + FTGMAC100_OFFSET_ITC);
/* Configure FIFO sizes in the TPAFCR register */
reg = ioread32(priv->base + FTGMAC100_OFFSET_FEAR);
rfifo_sz = reg & 0x00000007;
tfifo_sz = (reg >> 3) & 0x00000007;
reg = ioread32(priv->base + FTGMAC100_OFFSET_TPAFCR);
reg &= ~0x3f000000;
reg |= (tfifo_sz << 27);
reg |= (rfifo_sz << 24);
iowrite32(reg, priv->base + FTGMAC100_OFFSET_TPAFCR);
} }
static void ftgmac100_start_hw(struct ftgmac100 *priv) static void ftgmac100_start_hw(struct ftgmac100 *priv)
...@@ -316,7 +344,7 @@ static int ftgmac100_alloc_rx_buf(struct ftgmac100 *priv, unsigned int entry, ...@@ -316,7 +344,7 @@ static int ftgmac100_alloc_rx_buf(struct ftgmac100 *priv, unsigned int entry,
dma_wmb(); dma_wmb();
/* Clean status (which resets own bit) */ /* Clean status (which resets own bit) */
if (entry == (RX_QUEUE_ENTRIES - 1)) if (entry == (priv->rx_q_entries - 1))
rxdes->rxdes0 = cpu_to_le32(priv->rxdes0_edorr_mask); rxdes->rxdes0 = cpu_to_le32(priv->rxdes0_edorr_mask);
else else
rxdes->rxdes0 = 0; rxdes->rxdes0 = 0;
...@@ -324,9 +352,10 @@ static int ftgmac100_alloc_rx_buf(struct ftgmac100 *priv, unsigned int entry, ...@@ -324,9 +352,10 @@ static int ftgmac100_alloc_rx_buf(struct ftgmac100 *priv, unsigned int entry,
return 0; return 0;
} }
static int ftgmac100_next_rx_pointer(int pointer) static unsigned int ftgmac100_next_rx_pointer(struct ftgmac100 *priv,
unsigned int pointer)
{ {
return (pointer + 1) & (RX_QUEUE_ENTRIES - 1); return (pointer + 1) & (priv->rx_q_entries - 1);
} }
static void ftgmac100_rx_packet_error(struct ftgmac100 *priv, u32 status) static void ftgmac100_rx_packet_error(struct ftgmac100 *priv, u32 status)
...@@ -356,7 +385,7 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed) ...@@ -356,7 +385,7 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
/* Grab next RX descriptor */ /* Grab next RX descriptor */
pointer = priv->rx_pointer; pointer = priv->rx_pointer;
rxdes = &priv->descs->rxdes[pointer]; rxdes = &priv->rxdes[pointer];
/* Grab descriptor status */ /* Grab descriptor status */
status = le32_to_cpu(rxdes->rxdes0); status = le32_to_cpu(rxdes->rxdes0);
...@@ -444,7 +473,7 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed) ...@@ -444,7 +473,7 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
/* Resplenish rx ring */ /* Resplenish rx ring */
ftgmac100_alloc_rx_buf(priv, pointer, rxdes, GFP_ATOMIC); ftgmac100_alloc_rx_buf(priv, pointer, rxdes, GFP_ATOMIC);
priv->rx_pointer = ftgmac100_next_rx_pointer(pointer); priv->rx_pointer = ftgmac100_next_rx_pointer(priv, pointer);
skb->protocol = eth_type_trans(skb, netdev); skb->protocol = eth_type_trans(skb, netdev);
...@@ -463,7 +492,7 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed) ...@@ -463,7 +492,7 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
drop: drop:
/* Clean rxdes0 (which resets own bit) */ /* Clean rxdes0 (which resets own bit) */
rxdes->rxdes0 = cpu_to_le32(status & priv->rxdes0_edorr_mask); rxdes->rxdes0 = cpu_to_le32(status & priv->rxdes0_edorr_mask);
priv->rx_pointer = ftgmac100_next_rx_pointer(pointer); priv->rx_pointer = ftgmac100_next_rx_pointer(priv, pointer);
netdev->stats.rx_dropped++; netdev->stats.rx_dropped++;
return true; return true;
} }
...@@ -471,15 +500,16 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed) ...@@ -471,15 +500,16 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
static u32 ftgmac100_base_tx_ctlstat(struct ftgmac100 *priv, static u32 ftgmac100_base_tx_ctlstat(struct ftgmac100 *priv,
unsigned int index) unsigned int index)
{ {
if (index == (TX_QUEUE_ENTRIES - 1)) if (index == (priv->tx_q_entries - 1))
return priv->txdes0_edotr_mask; return priv->txdes0_edotr_mask;
else else
return 0; return 0;
} }
static int ftgmac100_next_tx_pointer(int pointer) static unsigned int ftgmac100_next_tx_pointer(struct ftgmac100 *priv,
unsigned int pointer)
{ {
return (pointer + 1) & (TX_QUEUE_ENTRIES - 1); return (pointer + 1) & (priv->tx_q_entries - 1);
} }
static u32 ftgmac100_tx_buf_avail(struct ftgmac100 *priv) static u32 ftgmac100_tx_buf_avail(struct ftgmac100 *priv)
...@@ -491,7 +521,7 @@ static u32 ftgmac100_tx_buf_avail(struct ftgmac100 *priv) ...@@ -491,7 +521,7 @@ static u32 ftgmac100_tx_buf_avail(struct ftgmac100 *priv)
* test for ftgmac100_tx_buf_cleanable() below * test for ftgmac100_tx_buf_cleanable() below
*/ */
return (priv->tx_clean_pointer - priv->tx_pointer - 1) & return (priv->tx_clean_pointer - priv->tx_pointer - 1) &
(TX_QUEUE_ENTRIES - 1); (priv->tx_q_entries - 1);
} }
static bool ftgmac100_tx_buf_cleanable(struct ftgmac100 *priv) static bool ftgmac100_tx_buf_cleanable(struct ftgmac100 *priv)
...@@ -531,7 +561,7 @@ static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv) ...@@ -531,7 +561,7 @@ static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)
u32 ctl_stat; u32 ctl_stat;
pointer = priv->tx_clean_pointer; pointer = priv->tx_clean_pointer;
txdes = &priv->descs->txdes[pointer]; txdes = &priv->txdes[pointer];
ctl_stat = le32_to_cpu(txdes->txdes0); ctl_stat = le32_to_cpu(txdes->txdes0);
if (ctl_stat & FTGMAC100_TXDES0_TXDMA_OWN) if (ctl_stat & FTGMAC100_TXDES0_TXDMA_OWN)
...@@ -543,7 +573,7 @@ static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv) ...@@ -543,7 +573,7 @@ static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)
ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat); ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat);
txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask); txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask);
priv->tx_clean_pointer = ftgmac100_next_tx_pointer(pointer); priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv, pointer);
return true; return true;
} }
...@@ -572,6 +602,26 @@ static void ftgmac100_tx_complete(struct ftgmac100 *priv) ...@@ -572,6 +602,26 @@ static void ftgmac100_tx_complete(struct ftgmac100 *priv)
} }
} }
static bool ftgmac100_prep_tx_csum(struct sk_buff *skb, u32 *csum_vlan)
{
if (skb->protocol == cpu_to_be16(ETH_P_IP)) {
u8 ip_proto = ip_hdr(skb)->protocol;
*csum_vlan |= FTGMAC100_TXDES1_IP_CHKSUM;
switch(ip_proto) {
case IPPROTO_TCP:
*csum_vlan |= FTGMAC100_TXDES1_TCP_CHKSUM;
return true;
case IPPROTO_UDP:
*csum_vlan |= FTGMAC100_TXDES1_UDP_CHKSUM;
return true;
case IPPROTO_IP:
return true;
}
}
return skb_checksum_help(skb) == 0;
}
static int ftgmac100_hard_start_xmit(struct sk_buff *skb, static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
struct net_device *netdev) struct net_device *netdev)
{ {
...@@ -612,7 +662,7 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb, ...@@ -612,7 +662,7 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
/* Grab the next free tx descriptor */ /* Grab the next free tx descriptor */
pointer = priv->tx_pointer; pointer = priv->tx_pointer;
txdes = first = &priv->descs->txdes[pointer]; txdes = first = &priv->txdes[pointer];
/* Setup it up with the packet head. Don't write the head to the /* Setup it up with the packet head. Don't write the head to the
* ring just yet * ring just yet
...@@ -628,23 +678,13 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb, ...@@ -628,23 +678,13 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
/* Setup HW checksumming */ /* Setup HW checksumming */
csum_vlan = 0; csum_vlan = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL) { if (skb->ip_summed == CHECKSUM_PARTIAL &&
__be16 protocol = skb->protocol; !ftgmac100_prep_tx_csum(skb, &csum_vlan))
goto drop;
if (protocol == cpu_to_be16(ETH_P_IP)) {
u8 ip_proto = ip_hdr(skb)->protocol;
csum_vlan |= FTGMAC100_TXDES1_IP_CHKSUM;
if (ip_proto == IPPROTO_TCP)
csum_vlan |= FTGMAC100_TXDES1_TCP_CHKSUM;
else if (ip_proto == IPPROTO_UDP)
csum_vlan |= FTGMAC100_TXDES1_UDP_CHKSUM;
}
}
txdes->txdes1 = cpu_to_le32(csum_vlan); txdes->txdes1 = cpu_to_le32(csum_vlan);
/* Next descriptor */ /* Next descriptor */
pointer = ftgmac100_next_tx_pointer(pointer); pointer = ftgmac100_next_tx_pointer(priv, pointer);
/* Add the fragments */ /* Add the fragments */
for (i = 0; i < nfrags; i++) { for (i = 0; i < nfrags; i++) {
...@@ -660,7 +700,7 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb, ...@@ -660,7 +700,7 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
/* Setup descriptor */ /* Setup descriptor */
priv->tx_skbs[pointer] = skb; priv->tx_skbs[pointer] = skb;
txdes = &priv->descs->txdes[pointer]; txdes = &priv->txdes[pointer];
ctl_stat = ftgmac100_base_tx_ctlstat(priv, pointer); ctl_stat = ftgmac100_base_tx_ctlstat(priv, pointer);
ctl_stat |= FTGMAC100_TXDES0_TXDMA_OWN; ctl_stat |= FTGMAC100_TXDES0_TXDMA_OWN;
ctl_stat |= FTGMAC100_TXDES0_TXBUF_SIZE(len); ctl_stat |= FTGMAC100_TXDES0_TXBUF_SIZE(len);
...@@ -671,7 +711,7 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb, ...@@ -671,7 +711,7 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
txdes->txdes3 = cpu_to_le32(map); txdes->txdes3 = cpu_to_le32(map);
/* Next one */ /* Next one */
pointer = ftgmac100_next_tx_pointer(pointer); pointer = ftgmac100_next_tx_pointer(priv, pointer);
} }
/* Order the previous packet and descriptor udpates /* Order the previous packet and descriptor udpates
...@@ -695,7 +735,8 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb, ...@@ -695,7 +735,8 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
netif_wake_queue(netdev); netif_wake_queue(netdev);
} }
ftgmac100_txdma_normal_prio_start_polling(priv); /* Poke transmitter to read the updated TX descriptors */
iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD);
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -710,8 +751,8 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb, ...@@ -710,8 +751,8 @@ static int ftgmac100_hard_start_xmit(struct sk_buff *skb,
/* Then all fragments */ /* Then all fragments */
for (j = 0; j < i; j++) { for (j = 0; j < i; j++) {
pointer = ftgmac100_next_tx_pointer(pointer); pointer = ftgmac100_next_tx_pointer(priv, pointer);
txdes = &priv->descs->txdes[pointer]; txdes = &priv->txdes[pointer];
ctl_stat = le32_to_cpu(txdes->txdes0); ctl_stat = le32_to_cpu(txdes->txdes0);
ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat); ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat);
txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask); txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask);
...@@ -734,8 +775,8 @@ static void ftgmac100_free_buffers(struct ftgmac100 *priv) ...@@ -734,8 +775,8 @@ static void ftgmac100_free_buffers(struct ftgmac100 *priv)
int i; int i;
/* Free all RX buffers */ /* Free all RX buffers */
for (i = 0; i < RX_QUEUE_ENTRIES; i++) { for (i = 0; i < priv->rx_q_entries; i++) {
struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i]; struct ftgmac100_rxdes *rxdes = &priv->rxdes[i];
struct sk_buff *skb = priv->rx_skbs[i]; struct sk_buff *skb = priv->rx_skbs[i];
dma_addr_t map = le32_to_cpu(rxdes->rxdes3); dma_addr_t map = le32_to_cpu(rxdes->rxdes3);
...@@ -748,8 +789,8 @@ static void ftgmac100_free_buffers(struct ftgmac100 *priv) ...@@ -748,8 +789,8 @@ static void ftgmac100_free_buffers(struct ftgmac100 *priv)
} }
/* Free all TX buffers */ /* Free all TX buffers */
for (i = 0; i < TX_QUEUE_ENTRIES; i++) { for (i = 0; i < priv->tx_q_entries; i++) {
struct ftgmac100_txdes *txdes = &priv->descs->txdes[i]; struct ftgmac100_txdes *txdes = &priv->txdes[i];
struct sk_buff *skb = priv->tx_skbs[i]; struct sk_buff *skb = priv->tx_skbs[i];
if (!skb) if (!skb)
...@@ -761,10 +802,22 @@ static void ftgmac100_free_buffers(struct ftgmac100 *priv) ...@@ -761,10 +802,22 @@ static void ftgmac100_free_buffers(struct ftgmac100 *priv)
static void ftgmac100_free_rings(struct ftgmac100 *priv) static void ftgmac100_free_rings(struct ftgmac100 *priv)
{ {
/* Free skb arrays */
kfree(priv->rx_skbs);
kfree(priv->tx_skbs);
/* Free descriptors */ /* Free descriptors */
if (priv->descs) if (priv->rxdes)
dma_free_coherent(priv->dev, sizeof(struct ftgmac100_descs), dma_free_coherent(priv->dev, MAX_RX_QUEUE_ENTRIES *
priv->descs, priv->descs_dma_addr); sizeof(struct ftgmac100_rxdes),
priv->rxdes, priv->rxdes_dma);
priv->rxdes = NULL;
if (priv->txdes)
dma_free_coherent(priv->dev, MAX_TX_QUEUE_ENTRIES *
sizeof(struct ftgmac100_txdes),
priv->txdes, priv->txdes_dma);
priv->txdes = NULL;
/* Free scratch packet buffer */ /* Free scratch packet buffer */
if (priv->rx_scratch) if (priv->rx_scratch)
...@@ -774,11 +827,28 @@ static void ftgmac100_free_rings(struct ftgmac100 *priv) ...@@ -774,11 +827,28 @@ static void ftgmac100_free_rings(struct ftgmac100 *priv)
static int ftgmac100_alloc_rings(struct ftgmac100 *priv) static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
{ {
/* Allocate skb arrays */
priv->rx_skbs = kcalloc(MAX_RX_QUEUE_ENTRIES, sizeof(void *),
GFP_KERNEL);
if (!priv->rx_skbs)
return -ENOMEM;
priv->tx_skbs = kcalloc(MAX_TX_QUEUE_ENTRIES, sizeof(void *),
GFP_KERNEL);
if (!priv->tx_skbs)
return -ENOMEM;
/* Allocate descriptors */ /* Allocate descriptors */
priv->descs = dma_zalloc_coherent(priv->dev, priv->rxdes = dma_zalloc_coherent(priv->dev,
sizeof(struct ftgmac100_descs), MAX_RX_QUEUE_ENTRIES *
&priv->descs_dma_addr, GFP_KERNEL); sizeof(struct ftgmac100_rxdes),
if (!priv->descs) &priv->rxdes_dma, GFP_KERNEL);
if (!priv->rxdes)
return -ENOMEM;
priv->txdes = dma_zalloc_coherent(priv->dev,
MAX_TX_QUEUE_ENTRIES *
sizeof(struct ftgmac100_txdes),
&priv->txdes_dma, GFP_KERNEL);
if (!priv->txdes)
return -ENOMEM; return -ENOMEM;
/* Allocate scratch packet buffer */ /* Allocate scratch packet buffer */
...@@ -794,22 +864,32 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv) ...@@ -794,22 +864,32 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv)
static void ftgmac100_init_rings(struct ftgmac100 *priv) static void ftgmac100_init_rings(struct ftgmac100 *priv)
{ {
struct ftgmac100_rxdes *rxdes; struct ftgmac100_rxdes *rxdes = NULL;
struct ftgmac100_txdes *txdes; struct ftgmac100_txdes *txdes = NULL;
int i; int i;
/* Update entries counts */
priv->rx_q_entries = priv->new_rx_q_entries;
priv->tx_q_entries = priv->new_tx_q_entries;
if (WARN_ON(priv->rx_q_entries < MIN_RX_QUEUE_ENTRIES))
return;
/* Initialize RX ring */ /* Initialize RX ring */
for (i = 0; i < RX_QUEUE_ENTRIES; i++) { for (i = 0; i < priv->rx_q_entries; i++) {
rxdes = &priv->descs->rxdes[i]; rxdes = &priv->rxdes[i];
rxdes->rxdes0 = 0; rxdes->rxdes0 = 0;
rxdes->rxdes3 = cpu_to_le32(priv->rx_scratch_dma); rxdes->rxdes3 = cpu_to_le32(priv->rx_scratch_dma);
} }
/* Mark the end of the ring */ /* Mark the end of the ring */
rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask); rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask);
if (WARN_ON(priv->tx_q_entries < MIN_RX_QUEUE_ENTRIES))
return;
/* Initialize TX ring */ /* Initialize TX ring */
for (i = 0; i < TX_QUEUE_ENTRIES; i++) { for (i = 0; i < priv->tx_q_entries; i++) {
txdes = &priv->descs->txdes[i]; txdes = &priv->txdes[i];
txdes->txdes0 = 0; txdes->txdes0 = 0;
} }
txdes->txdes0 |= cpu_to_le32(priv->txdes0_edotr_mask); txdes->txdes0 |= cpu_to_le32(priv->txdes0_edotr_mask);
...@@ -819,8 +899,8 @@ static int ftgmac100_alloc_rx_buffers(struct ftgmac100 *priv) ...@@ -819,8 +899,8 @@ static int ftgmac100_alloc_rx_buffers(struct ftgmac100 *priv)
{ {
int i; int i;
for (i = 0; i < RX_QUEUE_ENTRIES; i++) { for (i = 0; i < priv->rx_q_entries; i++) {
struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[i]; struct ftgmac100_rxdes *rxdes = &priv->rxdes[i];
if (ftgmac100_alloc_rx_buf(priv, i, rxdes, GFP_KERNEL)) if (ftgmac100_alloc_rx_buf(priv, i, rxdes, GFP_KERNEL))
return -ENOMEM; return -ENOMEM;
...@@ -965,11 +1045,53 @@ static void ftgmac100_get_drvinfo(struct net_device *netdev, ...@@ -965,11 +1045,53 @@ static void ftgmac100_get_drvinfo(struct net_device *netdev,
strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info)); strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
} }
static int ftgmac100_nway_reset(struct net_device *ndev)
{
if (!ndev->phydev)
return -ENXIO;
return phy_start_aneg(ndev->phydev);
}
static void ftgmac100_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ering)
{
struct ftgmac100 *priv = netdev_priv(netdev);
memset(ering, 0, sizeof(*ering));
ering->rx_max_pending = MAX_RX_QUEUE_ENTRIES;
ering->tx_max_pending = MAX_TX_QUEUE_ENTRIES;
ering->rx_pending = priv->rx_q_entries;
ering->tx_pending = priv->tx_q_entries;
}
static int ftgmac100_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ering)
{
struct ftgmac100 *priv = netdev_priv(netdev);
if (ering->rx_pending > MAX_RX_QUEUE_ENTRIES ||
ering->tx_pending > MAX_TX_QUEUE_ENTRIES ||
ering->rx_pending < MIN_RX_QUEUE_ENTRIES ||
ering->tx_pending < MIN_TX_QUEUE_ENTRIES ||
!is_power_of_2(ering->rx_pending) ||
!is_power_of_2(ering->tx_pending))
return -EINVAL;
priv->new_rx_q_entries = ering->rx_pending;
priv->new_tx_q_entries = ering->tx_pending;
if (netif_running(netdev))
schedule_work(&priv->reset_task);
return 0;
}
static const struct ethtool_ops ftgmac100_ethtool_ops = { static const struct ethtool_ops ftgmac100_ethtool_ops = {
.get_drvinfo = ftgmac100_get_drvinfo, .get_drvinfo = ftgmac100_get_drvinfo,
.get_link = ethtool_op_get_link, .get_link = ethtool_op_get_link,
.get_link_ksettings = phy_ethtool_get_link_ksettings, .get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings,
.get_ringparam = ftgmac100_get_ringparam,
.set_ringparam = ftgmac100_set_ringparam,
}; };
static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id) static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id)
...@@ -1025,7 +1147,7 @@ static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id) ...@@ -1025,7 +1147,7 @@ static irqreturn_t ftgmac100_interrupt(int irq, void *dev_id)
static bool ftgmac100_check_rx(struct ftgmac100 *priv) static bool ftgmac100_check_rx(struct ftgmac100 *priv)
{ {
struct ftgmac100_rxdes *rxdes = &priv->descs->rxdes[priv->rx_pointer]; struct ftgmac100_rxdes *rxdes = &priv->rxdes[priv->rx_pointer];
/* Do we have a packet ? */ /* Do we have a packet ? */
return !!(rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY)); return !!(rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY));
...@@ -1312,8 +1434,7 @@ static int ftgmac100_setup_mdio(struct net_device *netdev) ...@@ -1312,8 +1434,7 @@ static int ftgmac100_setup_mdio(struct net_device *netdev)
if (!priv->mii_bus) if (!priv->mii_bus)
return -EIO; return -EIO;
if (of_machine_is_compatible("aspeed,ast2400") || if (priv->is_aspeed) {
of_machine_is_compatible("aspeed,ast2500")) {
/* This driver supports the old MDIO interface */ /* This driver supports the old MDIO interface */
reg = ioread32(priv->base + FTGMAC100_OFFSET_REVR); reg = ioread32(priv->base + FTGMAC100_OFFSET_REVR);
reg &= ~FTGMAC100_REVR_NEW_MDIO_INTERFACE; reg &= ~FTGMAC100_REVR_NEW_MDIO_INTERFACE;
...@@ -1378,6 +1499,7 @@ static int ftgmac100_probe(struct platform_device *pdev) ...@@ -1378,6 +1499,7 @@ static int ftgmac100_probe(struct platform_device *pdev)
int irq; int irq;
struct net_device *netdev; struct net_device *netdev;
struct ftgmac100 *priv; struct ftgmac100 *priv;
struct device_node *np;
int err = 0; int err = 0;
if (!pdev) if (!pdev)
...@@ -1431,19 +1553,20 @@ static int ftgmac100_probe(struct platform_device *pdev) ...@@ -1431,19 +1553,20 @@ static int ftgmac100_probe(struct platform_device *pdev)
netdev->irq = irq; netdev->irq = irq;
/* MAC address from chip or random one */ /* MAC address from chip or random one */
ftgmac100_setup_mac(priv); ftgmac100_initial_mac(priv);
if (of_machine_is_compatible("aspeed,ast2400") || np = pdev->dev.of_node;
of_machine_is_compatible("aspeed,ast2500")) { if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac") ||
of_device_is_compatible(np, "aspeed,ast2500-mac"))) {
priv->rxdes0_edorr_mask = BIT(30); priv->rxdes0_edorr_mask = BIT(30);
priv->txdes0_edotr_mask = BIT(30); priv->txdes0_edotr_mask = BIT(30);
priv->is_aspeed = true;
} else { } else {
priv->rxdes0_edorr_mask = BIT(15); priv->rxdes0_edorr_mask = BIT(15);
priv->txdes0_edotr_mask = BIT(15); priv->txdes0_edotr_mask = BIT(15);
} }
if (pdev->dev.of_node && if (np && of_get_property(np, "use-ncsi", NULL)) {
of_get_property(pdev->dev.of_node, "use-ncsi", NULL)) {
if (!IS_ENABLED(CONFIG_NET_NCSI)) { if (!IS_ENABLED(CONFIG_NET_NCSI)) {
dev_err(&pdev->dev, "NCSI stack not enabled\n"); dev_err(&pdev->dev, "NCSI stack not enabled\n");
goto err_ncsi_dev; goto err_ncsi_dev;
...@@ -1461,15 +1584,20 @@ static int ftgmac100_probe(struct platform_device *pdev) ...@@ -1461,15 +1584,20 @@ static int ftgmac100_probe(struct platform_device *pdev)
goto err_setup_mdio; goto err_setup_mdio;
} }
/* We have to disable on-chip IP checksum functionality /* Default ring sizes */
* when NCSI is enabled on the interface. It doesn't work priv->rx_q_entries = priv->new_rx_q_entries = DEF_RX_QUEUE_ENTRIES;
* in that case. priv->tx_q_entries = priv->new_tx_q_entries = DEF_TX_QUEUE_ENTRIES;
*/
netdev->features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | /* Base feature set */
netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
NETIF_F_GRO | NETIF_F_SG; NETIF_F_GRO | NETIF_F_SG;
if (priv->use_ncsi &&
of_get_property(pdev->dev.of_node, "no-hw-checksum", NULL)) /* AST2400 doesn't have working HW checksum generation */
netdev->features &= ~NETIF_F_IP_CSUM; if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac")))
netdev->hw_features &= ~NETIF_F_HW_CSUM;
if (np && of_get_property(np, "no-hw-checksum", NULL))
netdev->hw_features &= ~(NETIF_F_HW_CSUM | NETIF_F_RXCSUM);
netdev->features |= netdev->hw_features;
/* register network device */ /* register network device */
err = register_netdev(netdev); err = register_netdev(netdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment