@@ -45,7 +45,7 @@
default, use ethtool to turn it on.
*/
-
+#define DEBUG
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define DRV_NAME "8139cp"
@@ -157,6 +157,7 @@ enum {
NWayAdvert = 0x66, /* MII ADVERTISE */
NWayLPAR = 0x68, /* MII LPA */
NWayExpansion = 0x6A, /* MII Expansion */
+ TxDmaOkLowDesc = 0x82, /* Low 16 bit address of a Tx descriptor. */
Config5 = 0xD8, /* Config5 */
TxPoll = 0xD9, /* Tell chip to check Tx descriptors for work */
RxMaxSize = 0xDA, /* Max size of an Rx packet (8169 only) */
@@ -341,10 +342,11 @@ struct cp_private {
unsigned tx_tail;
struct cp_desc *tx_ring;
struct sk_buff *tx_skb[CP_TX_RING_SIZE];
-
+ struct cp_desc tx_ring_shadow[CP_TX_RING_SIZE];
unsigned rx_buf_sz;
unsigned wol_enabled : 1; /* Is Wake-on-LAN enabled? */
-
+ unsigned tx_ring_running : 1;
+ int tx_ring_seen;
dma_addr_t ring_dma;
struct mii_if_info mii_if;
@@ -504,8 +506,8 @@ rx_status_loop:
goto rx_next;
}
- netif_dbg(cp, rx_status, dev, "rx slot %d status 0x%x len %d\n",
- rx_tail, status, len);
+ netif_dbg(cp, rx_status, dev, "rx (%d) slot %d status 0x%x len %d\n",
+ rx, rx_tail, status, len);
new_skb = napi_alloc_skb(napi, buflen);
if (!new_skb) {
@@ -554,6 +556,7 @@ rx_next:
/* if we did not reach work limit, then we're done with
* this round of polling
*/
+ netif_dbg(cp, rx_status, dev, "rx %d of %d\n", rx, budget);
if (rx < budget) {
unsigned long flags;
@@ -566,6 +569,7 @@ rx_next:
cpw16_f(IntrMask, cp_intr_mask);
spin_unlock_irqrestore(&cp->lock, flags);
}
+ netif_dbg(cp, rx_status, dev, "rx done %d of %d\n", rx, budget);
return rx;
}
@@ -606,9 +610,38 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
__napi_schedule(&cp->napi);
}
}
+
if (status & (TxOK | TxErr | TxEmpty | SWInt))
handled |= cp_tx(cp);
+ if (status & TxEmpty) {
+ handled = 1;
+ if (cp->tx_head == cp->tx_tail) {
+ /* Out of descriptors and we have nothing more for it.
+ Let it stop. */
+ cp->tx_ring_running = 0;
+ netif_dbg(cp, tx_queued, cp->dev, "irq not kicking tx_poll, head %d tail %d desc %04x poll %02x", cp->tx_head, cp->tx_tail, cpr16(TxDmaOkLowDesc), cpr8(TxPoll));
+ cp->tx_head = cp->tx_tail = 0;
+ } else {
+ if (cp->tx_ring_seen >= 0) {
+ /* We *know* that tx_ring_seen was in the queue when
+ we prodded it to start, and yet it's claiming that
+ it's out of descriptors already! */
+ netdev_warn(dev, "Invalid TxEmpty, should have seen %d at %p status %2x %4x %4x %4x desc %4x poll %02x\n",
+ cp->tx_ring_seen, &cp->tx_ring[cp->tx_ring_seen],
+ cpr8(Cmd), cpr16(CpCmd),
+ cpr16(IntrStatus), cpr16(IntrMask), cpr16(TxDmaOkLowDesc), cpr8(TxPoll));
+ }
+ /* The hardware raced with us adding a new descriptor, and
+ we didn't get the IRQ in time so we didn't prod it.
+ Prod it now to restart */
+ cp->tx_ring_running = 1;
+ cp->tx_ring_seen = cp->tx_head ? cp->tx_head - 1 : (CP_TX_RING_SIZE - 1);;
+ netif_dbg(cp, tx_queued, cp->dev, "irq kicking tx_poll, head %d tail %d desc %04x poll %02x", cp->tx_head, cp->tx_tail, cpr16(TxDmaOkLowDesc), cpr8(TxPoll));
+ cpw8(TxPoll, NormalTxPoll);
+ }
+ }
+
if (status & LinkChg) {
handled = 1;
mii_check_media(&cp->mii_if, netif_msg_link(cp), false);
@@ -665,6 +698,11 @@ static int cp_tx (struct cp_private *cp)
if (status & DescOwn)
break;
+ /* If it's processed the last descriptor we *knew*
+ * was in place when we last started it, note that. */
+ if (tx_tail == cp->tx_ring_seen)
+ cp->tx_ring_seen = -1;
+
handled = 1;
skb = cp->tx_skb[tx_tail];
BUG_ON(!skb);
@@ -692,12 +730,12 @@ static int cp_tx (struct cp_private *cp)
cp->dev->stats.tx_packets++;
cp->dev->stats.tx_bytes += skb->len;
netif_dbg(cp, tx_done, cp->dev,
- "tx done, slot %d\n", tx_tail);
+ "tx done, slot %d, status 0x%x dec %04x\n", tx_tail, status, cpr16(TxDmaOkLowDesc));
}
bytes_compl += skb->len;
pkts_compl++;
dev_kfree_skb_irq(skb);
- }
+ } else netif_dbg(cp, tx_done, cp->dev, "tx partial done, stlot %d, status 0x%x", tx_tail, status);
cp->tx_skb[tx_tail] = NULL;
@@ -773,6 +811,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
txd->opts2 = opts2;
txd->addr = cpu_to_le64(mapping);
+
wmb();
flags = eor | len | DescOwn | FirstFrag | LastFrag;
@@ -790,13 +829,16 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
}
txd->opts1 = cpu_to_le32(flags);
+ cp->tx_ring_shadow[entry].opts2 = opts2;
+ cp->tx_ring_shadow[entry].addr = cpu_to_le64(mapping);
+ cp->tx_ring_shadow[entry].opts1 = cpu_to_le32(flags);
wmb();
cp->tx_skb[entry] = skb;
entry = NEXT_TX(entry);
} else {
struct cp_desc *txd;
- u32 first_len, first_eor;
+ u32 first_len, first_eor, ctrl;
dma_addr_t first_mapping;
int frag, first_entry = entry;
const struct iphdr *ip = ip_hdr(skb);
@@ -817,7 +859,6 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
const skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
u32 len;
- u32 ctrl;
dma_addr_t mapping;
len = skb_frag_size(this_frag);
@@ -854,6 +895,9 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
wmb();
txd->opts1 = cpu_to_le32(ctrl);
+ cp->tx_ring_shadow[entry].opts2 = opts2;
+ cp->tx_ring_shadow[entry].addr = cpu_to_le64(mapping);
+ cp->tx_ring_shadow[entry].opts1 = cpu_to_le32(ctrl);
wmb();
cp->tx_skb[entry] = skb;
@@ -863,37 +907,48 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
txd = &cp->tx_ring[first_entry];
txd->opts2 = opts2;
txd->addr = cpu_to_le64(first_mapping);
+ cp->tx_ring_shadow[first_entry].opts2 = opts2;
+ cp->tx_ring_shadow[first_entry].addr = cpu_to_le64(first_mapping);
+
wmb();
if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (ip->protocol == IPPROTO_TCP)
- txd->opts1 = cpu_to_le32(first_eor | first_len |
+ ctrl = (first_eor | first_len |
FirstFrag | DescOwn |
IPCS | TCPCS);
else if (ip->protocol == IPPROTO_UDP)
- txd->opts1 = cpu_to_le32(first_eor | first_len |
+ ctrl = (first_eor | first_len |
FirstFrag | DescOwn |
IPCS | UDPCS);
else
BUG();
} else
- txd->opts1 = cpu_to_le32(first_eor | first_len |
+ ctrl = (first_eor | first_len |
FirstFrag | DescOwn);
+ txd->opts1 = cpu_to_le32(ctrl);
+ cp->tx_ring_shadow[first_entry].opts1 = cpu_to_le32(ctrl);
wmb();
}
cp->tx_head = entry;
netdev_sent_queue(dev, skb->len);
netif_dbg(cp, tx_queued, cp->dev, "tx queued, slot %d, skblen %d\n",
- entry, skb->len);
+ entry ? entry - 1 : CP_TX_RING_SIZE-1, skb->len);
if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
netif_stop_queue(dev);
out_unlock:
+ if (!cp->tx_ring_running) {
+ cp->tx_ring_running = 1;
+ cp->tx_ring_seen = cp->tx_head ? cp->tx_head - 1 : (CP_TX_RING_SIZE - 1);;
+ netif_dbg(cp, tx_queued, cp->dev, "tx kicking tx_poll, head %d tail %d desc %04x poll %02x", cp->tx_head, cp->tx_tail, cpr16(TxDmaOkLowDesc), cpr8(TxPoll));
+ cpw8(TxPoll, NormalTxPoll);
+ } else {
+ netif_dbg(cp, tx_queued, cp->dev, "tx not kicking tx_poll, head %d tail %d desc %04x poll %02x", cp->tx_head, cp->tx_tail, cpr16(TxDmaOkLowDesc), cpr8(TxPoll));
+ }
spin_unlock_irqrestore(&cp->lock, intr_flags);
- cpw8(TxPoll, NormalTxPoll);
-
return NETDEV_TX_OK;
out_dma_error:
dev_kfree_skb_any(skb);
@@ -1035,7 +1090,8 @@ static inline void cp_start_hw (struct cp_private *cp)
* This variant appears to work fine.
*/
cpw8(Cmd, RxOn | TxOn);
-
+ cp->tx_ring_running = 0;
+ cp->tx_ring_seen = -1;
netdev_reset_queue(cp->dev);
}
@@ -1057,7 +1113,7 @@ static void cp_init_hw (struct cp_private *cp)
cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4)));
cp_start_hw(cp);
- cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */
+ cpw8(TxThresh, 0x2f); /* XXX convert magic num to a constant */
__cp_set_rx_mode(dev);
cpw32_f (TxConfig, IFG | (TX_DMA_BURST << TxDMAShift));
@@ -1255,26 +1311,74 @@ static int cp_close (struct net_device *dev)
static void cp_tx_timeout(struct net_device *dev)
{
struct cp_private *cp = netdev_priv(dev);
+ dma_addr_t ring_dma;
unsigned long flags;
int rc;
+ int i;
- netdev_warn(dev, "Transmit timeout, status %2x %4x %4x %4x\n",
+ netdev_warn(dev, "Transmit timeout, status %2x %4x %4x %4x desc %02x poll %02x\n",
cpr8(Cmd), cpr16(CpCmd),
- cpr16(IntrStatus), cpr16(IntrMask));
+ cpr16(IntrStatus), cpr16(IntrMask),
+ cpr16(TxDmaOkLowDesc), cpr8(TxPoll));
spin_lock_irqsave(&cp->lock, flags);
+ for (i = 0; i < CP_TX_RING_SIZE; i++) {
+ printk("TX ring %02d @%p: %p %llx %x %x (%x %x)\n",
+ i, &cp->tx_ring[i], cp->tx_skb[i], (unsigned long long)cp->tx_ring[i].addr,
+ cp->tx_ring[i].opts1, cp->tx_ring[i].opts2,
+ cp->tx_ring_shadow[i].opts1, cp->tx_ring_shadow[i].opts2);
+ }
+//static void cp_stop_hw (struct cp_private *cp)
+{
+ cpw8(Cmd, RxOn);
+
+ cp->tx_head = cp->tx_tail = 0;
+
+}
+//static void cp_clean_rings (struct cp_private *cp)
+{
+ struct cp_desc *desc;
+
+ for (i = 0; i < CP_TX_RING_SIZE; i++) {
+ if (cp->tx_skb[i]) {
+ struct sk_buff *skb = cp->tx_skb[i];
+
+ desc = cp->tx_ring + i;
+ dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
+ le32_to_cpu(desc->opts1) & 0xffff,
+ PCI_DMA_TODEVICE);
+ if (le32_to_cpu(desc->opts1) & LastFrag)
+ dev_kfree_skb_any(skb);
+ cp->dev->stats.tx_dropped++;
+ cp->tx_skb[i] = NULL;
+ }
+ if (i == CP_TX_RING_SIZE - 1)
+ cp->tx_ring[i].opts1 = cpu_to_le32(RingEnd);
+ else
+ cp->tx_ring[i].opts1 = cpu_to_le32(0);
+ cp->tx_ring[i].opts2 = cpu_to_le32(0);
+ cp->tx_ring[i].addr = cpu_to_le64(0);
+ }
+ netdev_reset_queue(cp->dev);
+}
+
+ cpw8(Cmd, RxOn | TxOn);
+ cp->tx_ring_running = 0;
+ cp->tx_ring_seen = -1;
+
+
+#if 0
cp_stop_hw(cp);
cp_clean_rings(cp);
rc = cp_init_rings(cp);
cp_start_hw(cp);
+#endif
__cp_set_rx_mode(dev);
cpw16_f(IntrMask, cp_norx_intr_mask);
-
- netif_wake_queue(dev);
napi_schedule_irqoff(&cp->napi);
-
spin_unlock_irqrestore(&cp->lock, flags);
+ netif_wake_queue(dev);
}
static int cp_change_mtu(struct net_device *dev, int new_mtu)
@@ -1989,7 +2093,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
cpu_to_le16(read_eeprom (regs, i + 7, addr_len));
dev->netdev_ops = &cp_netdev_ops;
- netif_napi_add(dev, &cp->napi, cp_rx_poll, 16);
+ netif_napi_add(dev, &cp->napi, cp_rx_poll, NAPI_POLL_WEIGHT);
dev->ethtool_ops = &cp_ethtool_ops;
dev->watchdog_timeo = TX_TIMEOUT;