Skip to content

Commit

Permalink
sky2: dynamic size transmit ring
Browse files Browse the repository at this point in the history
Allocate and size transmit ring based on parameters. Saves excess
space and allows configuring larger rings for testing.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Stephen Hemminger authored and David S. Miller committed Aug 19, 2009
1 parent c119731 commit ee5f68f
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 23 deletions.
50 changes: 27 additions & 23 deletions drivers/net/sky2.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,12 @@
#define RX_MAX_PENDING (RX_LE_SIZE/6 - 2)
#define RX_DEF_PENDING RX_MAX_PENDING

#define TX_RING_SIZE 512
#define TX_DEF_PENDING 128
#define MAX_SKB_TX_LE (4 + (sizeof(dma_addr_t)/sizeof(u32))*MAX_SKB_FRAGS)
/* This is the worst case number of transmit list elements for a single skb:
VLAN + TSO + CKSUM + Data + skb_frags * DMA */
#define MAX_SKB_TX_LE (4 + (sizeof(dma_addr_t)/sizeof(u32))*MAX_SKB_FRAGS)
#define TX_MIN_PENDING (MAX_SKB_TX_LE+1)
#define TX_MAX_PENDING 4096
#define TX_DEF_PENDING 127

#define STATUS_RING_SIZE 2048 /* 2 ports * (TX + 2*RX) */
#define STATUS_LE_BYTES (STATUS_RING_SIZE*sizeof(struct sky2_status_le))
Expand Down Expand Up @@ -1000,7 +1002,7 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2, u16 *slot)
{
struct sky2_tx_le *le = sky2->tx_le + *slot;

*slot = RING_NEXT(*slot, TX_RING_SIZE);
*slot = RING_NEXT(*slot, sky2->tx_ring_size);
le->ctrl = 0;
return le;
}
Expand Down Expand Up @@ -1433,13 +1435,13 @@ static int sky2_up(struct net_device *dev)

/* must be power of 2 */
sky2->tx_le = pci_alloc_consistent(hw->pdev,
TX_RING_SIZE *
sky2->tx_ring_size *
sizeof(struct sky2_tx_le),
&sky2->tx_le_map);
if (!sky2->tx_le)
goto err_out;

sky2->tx_ring = kcalloc(TX_RING_SIZE, sizeof(struct tx_ring_info),
sky2->tx_ring = kcalloc(sky2->tx_ring_size, sizeof(struct tx_ring_info),
GFP_KERNEL);
if (!sky2->tx_ring)
goto err_out;
Expand Down Expand Up @@ -1491,7 +1493,7 @@ static int sky2_up(struct net_device *dev)
sky2_write16(hw, Q_ADDR(txqaddr[port], Q_AL), ECU_TXFF_LEV);

sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
TX_RING_SIZE - 1);
sky2->tx_ring_size - 1);

#ifdef SKY2_VLAN_TAG_USED
sky2_set_vlan_mode(hw, port, sky2->vlgrp != NULL);
Expand Down Expand Up @@ -1520,7 +1522,7 @@ static int sky2_up(struct net_device *dev)
}
if (sky2->tx_le) {
pci_free_consistent(hw->pdev,
TX_RING_SIZE * sizeof(struct sky2_tx_le),
sky2->tx_ring_size * sizeof(struct sky2_tx_le),
sky2->tx_le, sky2->tx_le_map);
sky2->tx_le = NULL;
}
Expand All @@ -1533,15 +1535,15 @@ static int sky2_up(struct net_device *dev)
}

/* Modular subtraction in ring */
static inline int tx_dist(unsigned tail, unsigned head)
static inline int tx_inuse(const struct sky2_port *sky2)
{
return (head - tail) & (TX_RING_SIZE - 1);
return (sky2->tx_prod - sky2->tx_cons) & (sky2->tx_ring_size - 1);
}

/* Number of list elements available for next tx */
static inline int tx_avail(const struct sky2_port *sky2)
{
return sky2->tx_pending - tx_dist(sky2->tx_cons, sky2->tx_prod);
return sky2->tx_pending - tx_inuse(sky2);
}

/* Estimate of number of transmit list elements required */
Expand Down Expand Up @@ -1717,7 +1719,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;

mapping_unwind:
for (i = sky2->tx_prod; i != slot; i = RING_NEXT(i, TX_RING_SIZE)) {
for (i = sky2->tx_prod; i != slot; i = RING_NEXT(i, sky2->tx_ring_size)) {
le = sky2->tx_le + i;
re = sky2->tx_ring + i;

Expand Down Expand Up @@ -1760,10 +1762,10 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
struct pci_dev *pdev = sky2->hw->pdev;
unsigned idx;

BUG_ON(done >= TX_RING_SIZE);
BUG_ON(done >= sky2->tx_ring_size);

for (idx = sky2->tx_cons; idx != done;
idx = RING_NEXT(idx, TX_RING_SIZE)) {
idx = RING_NEXT(idx, sky2->tx_ring_size)) {
struct sky2_tx_le *le = sky2->tx_le + idx;
struct tx_ring_info *re = sky2->tx_ring + idx;

Expand Down Expand Up @@ -1799,7 +1801,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
else
dev_kfree_skb_any(skb);

sky2->tx_next = RING_NEXT(idx, TX_RING_SIZE);
sky2->tx_next = RING_NEXT(idx, sky2->tx_ring_size);
}
}

Expand Down Expand Up @@ -1907,7 +1909,7 @@ static int sky2_down(struct net_device *dev)
kfree(sky2->rx_ring);

pci_free_consistent(hw->pdev,
TX_RING_SIZE * sizeof(struct sky2_tx_le),
sky2->tx_ring_size * sizeof(struct sky2_tx_le),
sky2->tx_le, sky2->tx_le_map);
kfree(sky2->tx_ring);

Expand Down Expand Up @@ -2517,7 +2519,6 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)

case OP_TXINDEXLE:
/* TX index reports status for both ports */
BUILD_BUG_ON(TX_RING_SIZE > 0x1000);
sky2_tx_done(hw->dev[0], status & 0xfff);
if (hw->dev[1])
sky2_tx_done(hw->dev[1],
Expand Down Expand Up @@ -3669,7 +3670,7 @@ static int sky2_set_coalesce(struct net_device *dev,
ecmd->rx_coalesce_usecs_irq > tmax)
return -EINVAL;

if (ecmd->tx_max_coalesced_frames >= TX_RING_SIZE-1)
if (ecmd->tx_max_coalesced_frames >= sky2->tx_ring_size-1)
return -EINVAL;
if (ecmd->rx_max_coalesced_frames > RX_MAX_PENDING)
return -EINVAL;
Expand Down Expand Up @@ -3713,7 +3714,7 @@ static void sky2_get_ringparam(struct net_device *dev,
ering->rx_max_pending = RX_MAX_PENDING;
ering->rx_mini_max_pending = 0;
ering->rx_jumbo_max_pending = 0;
ering->tx_max_pending = TX_RING_SIZE - 1;
ering->tx_max_pending = TX_MAX_PENDING;

ering->rx_pending = sky2->rx_pending;
ering->rx_mini_pending = 0;
Expand All @@ -3728,14 +3729,15 @@ static int sky2_set_ringparam(struct net_device *dev,

if (ering->rx_pending > RX_MAX_PENDING ||
ering->rx_pending < 8 ||
ering->tx_pending < MAX_SKB_TX_LE ||
ering->tx_pending > TX_RING_SIZE - 1)
ering->tx_pending < TX_MIN_PENDING ||
ering->tx_pending > TX_MAX_PENDING)
return -EINVAL;

sky2_detach(dev);

sky2->rx_pending = ering->rx_pending;
sky2->tx_pending = ering->tx_pending;
sky2->tx_ring_size = roundup_pow_of_two(sky2->tx_pending+1);

return sky2_reattach(dev);
}
Expand Down Expand Up @@ -4105,8 +4107,8 @@ static int sky2_debug_show(struct seq_file *seq, void *v)

/* Dump contents of tx ring */
sop = 1;
for (idx = sky2->tx_next; idx != sky2->tx_prod && idx < TX_RING_SIZE;
idx = RING_NEXT(idx, TX_RING_SIZE)) {
for (idx = sky2->tx_next; idx != sky2->tx_prod && idx < sky2->tx_ring_size;
idx = RING_NEXT(idx, sky2->tx_ring_size)) {
const struct sky2_tx_le *le = sky2->tx_le + idx;
u32 a = le32_to_cpu(le->addr);

Expand Down Expand Up @@ -4315,7 +4317,9 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->wol = wol;

spin_lock_init(&sky2->phy_lock);

sky2->tx_pending = TX_DEF_PENDING;
sky2->tx_ring_size = roundup_pow_of_two(TX_DEF_PENDING+1);
sky2->rx_pending = RX_DEF_PENDING;

hw->dev[port] = dev;
Expand Down
1 change: 1 addition & 0 deletions drivers/net/sky2.h
Original file line number Diff line number Diff line change
Expand Up @@ -2011,6 +2011,7 @@ struct sky2_port {

struct tx_ring_info *tx_ring;
struct sky2_tx_le *tx_le;
u16 tx_ring_size;
u16 tx_cons; /* next le to check */
u16 tx_prod; /* next le to use */
u16 tx_next; /* debug only */
Expand Down

0 comments on commit ee5f68f

Please sign in to comment.