Commit 850d2fed authored by Thomas Bogendoerfer's avatar Thomas Bogendoerfer Committed by David S. Miller

net: sgi: ioc3-eth: refactor rx buffer allocation

Move common code for rx buffer setup into ioc3_alloc_skb and deal
with allocation failures. Also clean up allocation size calculation.
Signed-off-by: default avatarThomas Bogendoerfer <tbogendoerfer@suse.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 19a957b6
...@@ -11,11 +11,8 @@ ...@@ -11,11 +11,8 @@
* *
* To do: * To do:
* *
* o Handle allocation failures in ioc3_alloc_skb() more gracefully.
* o Handle allocation failures in ioc3_init_rings().
* o Use prefetching for large packets. What is a good lower limit for * o Use prefetching for large packets. What is a good lower limit for
* prefetching? * prefetching?
* o We're probably allocating a bit too much memory.
* o Use hardware checksums. * o Use hardware checksums.
* o Convert to using a IOC3 meta driver. * o Convert to using a IOC3 meta driver.
* o Which PHYs might possibly be attached to the IOC3 in real live, * o Which PHYs might possibly be attached to the IOC3 in real live,
...@@ -72,6 +69,13 @@ ...@@ -72,6 +69,13 @@
#define TX_RING_ENTRIES 128 #define TX_RING_ENTRIES 128
#define TX_RING_MASK (TX_RING_ENTRIES - 1) #define TX_RING_MASK (TX_RING_ENTRIES - 1)
/* IOC3 does dma transfers in 128 byte blocks */
#define IOC3_DMA_XFER_LEN 128UL
/* Every RX buffer starts with 8 byte descriptor data */
#define RX_OFFSET (sizeof(struct ioc3_erxbuf) + NET_IP_ALIGN)
#define RX_BUF_SIZE (13 * IOC3_DMA_XFER_LEN)
#define ETCSR_FD ((17 << ETCSR_IPGR2_SHIFT) | (11 << ETCSR_IPGR1_SHIFT) | 21) #define ETCSR_FD ((17 << ETCSR_IPGR2_SHIFT) | (11 << ETCSR_IPGR1_SHIFT) | 21)
#define ETCSR_HD ((21 << ETCSR_IPGR2_SHIFT) | (21 << ETCSR_IPGR1_SHIFT) | 21) #define ETCSR_HD ((21 << ETCSR_IPGR2_SHIFT) | (21 << ETCSR_IPGR1_SHIFT) | 21)
...@@ -108,36 +112,38 @@ static inline unsigned int ioc3_hash(const unsigned char *addr); ...@@ -108,36 +112,38 @@ static inline unsigned int ioc3_hash(const unsigned char *addr);
static void ioc3_start(struct ioc3_private *ip); static void ioc3_start(struct ioc3_private *ip);
static inline void ioc3_stop(struct ioc3_private *ip); static inline void ioc3_stop(struct ioc3_private *ip);
static void ioc3_init(struct net_device *dev); static void ioc3_init(struct net_device *dev);
static void ioc3_alloc_rx_bufs(struct net_device *dev); static int ioc3_alloc_rx_bufs(struct net_device *dev);
static void ioc3_free_rx_bufs(struct ioc3_private *ip); static void ioc3_free_rx_bufs(struct ioc3_private *ip);
static inline void ioc3_clean_tx_ring(struct ioc3_private *ip); static inline void ioc3_clean_tx_ring(struct ioc3_private *ip);
static const char ioc3_str[] = "IOC3 Ethernet"; static const char ioc3_str[] = "IOC3 Ethernet";
static const struct ethtool_ops ioc3_ethtool_ops; static const struct ethtool_ops ioc3_ethtool_ops;
/* We use this to acquire receive skb's that we can DMA directly into. */
#define IOC3_CACHELINE 128UL
static inline unsigned long aligned_rx_skb_addr(unsigned long addr) static inline unsigned long aligned_rx_skb_addr(unsigned long addr)
{ {
return (~addr + 1) & (IOC3_CACHELINE - 1UL); return (~addr + 1) & (IOC3_DMA_XFER_LEN - 1UL);
} }
static inline struct sk_buff *ioc3_alloc_skb(unsigned long length, static inline int ioc3_alloc_skb(struct sk_buff **skb, struct ioc3_erxbuf **rxb)
unsigned int gfp_mask)
{ {
struct sk_buff *skb; struct sk_buff *new_skb;
int offset;
skb = alloc_skb(length + IOC3_CACHELINE - 1, gfp_mask); new_skb = alloc_skb(RX_BUF_SIZE + IOC3_DMA_XFER_LEN - 1, GFP_ATOMIC);
if (likely(skb)) { if (!new_skb)
int offset = aligned_rx_skb_addr((unsigned long)skb->data); return -ENOMEM;
if (offset) /* ensure buffer is aligned to IOC3_DMA_XFER_LEN */
skb_reserve(skb, offset); offset = aligned_rx_skb_addr((unsigned long)new_skb->data);
} if (offset)
skb_reserve(new_skb, offset);
*rxb = (struct ioc3_erxbuf *)new_skb->data;
skb_reserve(new_skb, RX_OFFSET);
*skb = new_skb;
return skb; return 0;
} }
static inline unsigned long ioc3_map(void *ptr, unsigned long vdev) static inline unsigned long ioc3_map(void *ptr, unsigned long vdev)
...@@ -151,13 +157,6 @@ static inline unsigned long ioc3_map(void *ptr, unsigned long vdev) ...@@ -151,13 +157,6 @@ static inline unsigned long ioc3_map(void *ptr, unsigned long vdev)
return virt_to_bus(ptr); return virt_to_bus(ptr);
#endif #endif
} }
/* BEWARE: The IOC3 documentation documents the size of rx buffers as
* 1644 while it's actually 1664. This one was nasty to track down ...
*/
#define RX_OFFSET 10
#define RX_BUF_ALLOC_SIZE (1664 + RX_OFFSET + IOC3_CACHELINE)
#define IOC3_SIZE 0x100000 #define IOC3_SIZE 0x100000
static inline u32 mcr_pack(u32 pulse, u32 sample) static inline u32 mcr_pack(u32 pulse, u32 sample)
...@@ -538,11 +537,10 @@ static inline void ioc3_rx(struct net_device *dev) ...@@ -538,11 +537,10 @@ static inline void ioc3_rx(struct net_device *dev)
err = be32_to_cpu(rxb->err); /* It's valid ... */ err = be32_to_cpu(rxb->err); /* It's valid ... */
if (err & ERXBUF_GOODPKT) { if (err & ERXBUF_GOODPKT) {
len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4; len = ((w0 >> ERXBUF_BYTECNT_SHIFT) & 0x7ff) - 4;
skb_trim(skb, len); skb_put(skb, len);
skb->protocol = eth_type_trans(skb, dev); skb->protocol = eth_type_trans(skb, dev);
new_skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); if (ioc3_alloc_skb(&new_skb, &rxb)) {
if (!new_skb) {
/* Ouch, drop packet and just recycle packet /* Ouch, drop packet and just recycle packet
* to keep the ring filled. * to keep the ring filled.
*/ */
...@@ -560,11 +558,6 @@ static inline void ioc3_rx(struct net_device *dev) ...@@ -560,11 +558,6 @@ static inline void ioc3_rx(struct net_device *dev)
ip->rx_skbs[rx_entry] = NULL; /* Poison */ ip->rx_skbs[rx_entry] = NULL; /* Poison */
/* Because we reserve afterwards. */
skb_put(new_skb, (1664 + RX_OFFSET));
rxb = (struct ioc3_erxbuf *)new_skb->data;
skb_reserve(new_skb, RX_OFFSET);
dev->stats.rx_packets++; /* Statistics */ dev->stats.rx_packets++; /* Statistics */
dev->stats.rx_bytes += len; dev->stats.rx_bytes += len;
} else { } else {
...@@ -667,7 +660,11 @@ static void ioc3_error(struct net_device *dev, u32 eisr) ...@@ -667,7 +660,11 @@ static void ioc3_error(struct net_device *dev, u32 eisr)
ioc3_clean_tx_ring(ip); ioc3_clean_tx_ring(ip);
ioc3_init(dev); ioc3_init(dev);
ioc3_alloc_rx_bufs(dev); if (ioc3_alloc_rx_bufs(dev)) {
netdev_err(dev, "%s: rx buffer allocation failed\n", __func__);
spin_unlock(&ip->ioc3_lock);
return;
}
ioc3_start(ip); ioc3_start(ip);
ioc3_mii_init(ip); ioc3_mii_init(ip);
...@@ -801,7 +798,7 @@ static void ioc3_free_rx_bufs(struct ioc3_private *ip) ...@@ -801,7 +798,7 @@ static void ioc3_free_rx_bufs(struct ioc3_private *ip)
} }
} }
static void ioc3_alloc_rx_bufs(struct net_device *dev) static int ioc3_alloc_rx_bufs(struct net_device *dev)
{ {
struct ioc3_private *ip = netdev_priv(dev); struct ioc3_private *ip = netdev_priv(dev);
struct ioc3_erxbuf *rxb; struct ioc3_erxbuf *rxb;
...@@ -812,25 +809,16 @@ static void ioc3_alloc_rx_bufs(struct net_device *dev) ...@@ -812,25 +809,16 @@ static void ioc3_alloc_rx_bufs(struct net_device *dev)
* this for performance and memory later. * this for performance and memory later.
*/ */
for (i = 0; i < RX_BUFFS; i++) { for (i = 0; i < RX_BUFFS; i++) {
struct sk_buff *skb; if (ioc3_alloc_skb(&ip->rx_skbs[i], &rxb))
return -ENOMEM;
skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
if (!skb) {
show_free_areas(0, NULL);
continue;
}
ip->rx_skbs[i] = skb;
/* Because we reserve afterwards. */
skb_put(skb, (1664 + RX_OFFSET));
rxb = (struct ioc3_erxbuf *)skb->data;
rxb->w0 = 0; /* Clear valid flag */ rxb->w0 = 0; /* Clear valid flag */
ip->rxr[i] = cpu_to_be64(ioc3_map(rxb, 1)); ip->rxr[i] = cpu_to_be64(ioc3_map(rxb, 1));
skb_reserve(skb, RX_OFFSET);
} }
ip->rx_ci = 0; ip->rx_ci = 0;
ip->rx_pi = RX_BUFFS; ip->rx_pi = RX_BUFFS;
return 0;
} }
static inline void ioc3_ssram_disc(struct ioc3_private *ip) static inline void ioc3_ssram_disc(struct ioc3_private *ip)
...@@ -942,7 +930,10 @@ static int ioc3_open(struct net_device *dev) ...@@ -942,7 +930,10 @@ static int ioc3_open(struct net_device *dev)
ip->ehar_l = 0; ip->ehar_l = 0;
ioc3_init(dev); ioc3_init(dev);
ioc3_alloc_rx_bufs(dev); if (ioc3_alloc_rx_bufs(dev)) {
netdev_err(dev, "%s: rx buffer allocation failed\n", __func__);
return -ENOMEM;
}
ioc3_start(ip); ioc3_start(ip);
ioc3_mii_start(ip); ioc3_mii_start(ip);
...@@ -1435,7 +1426,11 @@ static void ioc3_timeout(struct net_device *dev) ...@@ -1435,7 +1426,11 @@ static void ioc3_timeout(struct net_device *dev)
ioc3_clean_tx_ring(ip); ioc3_clean_tx_ring(ip);
ioc3_init(dev); ioc3_init(dev);
ioc3_alloc_rx_bufs(dev); if (ioc3_alloc_rx_bufs(dev)) {
netdev_err(dev, "%s: rx buffer allocation failed\n", __func__);
spin_unlock_irq(&ip->ioc3_lock);
return;
}
ioc3_start(ip); ioc3_start(ip);
ioc3_mii_init(ip); ioc3_mii_init(ip);
ioc3_mii_start(ip); ioc3_mii_start(ip);
......
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