[PATCH 107/222] net:fec: better indexing for receive descriptor ring
Russell King
rmk+kernel at arm.linux.org.uk
Fri Apr 25 04:40:03 PDT 2014
Extend the previous commit to the receive descriptor ring as well. This
gets rid of the two nextdesc/prevdesc functions, since we now just need
to get the descriptor for an index instead.
Signed-off-by: Russell King <rmk+kernel at arm.linux.org.uk>
---
drivers/net/ethernet/freescale/fec.h | 2 +-
drivers/net/ethernet/freescale/fec_main.c | 98 +++++++++++--------------------
2 files changed, 35 insertions(+), 65 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index c5a72c4bd07d..4b92758b51b8 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -293,7 +293,7 @@ struct fec_enet_private {
/* The next free ring entry */
unsigned short tx_next;
unsigned short tx_dirty;
- union bufdesc_u *cur_rx;
+ unsigned short rx_next;
unsigned short tx_ring_size;
unsigned short rx_ring_size;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index aec802b778f7..dba2e315f937 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -241,44 +241,20 @@ fec_enet_tx_get(unsigned index, struct fec_enet_private *fep)
return bdp;
}
-static inline
-union bufdesc_u *fec_enet_get_nextdesc(union bufdesc_u *bdp, struct fec_enet_private *fep)
+static union bufdesc_u *
+fec_enet_rx_get(unsigned index, struct fec_enet_private *fep)
{
- union bufdesc_u *base;
- int ring_size;
-
- base = fep->rx_bd_base;
- ring_size = fep->rx_ring_size;
-
- if (fep->bufdesc_ex) {
- struct bufdesc_ex *ebd = &bdp->ebd + 1;
- return ebd >= (&base->ebd + ring_size) ?
- base : (union bufdesc_u *)ebd;
- } else {
- struct bufdesc *bd = &bdp->bd + 1;
- return bd >= (&base->bd + ring_size) ?
- base : (union bufdesc_u *)bd;
- }
-}
+ union bufdesc_u *base = fep->rx_bd_base;
+ union bufdesc_u *bdp;
-static inline
-union bufdesc_u *fec_enet_get_prevdesc(union bufdesc_u *bdp, struct fec_enet_private *fep)
-{
- union bufdesc_u *base;
- int ring_size;
+ index &= fep->rx_ring_size - 1;
- base = fep->rx_bd_base;
- ring_size = fep->rx_ring_size;
+ if (fep->bufdesc_ex)
+ bdp = (union bufdesc_u *)(&base->ebd + index);
+ else
+ bdp = (union bufdesc_u *)(&base->bd + index);
- if (fep->bufdesc_ex) {
- struct bufdesc_ex *ebd = &bdp->ebd - 1;
- return (union bufdesc_u *)(ebd < &base->ebd ?
- ebd + ring_size : ebd);
- } else {
- struct bufdesc *bd = &bdp->bd - 1;
- return (union bufdesc_u *)(bd < &base->bd ?
- bd + ring_size : bd);
- }
+ return bdp;
}
static void *swap_buffer(void *bufaddr, int len)
@@ -471,22 +447,20 @@ static void fec_enet_bd_init(struct net_device *dev)
unsigned int i;
/* Initialize the receive buffer descriptors. */
- bdp = fep->rx_bd_base;
for (i = 0; i < fep->rx_ring_size; i++) {
+ bdp = fec_enet_rx_get(i, fep);
/* Initialize the BD for every fragment in the page. */
if (bdp->bd.cbd_bufaddr)
bdp->bd.cbd_sc = BD_ENET_RX_EMPTY;
else
bdp->bd.cbd_sc = 0;
- bdp = fec_enet_get_nextdesc(bdp, fep);
- }
- /* Set the last buffer to wrap */
- bdp = fec_enet_get_prevdesc(bdp, fep);
- bdp->bd.cbd_sc |= BD_SC_WRAP;
+ if (i == fep->rx_ring_size - 1)
+ bdp->bd.cbd_sc |= BD_SC_WRAP;
+ }
- fep->cur_rx = fep->rx_bd_base;
+ fep->rx_next = 0;
/* ...and the same for transmit */
for (i = 0; i < fep->tx_ring_size; i++) {
@@ -848,7 +822,7 @@ fec_enet_tx(struct net_device *ndev)
}
-/* During a receive, the cur_rx points to the current incoming buffer.
+/* During a receive, the rx_next points to the current incoming buffer.
* When we update through the ring, if the next incoming buffer has
* not been given to the system, we just set the empty indicator,
* effectively tossing the packet.
@@ -859,7 +833,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
struct fec_enet_private *fep = netdev_priv(ndev);
const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev);
- union bufdesc_u *bdp;
unsigned short status;
struct sk_buff *skb;
ushort pkt_len;
@@ -867,7 +840,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
int pkt_received = 0;
bool vlan_packet_rcvd = false;
u16 vlan_tag;
- int index = 0;
+ unsigned index = fep->rx_next;
#ifdef CONFIG_M532x
flush_cache_all();
@@ -876,12 +849,16 @@ fec_enet_rx(struct net_device *ndev, int budget)
/* First, grab all of the stats for the incoming packet.
* These get messed up if we get called due to a busy condition.
*/
- bdp = fep->cur_rx;
+ do {
+ union bufdesc_u *bdp = fec_enet_rx_get(index, fep);
- while (!((status = bdp->bd.cbd_sc) & BD_ENET_RX_EMPTY)) {
+ status = bdp->bd.cbd_sc;
+ if (status & BD_ENET_RX_EMPTY)
+ break;
if (pkt_received >= budget)
break;
+
pkt_received++;
/* Since we have allocated space to hold a complete frame,
@@ -923,10 +900,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
pkt_len = bdp->bd.cbd_datlen;
ndev->stats.rx_bytes += pkt_len;
- if (fep->bufdesc_ex)
- index = &bdp->ebd - &fep->rx_bd_base->ebd;
- else
- index = &bdp->bd - &fep->rx_bd_base->bd;
data = fep->rx_skbuff[index]->data;
dma_sync_single_for_cpu(&fep->pdev->dev, bdp->bd.cbd_bufaddr,
FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
@@ -1017,16 +990,16 @@ fec_enet_rx(struct net_device *ndev, int budget)
status |= BD_ENET_RX_EMPTY;
bdp->bd.cbd_sc = status;
- /* Update BD pointer to next entry */
- bdp = fec_enet_get_nextdesc(bdp, fep);
-
/* Doing this here will keep the FEC running while we process
* incoming frames. On a heavily loaded network, we should be
* able to keep up at the expense of system resources.
*/
writel(0, fep->hwp + FEC_R_DES_ACTIVE);
- }
- fep->cur_rx = bdp;
+
+ if (++index >= fep->rx_ring_size)
+ index = 0;
+ } while (1);
+ fep->rx_next = index;
return pkt_received;
}
@@ -1713,8 +1686,9 @@ static void fec_enet_free_buffers(struct net_device *ndev)
struct sk_buff *skb;
union bufdesc_u *bdp;
- bdp = fep->rx_bd_base;
for (i = 0; i < fep->rx_ring_size; i++) {
+ bdp = fec_enet_rx_get(i, fep);
+
skb = fep->rx_skbuff[i];
fep->rx_skbuff[i] = NULL;
if (skb) {
@@ -1722,7 +1696,6 @@ static void fec_enet_free_buffers(struct net_device *ndev)
FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
dev_kfree_skb(skb);
}
- bdp = fec_enet_get_nextdesc(bdp, fep);
}
for (i = 0; i < fep->tx_ring_size; i++) {
@@ -1745,7 +1718,6 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
struct sk_buff *skb;
union bufdesc_u *bdp;
- bdp = fep->rx_bd_base;
for (i = 0; i < fep->rx_ring_size; i++) {
dma_addr_t addr;
@@ -1763,19 +1735,17 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
}
fep->rx_skbuff[i] = skb;
+ bdp = fec_enet_rx_get(i, fep);
bdp->bd.cbd_bufaddr = addr;
bdp->bd.cbd_sc = BD_ENET_RX_EMPTY;
+ /* Set the last buffer to wrap. */
+ if (i == fep->rx_ring_size - 1)
+ bdp->bd.cbd_sc |= BD_SC_WRAP;
if (fep->bufdesc_ex)
bdp->ebd.cbd_esc = BD_ENET_RX_INT;
-
- bdp = fec_enet_get_nextdesc(bdp, fep);
}
- /* Set the last buffer to wrap. */
- bdp = fec_enet_get_prevdesc(bdp, fep);
- bdp->bd.cbd_sc |= BD_SC_WRAP;
-
for (i = 0; i < fep->tx_ring_size; i++) {
bdp = fec_enet_tx_get(i, fep);
fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
--
1.8.3.1
More information about the linux-arm-kernel
mailing list