Commit 1e3550e4 authored by David S. Miller's avatar David S. Miller

Merge branch 'macb-next'

Cyrille Pitchen says:

====================
net/macb: add HW features to macb driver

this series of patches adds new hardware features to macb driver. These
features can be enabled/disabled at runtime using ethtool. Depending on
hardware and design configuration, some are enabled by default whereas other
are disabled.

For instance, checksum offload features are enabled by default for gem designed
for packet buffer mode but disabled for fifo mode design or for old macb.

Besides, the scatter-gather feature is enabled and tested on macb but disabled
on sama5d3x gem. When testing this feature on sama5d3x gem, TX lockups occured
frequently.

Also, the RX checksum offload feature is enabled at GEM level only when both
IFF_PROMISC bit is clear in dev->flags and NETIF_F_RXCSUM bit is set in
dev->features.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ef492001 4b7b0e4f
...@@ -74,7 +74,7 @@ macb0_clk: macb0_clk { ...@@ -74,7 +74,7 @@ macb0_clk: macb0_clk {
}; };
macb0: ethernet@f0028000 { macb0: ethernet@f0028000 {
compatible = "cdns,pc302-gem", "cdns,gem"; compatible = "atmel,sama5d3-gem";
reg = <0xf0028000 0x100>; reg = <0xf0028000 0x100>;
interrupts = <34 IRQ_TYPE_LEVEL_HIGH 3>; interrupts = <34 IRQ_TYPE_LEVEL_HIGH 3>;
pinctrl-names = "default"; pinctrl-names = "default";
......
...@@ -52,6 +52,9 @@ ...@@ -52,6 +52,9 @@
| MACB_BIT(TXERR)) | MACB_BIT(TXERR))
#define MACB_TX_INT_FLAGS (MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP)) #define MACB_TX_INT_FLAGS (MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP))
#define MACB_MAX_TX_LEN ((unsigned int)((1 << MACB_TX_FRMLEN_SIZE) - 1))
#define GEM_MAX_TX_LEN ((unsigned int)((1 << GEM_TX_FRMLEN_SIZE) - 1))
/* /*
* Graceful stop timeouts in us. We should allow up to * Graceful stop timeouts in us. We should allow up to
* 1 frame time (10 Mbits/s, full-duplex, ignoring collisions) * 1 frame time (10 Mbits/s, full-duplex, ignoring collisions)
...@@ -264,7 +267,8 @@ static void macb_handle_link_change(struct net_device *dev) ...@@ -264,7 +267,8 @@ static void macb_handle_link_change(struct net_device *dev)
reg |= MACB_BIT(FD); reg |= MACB_BIT(FD);
if (phydev->speed == SPEED_100) if (phydev->speed == SPEED_100)
reg |= MACB_BIT(SPD); reg |= MACB_BIT(SPD);
if (phydev->speed == SPEED_1000) if (phydev->speed == SPEED_1000 &&
bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)
reg |= GEM_BIT(GBE); reg |= GEM_BIT(GBE);
macb_or_gem_writel(bp, NCFGR, reg); macb_or_gem_writel(bp, NCFGR, reg);
...@@ -337,7 +341,7 @@ static int macb_mii_probe(struct net_device *dev) ...@@ -337,7 +341,7 @@ static int macb_mii_probe(struct net_device *dev)
} }
/* mask with MAC supported features */ /* mask with MAC supported features */
if (macb_is_gem(bp)) if (macb_is_gem(bp) && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)
phydev->supported &= PHY_GBIT_FEATURES; phydev->supported &= PHY_GBIT_FEATURES;
else else
phydev->supported &= PHY_BASIC_FEATURES; phydev->supported &= PHY_BASIC_FEATURES;
...@@ -467,6 +471,24 @@ static int macb_halt_tx(struct macb *bp) ...@@ -467,6 +471,24 @@ static int macb_halt_tx(struct macb *bp)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb)
{
if (tx_skb->mapping) {
if (tx_skb->mapped_as_page)
dma_unmap_page(&bp->pdev->dev, tx_skb->mapping,
tx_skb->size, DMA_TO_DEVICE);
else
dma_unmap_single(&bp->pdev->dev, tx_skb->mapping,
tx_skb->size, DMA_TO_DEVICE);
tx_skb->mapping = 0;
}
if (tx_skb->skb) {
dev_kfree_skb_any(tx_skb->skb);
tx_skb->skb = NULL;
}
}
static void macb_tx_error_task(struct work_struct *work) static void macb_tx_error_task(struct work_struct *work)
{ {
struct macb *bp = container_of(work, struct macb, tx_error_task); struct macb *bp = container_of(work, struct macb, tx_error_task);
...@@ -504,10 +526,23 @@ static void macb_tx_error_task(struct work_struct *work) ...@@ -504,10 +526,23 @@ static void macb_tx_error_task(struct work_struct *work)
skb = tx_skb->skb; skb = tx_skb->skb;
if (ctrl & MACB_BIT(TX_USED)) { if (ctrl & MACB_BIT(TX_USED)) {
netdev_vdbg(bp->dev, "txerr skb %u (data %p) TX complete\n", /* skb is set for the last buffer of the frame */
macb_tx_ring_wrap(tail), skb->data); while (!skb) {
bp->stats.tx_packets++; macb_tx_unmap(bp, tx_skb);
bp->stats.tx_bytes += skb->len; tail++;
tx_skb = macb_tx_skb(bp, tail);
skb = tx_skb->skb;
}
/* ctrl still refers to the first buffer descriptor
* since it's the only one written back by the hardware
*/
if (!(ctrl & MACB_BIT(TX_BUF_EXHAUSTED))) {
netdev_vdbg(bp->dev, "txerr skb %u (data %p) TX complete\n",
macb_tx_ring_wrap(tail), skb->data);
bp->stats.tx_packets++;
bp->stats.tx_bytes += skb->len;
}
} else { } else {
/* /*
* "Buffers exhausted mid-frame" errors may only happen * "Buffers exhausted mid-frame" errors may only happen
...@@ -521,10 +556,7 @@ static void macb_tx_error_task(struct work_struct *work) ...@@ -521,10 +556,7 @@ static void macb_tx_error_task(struct work_struct *work)
desc->ctrl = ctrl | MACB_BIT(TX_USED); desc->ctrl = ctrl | MACB_BIT(TX_USED);
} }
dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, skb->len, macb_tx_unmap(bp, tx_skb);
DMA_TO_DEVICE);
tx_skb->skb = NULL;
dev_kfree_skb(skb);
} }
/* Make descriptor updates visible to hardware */ /* Make descriptor updates visible to hardware */
...@@ -572,20 +604,35 @@ static void macb_tx_interrupt(struct macb *bp) ...@@ -572,20 +604,35 @@ static void macb_tx_interrupt(struct macb *bp)
ctrl = desc->ctrl; ctrl = desc->ctrl;
/* TX_USED bit is only set by hardware on the very first buffer
* descriptor of the transmitted frame.
*/
if (!(ctrl & MACB_BIT(TX_USED))) if (!(ctrl & MACB_BIT(TX_USED)))
break; break;
tx_skb = macb_tx_skb(bp, tail); /* Process all buffers of the current transmitted frame */
skb = tx_skb->skb; for (;; tail++) {
tx_skb = macb_tx_skb(bp, tail);
skb = tx_skb->skb;
/* First, update TX stats if needed */
if (skb) {
netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
macb_tx_ring_wrap(tail), skb->data);
bp->stats.tx_packets++;
bp->stats.tx_bytes += skb->len;
}
netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n", /* Now we can safely release resources */
macb_tx_ring_wrap(tail), skb->data); macb_tx_unmap(bp, tx_skb);
dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, skb->len,
DMA_TO_DEVICE); /* skb is set only for the last buffer of the frame.
bp->stats.tx_packets++; * WARNING: at this point skb has been freed by
bp->stats.tx_bytes += skb->len; * macb_tx_unmap().
tx_skb->skb = NULL; */
dev_kfree_skb_irq(skb); if (skb)
break;
}
} }
bp->tx_tail = tail; bp->tx_tail = tail;
...@@ -718,6 +765,10 @@ static int gem_rx(struct macb *bp, int budget) ...@@ -718,6 +765,10 @@ static int gem_rx(struct macb *bp, int budget)
skb->protocol = eth_type_trans(skb, bp->dev); skb->protocol = eth_type_trans(skb, bp->dev);
skb_checksum_none_assert(skb); skb_checksum_none_assert(skb);
if (bp->dev->features & NETIF_F_RXCSUM &&
!(bp->dev->flags & IFF_PROMISC) &&
GEM_BFEXT(RX_CSUM, ctrl) & GEM_RX_CSUM_CHECKED_MASK)
skb->ip_summed = CHECKSUM_UNNECESSARY;
bp->stats.rx_packets++; bp->stats.rx_packets++;
bp->stats.rx_bytes += skb->len; bp->stats.rx_bytes += skb->len;
...@@ -1001,15 +1052,145 @@ static void macb_poll_controller(struct net_device *dev) ...@@ -1001,15 +1052,145 @@ static void macb_poll_controller(struct net_device *dev)
} }
#endif #endif
static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) static inline unsigned int macb_count_tx_descriptors(struct macb *bp,
unsigned int len)
{
return (len + bp->max_tx_length - 1) / bp->max_tx_length;
}
static unsigned int macb_tx_map(struct macb *bp,
struct sk_buff *skb)
{ {
struct macb *bp = netdev_priv(dev);
dma_addr_t mapping; dma_addr_t mapping;
unsigned int len, entry; unsigned int len, entry, i, tx_head = bp->tx_head;
struct macb_tx_skb *tx_skb = NULL;
struct macb_dma_desc *desc; struct macb_dma_desc *desc;
struct macb_tx_skb *tx_skb; unsigned int offset, size, count = 0;
unsigned int f, nr_frags = skb_shinfo(skb)->nr_frags;
unsigned int eof = 1;
u32 ctrl; u32 ctrl;
/* First, map non-paged data */
len = skb_headlen(skb);
offset = 0;
while (len) {
size = min(len, bp->max_tx_length);
entry = macb_tx_ring_wrap(tx_head);
tx_skb = &bp->tx_skb[entry];
mapping = dma_map_single(&bp->pdev->dev,
skb->data + offset,
size, DMA_TO_DEVICE);
if (dma_mapping_error(&bp->pdev->dev, mapping))
goto dma_error;
/* Save info to properly release resources */
tx_skb->skb = NULL;
tx_skb->mapping = mapping;
tx_skb->size = size;
tx_skb->mapped_as_page = false;
len -= size;
offset += size;
count++;
tx_head++;
}
/* Then, map paged data from fragments */
for (f = 0; f < nr_frags; f++) {
const skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
len = skb_frag_size(frag);
offset = 0;
while (len) {
size = min(len, bp->max_tx_length);
entry = macb_tx_ring_wrap(tx_head);
tx_skb = &bp->tx_skb[entry];
mapping = skb_frag_dma_map(&bp->pdev->dev, frag,
offset, size, DMA_TO_DEVICE);
if (dma_mapping_error(&bp->pdev->dev, mapping))
goto dma_error;
/* Save info to properly release resources */
tx_skb->skb = NULL;
tx_skb->mapping = mapping;
tx_skb->size = size;
tx_skb->mapped_as_page = true;
len -= size;
offset += size;
count++;
tx_head++;
}
}
/* Should never happen */
if (unlikely(tx_skb == NULL)) {
netdev_err(bp->dev, "BUG! empty skb!\n");
return 0;
}
/* This is the last buffer of the frame: save socket buffer */
tx_skb->skb = skb;
/* Update TX ring: update buffer descriptors in reverse order
* to avoid race condition
*/
/* Set 'TX_USED' bit in buffer descriptor at tx_head position
* to set the end of TX queue
*/
i = tx_head;
entry = macb_tx_ring_wrap(i);
ctrl = MACB_BIT(TX_USED);
desc = &bp->tx_ring[entry];
desc->ctrl = ctrl;
do {
i--;
entry = macb_tx_ring_wrap(i);
tx_skb = &bp->tx_skb[entry];
desc = &bp->tx_ring[entry];
ctrl = (u32)tx_skb->size;
if (eof) {
ctrl |= MACB_BIT(TX_LAST);
eof = 0;
}
if (unlikely(entry == (TX_RING_SIZE - 1)))
ctrl |= MACB_BIT(TX_WRAP);
/* Set TX buffer descriptor */
desc->addr = tx_skb->mapping;
/* desc->addr must be visible to hardware before clearing
* 'TX_USED' bit in desc->ctrl.
*/
wmb();
desc->ctrl = ctrl;
} while (i != bp->tx_head);
bp->tx_head = tx_head;
return count;
dma_error:
netdev_err(bp->dev, "TX DMA map failed\n");
for (i = bp->tx_head; i != tx_head; i++) {
tx_skb = macb_tx_skb(bp, i);
macb_tx_unmap(bp, tx_skb);
}
return 0;
}
static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct macb *bp = netdev_priv(dev);
unsigned long flags; unsigned long flags;
unsigned int count, nr_frags, frag_size, f;
#if defined(DEBUG) && defined(VERBOSE_DEBUG) #if defined(DEBUG) && defined(VERBOSE_DEBUG)
netdev_vdbg(bp->dev, netdev_vdbg(bp->dev,
...@@ -1020,44 +1201,34 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1020,44 +1201,34 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->data, 16, true); skb->data, 16, true);
#endif #endif
len = skb->len; /* Count how many TX buffer descriptors are needed to send this
* socket buffer: skb fragments of jumbo frames may need to be
* splitted into many buffer descriptors.
*/
count = macb_count_tx_descriptors(bp, skb_headlen(skb));
nr_frags = skb_shinfo(skb)->nr_frags;
for (f = 0; f < nr_frags; f++) {
frag_size = skb_frag_size(&skb_shinfo(skb)->frags[f]);
count += macb_count_tx_descriptors(bp, frag_size);
}
spin_lock_irqsave(&bp->lock, flags); spin_lock_irqsave(&bp->lock, flags);
/* This is a hard error, log it. */ /* This is a hard error, log it. */
if (CIRC_SPACE(bp->tx_head, bp->tx_tail, TX_RING_SIZE) < 1) { if (CIRC_SPACE(bp->tx_head, bp->tx_tail, TX_RING_SIZE) < count) {
netif_stop_queue(dev); netif_stop_queue(dev);
spin_unlock_irqrestore(&bp->lock, flags); spin_unlock_irqrestore(&bp->lock, flags);
netdev_err(bp->dev, "BUG! Tx Ring full when queue awake!\n");
netdev_dbg(bp->dev, "tx_head = %u, tx_tail = %u\n", netdev_dbg(bp->dev, "tx_head = %u, tx_tail = %u\n",
bp->tx_head, bp->tx_tail); bp->tx_head, bp->tx_tail);
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
entry = macb_tx_ring_wrap(bp->tx_head); /* Map socket buffer for DMA transfer */
netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry); if (!macb_tx_map(bp, skb)) {
mapping = dma_map_single(&bp->pdev->dev, skb->data,
len, DMA_TO_DEVICE);
if (dma_mapping_error(&bp->pdev->dev, mapping)) {
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
goto unlock; goto unlock;
} }
bp->tx_head++;
tx_skb = &bp->tx_skb[entry];
tx_skb->skb = skb;
tx_skb->mapping = mapping;
netdev_vdbg(bp->dev, "Mapped skb data %p to DMA addr %08lx\n",
skb->data, (unsigned long)mapping);
ctrl = MACB_BF(TX_FRMLEN, len);
ctrl |= MACB_BIT(TX_LAST);
if (entry == (TX_RING_SIZE - 1))
ctrl |= MACB_BIT(TX_WRAP);
desc = &bp->tx_ring[entry];
desc->addr = mapping;
desc->ctrl = ctrl;
/* Make newly initialized descriptor visible to hardware */ /* Make newly initialized descriptor visible to hardware */
wmb(); wmb();
...@@ -1342,7 +1513,7 @@ static u32 macb_dbw(struct macb *bp) ...@@ -1342,7 +1513,7 @@ static u32 macb_dbw(struct macb *bp)
/* /*
* Configure the receive DMA engine * Configure the receive DMA engine
* - use the correct receive buffer size * - use the correct receive buffer size
* - set the possibility to use INCR16 bursts * - set best burst length for DMA operations
* (if not supported by FIFO, it will fallback to default) * (if not supported by FIFO, it will fallback to default)
* - set both rx/tx packet buffers to full memory size * - set both rx/tx packet buffers to full memory size
* These are configurable parameters for GEM. * These are configurable parameters for GEM.
...@@ -1354,24 +1525,20 @@ static void macb_configure_dma(struct macb *bp) ...@@ -1354,24 +1525,20 @@ static void macb_configure_dma(struct macb *bp)
if (macb_is_gem(bp)) { if (macb_is_gem(bp)) {
dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L); dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L);
dmacfg |= GEM_BF(RXBS, bp->rx_buffer_size / RX_BUFFER_MULTIPLE); dmacfg |= GEM_BF(RXBS, bp->rx_buffer_size / RX_BUFFER_MULTIPLE);
dmacfg |= GEM_BF(FBLDO, 16); if (bp->dma_burst_length)
dmacfg = GEM_BFINS(FBLDO, bp->dma_burst_length, dmacfg);
dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L); dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
dmacfg &= ~GEM_BIT(ENDIA); dmacfg &= ~GEM_BIT(ENDIA);
if (bp->dev->features & NETIF_F_HW_CSUM)
dmacfg |= GEM_BIT(TXCOEN);
else
dmacfg &= ~GEM_BIT(TXCOEN);
netdev_dbg(bp->dev, "Cadence configure DMA with 0x%08x\n",
dmacfg);
gem_writel(bp, DMACFG, dmacfg); gem_writel(bp, DMACFG, dmacfg);
} }
} }
/*
* Configure peripheral capacities according to integration options used
*/
static void macb_configure_caps(struct macb *bp)
{
if (macb_is_gem(bp)) {
if (GEM_BFEXT(IRQCOR, gem_readl(bp, DCFG1)) == 0)
bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE;
}
}
static void macb_init_hw(struct macb *bp) static void macb_init_hw(struct macb *bp)
{ {
u32 config; u32 config;
...@@ -1386,6 +1553,8 @@ static void macb_init_hw(struct macb *bp) ...@@ -1386,6 +1553,8 @@ static void macb_init_hw(struct macb *bp)
config |= MACB_BIT(BIG); /* Receive oversized frames */ config |= MACB_BIT(BIG); /* Receive oversized frames */
if (bp->dev->flags & IFF_PROMISC) if (bp->dev->flags & IFF_PROMISC)
config |= MACB_BIT(CAF); /* Copy All Frames */ config |= MACB_BIT(CAF); /* Copy All Frames */
else if (macb_is_gem(bp) && bp->dev->features & NETIF_F_RXCSUM)
config |= GEM_BIT(RXCOEN);
if (!(bp->dev->flags & IFF_BROADCAST)) if (!(bp->dev->flags & IFF_BROADCAST))
config |= MACB_BIT(NBC); /* No BroadCast */ config |= MACB_BIT(NBC); /* No BroadCast */
config |= macb_dbw(bp); config |= macb_dbw(bp);
...@@ -1394,7 +1563,6 @@ static void macb_init_hw(struct macb *bp) ...@@ -1394,7 +1563,6 @@ static void macb_init_hw(struct macb *bp)
bp->duplex = DUPLEX_HALF; bp->duplex = DUPLEX_HALF;
macb_configure_dma(bp); macb_configure_dma(bp);
macb_configure_caps(bp);
/* Initialize TX and RX buffers */ /* Initialize TX and RX buffers */
macb_writel(bp, RBQP, bp->rx_ring_dma); macb_writel(bp, RBQP, bp->rx_ring_dma);
...@@ -1500,13 +1668,22 @@ void macb_set_rx_mode(struct net_device *dev) ...@@ -1500,13 +1668,22 @@ void macb_set_rx_mode(struct net_device *dev)
cfg = macb_readl(bp, NCFGR); cfg = macb_readl(bp, NCFGR);
if (dev->flags & IFF_PROMISC) if (dev->flags & IFF_PROMISC) {
/* Enable promiscuous mode */ /* Enable promiscuous mode */
cfg |= MACB_BIT(CAF); cfg |= MACB_BIT(CAF);
else if (dev->flags & (~IFF_PROMISC))
/* Disable promiscuous mode */ /* Disable RX checksum offload */
if (macb_is_gem(bp))
cfg &= ~GEM_BIT(RXCOEN);
} else {
/* Disable promiscuous mode */
cfg &= ~MACB_BIT(CAF); cfg &= ~MACB_BIT(CAF);
/* Enable RX checksum offload only if requested */
if (macb_is_gem(bp) && dev->features & NETIF_F_RXCSUM)
cfg |= GEM_BIT(RXCOEN);
}
if (dev->flags & IFF_ALLMULTI) { if (dev->flags & IFF_ALLMULTI) {
/* Enable all multicast mode */ /* Enable all multicast mode */
macb_or_gem_writel(bp, HRB, -1); macb_or_gem_writel(bp, HRB, -1);
...@@ -1767,6 +1944,40 @@ int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -1767,6 +1944,40 @@ int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
} }
EXPORT_SYMBOL_GPL(macb_ioctl); EXPORT_SYMBOL_GPL(macb_ioctl);
static int macb_set_features(struct net_device *netdev,
netdev_features_t features)
{
struct macb *bp = netdev_priv(netdev);
netdev_features_t changed = features ^ netdev->features;
/* TX checksum offload */
if ((changed & NETIF_F_HW_CSUM) && macb_is_gem(bp)) {
u32 dmacfg;
dmacfg = gem_readl(bp, DMACFG);
if (features & NETIF_F_HW_CSUM)
dmacfg |= GEM_BIT(TXCOEN);
else
dmacfg &= ~GEM_BIT(TXCOEN);
gem_writel(bp, DMACFG, dmacfg);
}
/* RX checksum offload */
if ((changed & NETIF_F_RXCSUM) && macb_is_gem(bp)) {
u32 netcfg;
netcfg = gem_readl(bp, NCFGR);
if (features & NETIF_F_RXCSUM &&
!(netdev->flags & IFF_PROMISC))
netcfg |= GEM_BIT(RXCOEN);
else
netcfg &= ~GEM_BIT(RXCOEN);
gem_writel(bp, NCFGR, netcfg);
}
return 0;
}
static const struct net_device_ops macb_netdev_ops = { static const struct net_device_ops macb_netdev_ops = {
.ndo_open = macb_open, .ndo_open = macb_open,
.ndo_stop = macb_close, .ndo_stop = macb_close,
...@@ -1780,20 +1991,77 @@ static const struct net_device_ops macb_netdev_ops = { ...@@ -1780,20 +1991,77 @@ static const struct net_device_ops macb_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = macb_poll_controller, .ndo_poll_controller = macb_poll_controller,
#endif #endif
.ndo_set_features = macb_set_features,
}; };
#if defined(CONFIG_OF) #if defined(CONFIG_OF)
static struct macb_config pc302gem_config = {
.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
.dma_burst_length = 16,
};
static struct macb_config sama5d3_config = {
.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE,
.dma_burst_length = 16,
};
static struct macb_config sama5d4_config = {
.caps = 0,
.dma_burst_length = 4,
};
static const struct of_device_id macb_dt_ids[] = { static const struct of_device_id macb_dt_ids[] = {
{ .compatible = "cdns,at32ap7000-macb" }, { .compatible = "cdns,at32ap7000-macb" },
{ .compatible = "cdns,at91sam9260-macb" }, { .compatible = "cdns,at91sam9260-macb" },
{ .compatible = "cdns,macb" }, { .compatible = "cdns,macb" },
{ .compatible = "cdns,pc302-gem" }, { .compatible = "cdns,pc302-gem", .data = &pc302gem_config },
{ .compatible = "cdns,gem" }, { .compatible = "cdns,gem", .data = &pc302gem_config },
{ .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config },
{ .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, macb_dt_ids); MODULE_DEVICE_TABLE(of, macb_dt_ids);
#endif #endif
/*
* Configure peripheral capacities according to device tree
* and integration options used
*/
static void macb_configure_caps(struct macb *bp)
{
u32 dcfg;
const struct of_device_id *match;
const struct macb_config *config;
if (bp->pdev->dev.of_node) {
match = of_match_node(macb_dt_ids, bp->pdev->dev.of_node);
if (match && match->data) {
config = (const struct macb_config *)match->data;
bp->caps = config->caps;
/*
* As we have access to the matching node, configure
* DMA burst length as well
*/
bp->dma_burst_length = config->dma_burst_length;
}
}
if (MACB_BFEXT(IDNUM, macb_readl(bp, MID)) == 0x2)
bp->caps |= MACB_CAPS_MACB_IS_GEM;
if (macb_is_gem(bp)) {
dcfg = gem_readl(bp, DCFG1);
if (GEM_BFEXT(IRQCOR, dcfg) == 0)
bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE;
dcfg = gem_readl(bp, DCFG2);
if ((dcfg & (GEM_BIT(RX_PKT_BUFF) | GEM_BIT(TX_PKT_BUFF))) == 0)
bp->caps |= MACB_CAPS_FIFO_MODE;
}
netdev_dbg(bp->dev, "Cadence caps 0x%08x\n", bp->caps);
}
static int __init macb_probe(struct platform_device *pdev) static int __init macb_probe(struct platform_device *pdev)
{ {
struct macb_platform_data *pdata; struct macb_platform_data *pdata;
...@@ -1828,9 +2096,6 @@ static int __init macb_probe(struct platform_device *pdev) ...@@ -1828,9 +2096,6 @@ static int __init macb_probe(struct platform_device *pdev)
SET_NETDEV_DEV(dev, &pdev->dev); SET_NETDEV_DEV(dev, &pdev->dev);
/* TODO: Actually, we have some interesting features... */
dev->features |= 0;
bp = netdev_priv(dev); bp = netdev_priv(dev);
bp->pdev = pdev; bp->pdev = pdev;
bp->dev = dev; bp->dev = dev;
...@@ -1897,19 +2162,33 @@ static int __init macb_probe(struct platform_device *pdev) ...@@ -1897,19 +2162,33 @@ static int __init macb_probe(struct platform_device *pdev)
dev->base_addr = regs->start; dev->base_addr = regs->start;
/* setup capacities */
macb_configure_caps(bp);
/* setup appropriated routines according to adapter type */ /* setup appropriated routines according to adapter type */
if (macb_is_gem(bp)) { if (macb_is_gem(bp)) {
bp->max_tx_length = GEM_MAX_TX_LEN;
bp->macbgem_ops.mog_alloc_rx_buffers = gem_alloc_rx_buffers; bp->macbgem_ops.mog_alloc_rx_buffers = gem_alloc_rx_buffers;
bp->macbgem_ops.mog_free_rx_buffers = gem_free_rx_buffers; bp->macbgem_ops.mog_free_rx_buffers = gem_free_rx_buffers;
bp->macbgem_ops.mog_init_rings = gem_init_rings; bp->macbgem_ops.mog_init_rings = gem_init_rings;
bp->macbgem_ops.mog_rx = gem_rx; bp->macbgem_ops.mog_rx = gem_rx;
} else { } else {
bp->max_tx_length = MACB_MAX_TX_LEN;
bp->macbgem_ops.mog_alloc_rx_buffers = macb_alloc_rx_buffers; bp->macbgem_ops.mog_alloc_rx_buffers = macb_alloc_rx_buffers;
bp->macbgem_ops.mog_free_rx_buffers = macb_free_rx_buffers; bp->macbgem_ops.mog_free_rx_buffers = macb_free_rx_buffers;
bp->macbgem_ops.mog_init_rings = macb_init_rings; bp->macbgem_ops.mog_init_rings = macb_init_rings;
bp->macbgem_ops.mog_rx = macb_rx; bp->macbgem_ops.mog_rx = macb_rx;
} }
/* Set features */
dev->hw_features = NETIF_F_SG;
/* Checksum offload is only available on gem with packet buffer */
if (macb_is_gem(bp) && !(bp->caps & MACB_CAPS_FIFO_MODE))
dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
if (bp->caps & MACB_CAPS_SG_DISABLED)
dev->hw_features &= ~NETIF_F_SG;
dev->features = dev->hw_features;
/* Set MII management clock divider */ /* Set MII management clock divider */
config = macb_mdc_clk_div(bp); config = macb_mdc_clk_div(bp);
config |= macb_dbw(bp); config |= macb_dbw(bp);
......
...@@ -164,6 +164,8 @@ ...@@ -164,6 +164,8 @@
#define GEM_CLK_SIZE 3 #define GEM_CLK_SIZE 3
#define GEM_DBW_OFFSET 21 #define GEM_DBW_OFFSET 21
#define GEM_DBW_SIZE 2 #define GEM_DBW_SIZE 2
#define GEM_RXCOEN_OFFSET 24
#define GEM_RXCOEN_SIZE 1
/* Constants for data bus width. */ /* Constants for data bus width. */
#define GEM_DBW32 0 #define GEM_DBW32 0
...@@ -305,6 +307,12 @@ ...@@ -305,6 +307,12 @@
#define GEM_DBWDEF_OFFSET 25 #define GEM_DBWDEF_OFFSET 25
#define GEM_DBWDEF_SIZE 3 #define GEM_DBWDEF_SIZE 3
/* Bitfields in DCFG2. */
#define GEM_RX_PKT_BUFF_OFFSET 20
#define GEM_RX_PKT_BUFF_SIZE 1
#define GEM_TX_PKT_BUFF_OFFSET 21
#define GEM_TX_PKT_BUFF_SIZE 1
/* Constants for CLK */ /* Constants for CLK */
#define MACB_CLK_DIV8 0 #define MACB_CLK_DIV8 0
#define MACB_CLK_DIV16 1 #define MACB_CLK_DIV16 1
...@@ -326,7 +334,11 @@ ...@@ -326,7 +334,11 @@
#define MACB_MAN_CODE 2 #define MACB_MAN_CODE 2
/* Capability mask bits */ /* Capability mask bits */
#define MACB_CAPS_ISR_CLEAR_ON_WRITE 0x1 #define MACB_CAPS_ISR_CLEAR_ON_WRITE 0x00000001
#define MACB_CAPS_FIFO_MODE 0x10000000
#define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000
#define MACB_CAPS_SG_DISABLED 0x40000000
#define MACB_CAPS_MACB_IS_GEM 0x80000000
/* Bit manipulation macros */ /* Bit manipulation macros */
#define MACB_BIT(name) \ #define MACB_BIT(name) \
...@@ -442,6 +454,14 @@ struct macb_dma_desc { ...@@ -442,6 +454,14 @@ struct macb_dma_desc {
#define MACB_RX_BROADCAST_OFFSET 31 #define MACB_RX_BROADCAST_OFFSET 31
#define MACB_RX_BROADCAST_SIZE 1 #define MACB_RX_BROADCAST_SIZE 1
/* RX checksum offload disabled: bit 24 clear in NCFGR */
#define GEM_RX_TYPEID_MATCH_OFFSET 22
#define GEM_RX_TYPEID_MATCH_SIZE 2
/* RX checksum offload enabled: bit 24 set in NCFGR */
#define GEM_RX_CSUM_OFFSET 22
#define GEM_RX_CSUM_SIZE 2
#define MACB_TX_FRMLEN_OFFSET 0 #define MACB_TX_FRMLEN_OFFSET 0
#define MACB_TX_FRMLEN_SIZE 11 #define MACB_TX_FRMLEN_SIZE 11
#define MACB_TX_LAST_OFFSET 15 #define MACB_TX_LAST_OFFSET 15
...@@ -459,14 +479,32 @@ struct macb_dma_desc { ...@@ -459,14 +479,32 @@ struct macb_dma_desc {
#define MACB_TX_USED_OFFSET 31 #define MACB_TX_USED_OFFSET 31
#define MACB_TX_USED_SIZE 1 #define MACB_TX_USED_SIZE 1
#define GEM_TX_FRMLEN_OFFSET 0
#define GEM_TX_FRMLEN_SIZE 14
/* Buffer descriptor constants */
#define GEM_RX_CSUM_NONE 0
#define GEM_RX_CSUM_IP_ONLY 1
#define GEM_RX_CSUM_IP_TCP 2
#define GEM_RX_CSUM_IP_UDP 3
/* limit RX checksum offload to TCP and UDP packets */
#define GEM_RX_CSUM_CHECKED_MASK 2
/** /**
* struct macb_tx_skb - data about an skb which is being transmitted * struct macb_tx_skb - data about an skb which is being transmitted
* @skb: skb currently being transmitted * @skb: skb currently being transmitted, only set for the last buffer
* @mapping: DMA address of the skb's data buffer * of the frame
* @mapping: DMA address of the skb's fragment buffer
* @size: size of the DMA mapped buffer
* @mapped_as_page: true when buffer was mapped with skb_frag_dma_map(),
* false when buffer was mapped with dma_map_single()
*/ */
struct macb_tx_skb { struct macb_tx_skb {
struct sk_buff *skb; struct sk_buff *skb;
dma_addr_t mapping; dma_addr_t mapping;
size_t size;
bool mapped_as_page;
}; };
/* /*
...@@ -554,6 +592,11 @@ struct macb_or_gem_ops { ...@@ -554,6 +592,11 @@ struct macb_or_gem_ops {
int (*mog_rx)(struct macb *bp, int budget); int (*mog_rx)(struct macb *bp, int budget);
}; };
struct macb_config {
u32 caps;
unsigned int dma_burst_length;
};
struct macb { struct macb {
void __iomem *regs; void __iomem *regs;
...@@ -595,6 +638,7 @@ struct macb { ...@@ -595,6 +638,7 @@ struct macb {
unsigned int duplex; unsigned int duplex;
u32 caps; u32 caps;
unsigned int dma_burst_length;
phy_interface_t phy_interface; phy_interface_t phy_interface;
...@@ -602,6 +646,7 @@ struct macb { ...@@ -602,6 +646,7 @@ struct macb {
struct sk_buff *skb; /* holds skb until xmit interrupt completes */ struct sk_buff *skb; /* holds skb until xmit interrupt completes */
dma_addr_t skb_physaddr; /* phys addr from pci_map_single */ dma_addr_t skb_physaddr; /* phys addr from pci_map_single */
int skb_length; /* saved skb length for pci_unmap_single */ int skb_length; /* saved skb length for pci_unmap_single */
unsigned int max_tx_length;
}; };
extern const struct ethtool_ops macb_ethtool_ops; extern const struct ethtool_ops macb_ethtool_ops;
...@@ -615,7 +660,7 @@ void macb_get_hwaddr(struct macb *bp); ...@@ -615,7 +660,7 @@ void macb_get_hwaddr(struct macb *bp);
static inline bool macb_is_gem(struct macb *bp) static inline bool macb_is_gem(struct macb *bp)
{ {
return MACB_BFEXT(IDNUM, macb_readl(bp, MID)) == 0x2; return !!(bp->caps & MACB_CAPS_MACB_IS_GEM);
} }
#endif /* _MACB_H */ #endif /* _MACB_H */
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