[Click] e1000 driver timeout with 2.6.x

todd lewis tgl2 at yahoo.com
Tue Jul 18 02:36:58 EDT 2006


FWIW, this doesn't work any better for me at all.

I'm running a patched 2.6.16.13 on an opteron machine.  The card is a dual-port 82546GB PCI-X
card, using Massimiliano's patched driver.

*********************************
root at horsemen:/tmp/e1000-6.1.16.2.DB/src# dmesg|head
[17179569.184000] Linux version 2.6.16.13 (root at horsemen) (gcc version 4.0.2 20050808 (prerelease)
(Ubuntu 4.0.1-4ubuntu9)) #2 SMP Mon Jul 17 21:37:23 EDT 2006
*********************************

*********************************
[17179930.956000] NETDEV WATCHDOG: eth2: transmit timed out
[17179930.996000] ToDevice eth2 rejected a packet!
[17179934.996000] e1000: eth2: e1000_watchdog_1: NIC Link is Up 1000 Mbps Full Duplex
[17179958.412000] ToDevice eth3 rejected a packet!
[17179965.624000] NETDEV WATCHDOG: eth3: transmit timed out
[17179969.664000] e1000: eth3: e1000_watchdog_1: NIC Link is Up 1000 Mbps Full Duplex
[17179979.996000] NETDEV WATCHDOG: eth2: transmit timed out
[17179984.036000] e1000: eth2: e1000_watchdog_1: NIC Link is Up 1000 Mbps Full Duplex
[17180049.076000] NETDEV WATCHDOG: eth2: transmit timed out
[17180053.120000] e1000: eth2: e1000_watchdog_1: NIC Link is Up 1000 Mbps Full Duplex
[17180083.120000] NETDEV WATCHDOG: eth2: transmit timed out
[17180084.680000] NETDEV WATCHDOG: eth3: transmit timed out
[17180087.160000] e1000: eth2: e1000_watchdog_1: NIC Link is Up 1000 Mbps Full Duplex
*********************************

My config is a rather simple switch:

*********************************
s :: EtherSwitch;
in :: Suppressor;
out :: Suppressor;
st :: EtherSpanTree(00:02:03:04:05:06, in, out, s);
tohost :: ToHost;

w0 :: Queue -> ToDevice(eth2);
 PollDevice(eth2) -> f0 :: Classifier(14/4242, 0/000423CD4888, -);
f0[2] -> [0]in[0] -> [0]s[0] -> [0]out[0] -> w0;
f0[0] -> [0]st[0] -> w0;
f0[1] -> tohost;
w1 :: Queue -> ToDevice(eth3);
 PollDevice(eth3) -> f1 :: Classifier(14/4242, 0/000423CD4889, -);
f1[2] -> [1]in[1] -> [1]s[1] -> [1]out[1] -> w1;
f1[0] -> [1]st[1] -> w1;
f1[1] -> tohost;
*********************************

I hope this helps.

--- Massimiliano Poletto <maxp at mazunetworks.com> wrote:

> Hi Srivas and Beyers, I've spent some time looking at drivers again recently.
> 
> What works best for me at present is a patched version of the 6.1.16.2
> Intel driver (not the 6.3.9-k4 driver that comes with linux
> 2.6.16.13).  I attach the driver sources and patch to this email.  I'm
> using a 2.6.16.22 kernel, but I don't see why .13 should work any less
> well with the driver.
> 
> Performance is good, and it is stable across hundreds of
> installs/uninstalls and many hours of testing at full line rate
> offered load.  I sometimes see messages similar to yours (below is an
> example), but they only seem to happen during stress tests when click
> is repeatedly installed/uninstalled at very short intervals:
> e1000: eth2: e1000_clean_tx_irq: Detected Tx Unit Hang
>   TDH                  <b0>
>   TDT                  <b0>
>   next_to_use          <b0>
>   next_to_clean        <9e>
> buffer_info[next_to_clean]
>   dma                  <2c66c040>
>   time_stamp           <0>
>   next_to_watch        <0>
>   jiffies              <82ddae8>
>   next_to_watch.status <0>
> 
> I'm trying to get a sourceforge 7.x driver to work, but for now this
> seems at least workable.
> 
> Please let me know if you have problems with this driver, or if you
> make other progress yourselves.
> 
> Regards,
> max
> 
> 
> On 7/3/06, Srivas Chennu <chennu at hhi.fhg.de> wrote:
> > Hello Beyers,
> >
> > Thanks a lot for your speedy response. To answer your question regarding
> > the e1000 driver, I've downloaded and tested my configuration with the
> > latest stable release (7.1.9) from sourceforge, and the timeout
> > stubbornly continues to occur with the TSO option disabled.
> >
> > For your reference, the possibly relevant snippet of my click
> > configuration is attached. It uses a click element (onuagent) that I've
> > written to emulate the protocol being tested, which receives and
> > forwards packets between 3 interfaces via a customized priority
> > schedulers.
> >
> > ...
> > FromDevice($rp0, PROMISC true) -> [0]onuagent;
> > onuagent[0] -> priosched0 -> ToDevice($rp0);
> > FromDevice($rp1, PROMISC true) -> [1]onuagent;
> > onuagent[1] -> priosched1 -> ToDevice($rp1);
> > FromDevice($lp, PROMISC true) -> [2]onuagent;
> > onuagent[2] -> priosched2 -> ToDevice($lp);
> > ...
> >
> > I'm currently attempting to find a combination of a kernel (2.4.x or
> > 2.6.x) and a stable e1000 driver version with which I can reliably use
> > FromDevice/PollDevice. Any details of a setup that has worked for you in
> > this regard would be helpful.
> >
> > Thanks in advance,
> > Srivas.
> >
> > On Jul 03, 2006 05:18 PM, Beyers Cronje wrote:
> >
> >
> > >
> > > Hi Srivas,
> > >
> > > This is a problem myself, Adamand a few others have been struggling
> > > with. Strange FromDevice gives you the TX hang, as on my system it
> > > only happens when using PollDevice in certain configurations. If
> > > possible can you post the Click config you are using to duplicate the
> > > hang?
> > >
> > > Adam pointed me to the E1000 dev mailing list on SourceForge and the
> > > TX Hang issue seems to pop up on standard linux (non-click) systems as
> > > well. One possible workaround seems to be to disable tcp segmentation
> > > offloading (TSO), you can do this via 'ethtool -K eth0 tso off', but
> > > seems to work only sometimes ...
> > >
> > > What e1000 driver version are you using? Since you only using
> > > FromDevice have you tried the latest e1000 driver?
> > >
> > > Anyone else also having this problem?
> > >
> > > Beyers
> > >
> > >
> > > On 7/3/06, Srivas Chennu <chennu at hhi.fhg.de> wrote:
> > > > Hello all,
> > > >
> > > > I'm a relatively new click user trying to build and test a link
> > > > layer
> > > > protocol using Click. My test runs used the click kernel module
> > > > built
> > > > from the latest CVS sources. On a patched 2.6.16.13 kernel with an
> > > > original Intel PRO/1000 MT dual port GbE NIC for a click
> > > > configuration
> > > > using FromDevice, the driver abruptly times out during Tx and resets
> > > > with messages like those below:
> > > >
> > > > e1000: eth1: e1000_clean_tx_irq: Detected Tx Unit Hang
> > > > Tx Queue <0>
> > > > TDH <97>
> > > > TDT <9a>
> > > > next_to_use <9a>
> > > > next_to_clean <95>
> > > > buffer_info[next_to_clean]
> > > > time_stamp
> > > > next_to_watch <97>
> > > > jiffies
> > > > next_to_watch.status <0>
> > > > ....
> > > > ....
> > > > Eventually I see in the log file:
> > > >
> > > > NETDEV WATCHDOG: eth1: transmit timed out
> > > > e1000: eth1: e1000_watchdog: NIC Link is Up 1000 Mbps Full Duplex
> > > >
> > > > Interestingly, this timeout-and-reset problem does not occur when
> > > > running my click configuration at the userlevel, but reproduces
> > > > quite
> > > > easily with the kernel module, even when the NIC is working at low
> > > > packet Rx rates. All configuration parameters to the e1000 modules
> > > > are
> > > > at their defaults, and my attempts with parameters suggested in a
> > > > previous post
> > > > (
> > > > https://amsterdam.lcs.mit.edu/pipermail/click/2006-March/004690.html)
> > > > for similar problems didn't help.
> > > >
> > > >
> > > > Any pointers to solving this problem are appreciated,
> > > >
> > > > Thanks in advance,
> > > > Srivas.
> > > >
> > > >
> > > > --
> > > > Meet us at
> > > >
> > > > OC&I 2006 and NOC 2006: 10.-13.7.06 at HHI Berlin, Germany
> > > > IFA: 1.-6.9.06, Berlin, Germany
> > > > _______________________________________________
> > > > click mailing list
> > > > click at amsterdam.lcs.mit.edu
> > > > https://amsterdam.lcs.mit.edu/mailman/listinfo/click
> > > >
> >
> > >
> >
> >
> > --
> > Meet us at
> >
> > OC&I 2006 and NOC 2006: 10.-13.7.06 at HHI Berlin, Germany
> > IFA: 1.-6.9.06, Berlin, Germany
> > _______________________________________________
> > click mailing list
> > click at amsterdam.lcs.mit.edu
> > https://amsterdam.lcs.mit.edu/mailman/listinfo/click
> >
> > diff -ruN e1000-6.1.16.2.DB/src/e1000.h e1000-6.1.16.2.DB-patched/src/e1000.h
> --- e1000-6.1.16.2.DB/src/e1000.h	2006-01-05 19:23:20.000000000 -0500
> +++ e1000-6.1.16.2.DB-patched/src/e1000.h	2006-03-01 12:11:49.000000000 -0500
> @@ -243,6 +243,11 @@
>  #define E1000_TX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_tx_desc)
>  #define E1000_CONTEXT_DESC(R, i)	E1000_GET_DESC(R, i, e1000_context_desc)
>  
> +#define E1000_RX_STATE_NORMAL 0
> +#define E1000_RX_STATE_QUIET  1
> +#define E1000_RX_STATE_LOCKUP 2
> +
> +
>  /* board specific private data structure */
>  
>  struct e1000_adapter {
> @@ -361,5 +366,15 @@
>  #ifdef CONFIG_PCI_MSI
>  	boolean_t have_msi;
>  #endif
> +
> +        int do_poll_watchdog; /* Click polling */
> +
> +        /* Receive Lockup detection and recovery */
> +        int rx_state;              /* can be either: NORMAL, QUIET, LOCKUP */
> +        int rx_lockup_recoveries;  /* # of times the recovery seq is invoked */
> +        int rx_normal_jiffies;     /* jiffies timeout for the NORMAL state */
> +        int rx_quiet_jiffies;      /* jiffies timeout for the QUIET state */
> +        int prev_rdfh;             /* prev value of Rcv Data Fifo Head register */
> +        int prev_rdft;             /* prev value of Rcv Data Fifo Tail register */
>  };
>  #endif /* _E1000_H_ */
> diff -ruN e1000-6.1.16.2.DB/src/e1000_hw.h e1000-6.1.16.2.DB-patched/src/e1000_hw.h
> --- e1000-6.1.16.2.DB/src/e1000_hw.h	2006-01-05 19:23:20.000000000 -0500
> +++ e1000-6.1.16.2.DB-patched/src/e1000_hw.h	2006-03-01 12:11:50.000000000 -0500
> @@ -906,6 +906,13 @@
>  #define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
>  #define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
>  #define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
> +
> +#define E1000_RDFH     0x02410  /* Diagnostic: Receive Data Fifo Head - RW */
> +#define E1000_RDFT     0x02418  /* Diagnostic: Receive Data Fifo Tail - RW */
> +#define E1000_RDFHS    0x02420  /* Diagnostic: Receive Data Fifo Head Saved - RW */
> +#define E1000_RDFTS    0x02428  /* Diagnostic: Receive Data Fifo Tail Saved - RW */
> +#define E1000_RDFPC    0x02430  /* Diagnostic: Receive Data Fifo Packet Count - RW */
> +
>  #define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
>  #define E1000_RDBAL    0x02800  /* RX Descriptor Base Address Low - RW */
>  #define E1000_RDBAH    0x02804  /* RX Descriptor Base Address High - RW */
> @@ -1208,6 +1215,13 @@
>  #define E1000_82542_TDFT     0x08018
>  #define E1000_82542_FFMT     E1000_FFMT
>  #define E1000_82542_FFVT     E1000_FFVT
> +
> +#define E1000_82542_RDFH     E1000_RDFH
> +#define E1000_82542_RDFT     E1000_RDFT
> +#define E1000_82542_RDFHS    E1000_RDFHS
> +#define E1000_82542_RDFTS    E1000_RDFTS
> +#define E1000_82542_RDFPC    E1000_RDFPC
> +
>  #define E1000_82542_HOST_IF  E1000_HOST_IF
>  #define E1000_82542_IAM         E1000_IAM
>  #define E1000_82542_EEMNGCTL    E1000_EEMNGCTL
> diff -ruN e1000-6.1.16.2.DB/src/e1000_main.c e1000-6.1.16.2.DB-patched/src/e1000_main.c
> --- e1000-6.1.16.2.DB/src/e1000_main.c	2006-01-05 19:23:20.000000000 -0500
> +++ e1000-6.1.16.2.DB-patched/src/e1000_main.c	2006-03-01 12:17:09.000000000 -0500
> @@ -215,6 +215,8 @@
>  static void e1000_set_multi(struct net_device *netdev);
>  static void e1000_update_phy_info(unsigned long data);
>  static void e1000_watchdog(unsigned long data);
> +static void e1000_watchdog_1(struct e1000_adapter *adapter);
> +
>  static void e1000_82547_tx_fifo_stall(unsigned long data);
>  static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
>  static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
> @@ -270,6 +272,16 @@
>  static int e1000_resume(struct pci_dev *pdev);
>  #endif
>  
> +/* For Click polling */
> +static int e1000_tx_pqueue(struct net_device *dev, struct sk_buff *skb);
> +static int e1000_tx_start(struct net_device *dev);
> +static int e1000_rx_refill(struct net_device *dev, struct sk_buff **);
> +static int e1000_tx_eob(struct net_device *dev);
> +static struct sk_buff *e1000_tx_clean(struct net_device *dev);
> +static struct sk_buff *e1000_rx_poll(struct net_device *dev, int *want);
> +static int e1000_poll_on(struct net_device *dev);
> +static int e1000_poll_off(struct net_device *dev);
> +
>  #ifdef CONFIG_NET_POLL_CONTROLLER
>  /* for netdump / net console */
>  static void e1000_netpoll (struct net_device *netdev);
> @@ -286,6 +298,13 @@
>  	.priority	= 0
>  };
>  
> +#undef DEBUG_PRINT
> +#ifdef DEBUG_PRINT
> +static void e1000_print_rx_buffer_info(struct e1000_buffer *bi);
> +static void e1000_print_rx_desc(struct e1000_rx_desc *rx_desc);
> +static void e1000_print_skb(struct sk_buff* skb);
> +#endif
> +
>  /* Exported from other modules */
>  
>  extern void e1000_check_options(struct e1000_adapter *adapter);
> @@ -325,6 +344,7 @@
>  	printk(KERN_INFO "%s - version %s\n",
>  	       e1000_driver_string, e1000_driver_version);
>  
> +        printk(KERN_INFO " w/ Click polling\n");
>  	printk(KERN_INFO "%s\n", e1000_copyright);
>  
>  	ret = pci_module_init(&e1000_driver);
> @@ -598,6 +618,8 @@
>   * and a hardware reset occur.
>   **/
>  
> +#define SHOW_INTERFACE(d) printk("Interface mac_type=%d\n", d->hw.mac_type)
> +
>  static int __devinit
>  e1000_probe(struct pci_dev *pdev,
>              const struct pci_device_id *ent)
> @@ -649,6 +671,7 @@
>  	mmio_start = pci_resource_start(pdev, BAR_0);
>  	mmio_len = pci_resource_len(pdev, BAR_0);
>  
> +	SHOW_INTERFACE(adapter);
>  	adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
>  	if(!adapter->hw.hw_addr) {
>  		err = -EIO;
> @@ -686,6 +709,18 @@
>  	netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
>  	netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid;
>  #endif
> +
> +        /* Click - polling extensions */
> +        netdev->polling = 0;
> +        netdev->rx_poll = e1000_rx_poll;
> +        netdev->rx_refill = e1000_rx_refill;
> +        netdev->tx_queue = e1000_tx_pqueue;
> +        netdev->tx_eob = e1000_tx_eob;
> +        netdev->tx_start = e1000_tx_start;
> +        netdev->tx_clean = e1000_tx_clean;
> +        netdev->poll_off = e1000_poll_off;
> +        netdev->poll_on = e1000_poll_on;
> +
>  #ifdef CONFIG_NET_POLL_CONTROLLER
>  	netdev->poll_controller = e1000_netpoll;
>  #endif
> @@ -757,6 +792,7 @@
>  		DPRINTK(PROBE, ERR, "EEPROM Read Error\n");
>  	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
>  
> +	SHOW_INTERFACE(adapter);
>  	if(!is_valid_ether_addr(netdev->dev_addr)) {
>  		DPRINTK(PROBE, ERR, "Invalid MAC Address\n");
>  		err = -EIO;
> @@ -2296,7 +2332,19 @@
>  static void
>  e1000_watchdog(unsigned long data)
>  {
> -	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
> +  struct e1000_adapter *adapter = (struct e1000_adapter *) data;
> +  if(adapter->netdev->polling){
> +    adapter->do_poll_watchdog = 1;
> +  } else {
> +    e1000_watchdog_1(adapter);
> +  }
> +
> +  mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
> +}
> +
> +static void
> +e1000_watchdog_1(struct e1000_adapter *adapter)
> +{
>  	struct net_device *netdev = adapter->netdev;
>  	struct e1000_tx_ring *txdr = &adapter->tx_ring[0];
>  	uint32_t link;
> @@ -2392,9 +2440,6 @@
>  	 * reset from the other port. Set the appropriate LAA in RAR[0] */
>  	if (adapter->hw.mac_type == e1000_82571 && adapter->hw.laa_is_present)
>  		e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
> -
> -	/* Reset the timer */
> -	mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
>  }
>  
>  #define E1000_TX_FLAGS_CSUM		0x00000001
> @@ -4553,4 +4598,440 @@
>  }
>  #endif
>  
> + 
> +/* Click polling support */
> +
> +static struct sk_buff *
> +e1000_rx_poll(struct net_device *dev, int *want)
> +{
> +  struct e1000_adapter *adapter = dev->priv;
> +  struct pci_dev *pdev = adapter->pdev;
> +  struct e1000_rx_desc *rx_desc;
> +  struct e1000_rx_ring *rx_ring = adapter->rx_ring;
> +  struct sk_buff *skb_head = NULL, **skb;
> +  uint32_t length;
> +  int got, next;
> +
> +  skb = &skb_head;
> +
> +  for( got = 0, next = (rx_ring->next_to_clean + 1) % rx_ring->count;
> +       got < *want && next != rx_ring->next_to_use;
> +       got++, rx_ring->next_to_clean = next,
> +	 next = (rx_ring->next_to_clean + 1) % rx_ring->count) {
> +
> +    int i = rx_ring->next_to_clean;
> +    rx_desc = E1000_RX_DESC(*rx_ring, i);
> +    if(!(rx_desc->status & E1000_RXD_STAT_DD))
> +      break;
> +
> +    pci_unmap_single(pdev, rx_ring->buffer_info[i].dma,
> +		     rx_ring->buffer_info[i].length,
> +		     PCI_DMA_FROMDEVICE);
> +
> +    *skb = rx_ring->buffer_info[i].skb;
> +    rx_ring->buffer_info[i].skb = NULL;
> +    
> +    if(!(rx_desc->status & E1000_RXD_STAT_EOP) ||
> +       (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) {
> +      rx_desc->status = 0;
> +      dev_kfree_skb(*skb);
> +      *skb = NULL;
> +      continue;
> +    }
> +    rx_desc->status = 0;
> +
> +    length = le16_to_cpu(rx_desc->length);
> +    skb_put(*skb, length - CRC_LENGTH);
> +    e1000_rx_checksum(adapter, 
> +		      (uint32_t)(rx_desc->status) | ((uint32_t)(rx_desc->errors) << 24),
> +		      rx_desc->csum, *skb);
> +    skb_pull(*skb, dev->hard_header_len);
> +    
> +    skb = &((*skb)->next);
> +    *skb = NULL;
> +  }
> +
> +  *want = got;
> +
> +  /* 
> +   *  Receive Lockup detection and recovery
> +   */
> +  if (got) {
> +    adapter->rx_state = E1000_RX_STATE_NORMAL;
> +    adapter->rx_normal_jiffies = jiffies + HZ;
> +  } else {
> +    int rdfh;
> +    int rdft;
> +    switch (adapter->rx_state) {
> +    case E1000_RX_STATE_NORMAL:
> +      if (jiffies < adapter->rx_normal_jiffies)
> +        break;
> +      adapter->rx_state = E1000_RX_STATE_QUIET;
> +      adapter->rx_quiet_jiffies = jiffies + HZ;
> +      adapter->prev_rdfh = E1000_READ_REG(&adapter->hw, RDFH);
> +      adapter->prev_rdft = E1000_READ_REG(&adapter->hw, RDFT);
> +      break;
> +    case E1000_RX_STATE_QUIET:
> +      rdfh = E1000_READ_REG(&adapter->hw, RDFH);
> +      rdft = E1000_READ_REG(&adapter->hw, RDFT);
> +      if (adapter->prev_rdfh != rdfh ||
> +          adapter->prev_rdft != rdft ||
> +          adapter->prev_rdfh == adapter->prev_rdft) {
> +        adapter->prev_rdfh = rdfh;
> +        adapter->prev_rdft = rdft;
> +        adapter->rx_quiet_jiffies = jiffies + HZ;
> +        break;
> +      }
> +      if (jiffies < adapter->rx_quiet_jiffies)
> +        break;
> +      /* Fall into the lockup case */
> +    case E1000_RX_STATE_LOCKUP:
> +      /* Receive lockup detected: perform a recovery */
> +      adapter->rx_lockup_recoveries++;
> +      /* taken from e1000_down() */
> +      e1000_reset(adapter);
> +      e1000_clean_tx_ring(adapter, adapter->tx_ring);
> +      e1000_clean_rx_ring(adapter, adapter->rx_ring);
> +      /* taken from e1000_up() */
> +      e1000_set_multi(dev);
> +      e1000_configure_tx(adapter);
> +      e1000_setup_rctl(adapter);
> +      e1000_configure_rx(adapter);
> +      e1000_alloc_rx_buffers(adapter, adapter->rx_ring);
> +      /* reset the lockup detection */
> +      adapter->rx_state = E1000_RX_STATE_NORMAL;
> +      adapter->rx_normal_jiffies = jiffies + HZ;
> +      break;
> +    }
> +  }
> +
> +  return skb_head;
> +}
> +
> +int
> +e1000_rx_refill(struct net_device *dev, struct sk_buff **skbs)
> +{
> +  struct e1000_adapter *adapter = dev->priv;
> +  struct e1000_rx_ring *rx_ring = adapter->rx_ring;
> +  struct pci_dev *pdev = adapter->pdev;
> +  struct e1000_rx_desc *rx_desc;
> +  struct sk_buff *skb;
> +  int next;
> +
> +  /*
> +   * Update statistics counters, check link.
> +   * do_poll_watchdog is set by the timer interrupt e1000_watchdog(),
> +   * but we don't want to do the work in an interrupt (since it may
> +   * happen while polling code is active), so defer it to here.
> +   */
> +  if(adapter->do_poll_watchdog){
> +    adapter->do_poll_watchdog = 0;
> +    e1000_watchdog_1(adapter);
> +  }
> +
> +  if (!netif_carrier_ok(dev))
> +    return 0;
> +
> +  if(skbs == 0)
> +    return E1000_DESC_UNUSED(rx_ring);
> +
> +  for( next = (rx_ring->next_to_use + 1) % rx_ring->count;
> +       next != rx_ring->next_to_clean;
> +       rx_ring->next_to_use = next,
> +	 next = (rx_ring->next_to_use + 1) % rx_ring->count ) {
> +    int i = rx_ring->next_to_use;
> +    if(rx_ring->buffer_info[i].skb != NULL)
> +      break;
> +    
> +    if(!(skb = *skbs))
> +      break;
> +    *skbs = skb->next;
> +    skb->next = NULL;
> +    skb->dev = dev;
> +    
> +    rx_ring->buffer_info[i].skb = skb;
> +    rx_ring->buffer_info[i].length = adapter->rx_buffer_len;
> +    rx_ring->buffer_info[i].dma =
> +      pci_map_single(pdev,
> +		     skb->data,
> +		     adapter->rx_buffer_len,
> +		     PCI_DMA_FROMDEVICE);
> +
> +    rx_desc = E1000_RX_DESC(*rx_ring, i);
> +    rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma);
> +    
> +    /* Intel documnetation says: "Software adds receive descriptors by
> +     * writing the tail pointer with the index of the entry beyond the
> +     * last valid descriptor." (ref 11337 p 27) */
> +
> +    E1000_WRITE_REG(&adapter->hw, RDT, next);
> +  }
> +  
> +  return E1000_DESC_UNUSED(adapter->rx_ring);
> +}
> +
> +static int
> +e1000_tx_pqueue(struct net_device *netdev, struct sk_buff *skb)
> +{
> +  /*
> +   * This function is just a streamlined version of
> +   * return e1000_xmit_frame(skb, netdev);
> +   */
> +
> +  struct e1000_adapter *adapter = netdev->priv;
> +  struct pci_dev *pdev = adapter->pdev;
> +  struct e1000_tx_desc *tx_desc;
> +  int i, len, offset, txd_needed;
> +  uint32_t txd_upper, txd_lower;
> +  unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
> +
> +  if(!netif_carrier_ok(netdev)) {
> +    netif_stop_queue(netdev);
> +    return -1;
> +  }
> +
> +  txd_needed = TXD_USE_COUNT(skb->len, max_txd_pwr);
> +
> +  /* make sure there are enough Tx descriptors available in the ring */
> +  if(E1000_DESC_UNUSED(adapter->tx_ring) <= (txd_needed + 1)) {
> +    adapter->net_stats.tx_dropped++;
> +    netif_stop_queue(netdev);
> +    return -1;
> +  }
> +
> +  txd_upper = 0;
> +  txd_lower = adapter->txd_cmd;
> +
> +  if(e1000_tx_csum(adapter, adapter->tx_ring, skb)){
> +    txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
> +    txd_upper |= E1000_TXD_POPTS_TXSM << 8;
> +  }
> +
> +  i = adapter->tx_ring->next_to_use;
> +  tx_desc = E1000_TX_DESC(*(adapter->tx_ring), i);
> +
> +  len = skb->len;
> +  offset = 0;
> +
> +  adapter->tx_ring->buffer_info[i].length = len;
> +  adapter->tx_ring->buffer_info[i].dma =
> +    pci_map_page(pdev, virt_to_page(skb->data + offset),
> +                 (unsigned long) (skb->data + offset) & ~PAGE_MASK, len,
> +                 PCI_DMA_TODEVICE);
> +
> +  tx_desc->buffer_addr = cpu_to_le64(adapter->tx_ring->buffer_info[i].dma);
> +  tx_desc->lower.data = cpu_to_le32(txd_lower | len);
> +  tx_desc->upper.data = cpu_to_le32(txd_upper);
> +
> +    /* EOP and SKB pointer go with the last fragment */
> +  tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
> +  adapter->tx_ring->buffer_info[i].skb = skb;
> +
> +  i = i + 1;
> +  if(i >= adapter->tx_ring->count)
> +    i = 0;
> +
> +  /* Move the HW Tx Tail Pointer */
> +  adapter->tx_ring->next_to_use = i;
> +
> +  netdev->trans_start = jiffies;
> +
> +  return 0;
> +}
> +
> +static struct sk_buff *
> +e1000_tx_clean(struct net_device *netdev)
> +{
> +  /*
> +   * This function is a streamlined version of
> +   * return e1000_clean_tx_irq(adapter, 1);
> +   */
> +
> +  struct e1000_adapter *adapter = netdev->priv;
> +  struct pci_dev *pdev = adapter->pdev;
> +  int i;
> +  struct e1000_tx_desc *tx_desc;
> +  struct sk_buff *skb_head, *skb_last;
> +
> +  skb_head = skb_last = 0;
> +
> +  i = adapter->tx_ring->next_to_clean;
> +  tx_desc = E1000_TX_DESC(*(adapter->tx_ring), i);
> +
> +  while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
> +    if(adapter->tx_ring->buffer_info[i].dma != 0) {
> +      pci_unmap_page(pdev, adapter->tx_ring->buffer_info[i].dma,
> +                     adapter->tx_ring->buffer_info[i].length,
> +                     PCI_DMA_TODEVICE);
> +      adapter->tx_ring->buffer_info[i].dma = 0;
> +    }
> +
> +    if(adapter->tx_ring->buffer_info[i].skb != NULL) {
> +      struct sk_buff *skb = adapter->tx_ring->buffer_info[i].skb;
> +      if (skb_head == 0) {
> +        skb_head = skb;
> +        skb_last = skb;
> +        skb_last->next = NULL;
> +      } else {
> +        skb_last->next = skb;
> +        skb->next = NULL;
> +        skb_last = skb;
> +      }
> +      adapter->tx_ring->buffer_info[i].skb = NULL;
> +    }
> +    
> +    i = (i + 1) % adapter->tx_ring->count;
> +
> +    tx_desc->upper.data = 0;
> +    tx_desc = E1000_TX_DESC(*(adapter->tx_ring), i);
> +  }
> +
> +  adapter->tx_ring->next_to_clean = i;
> +
> +  if(netif_queue_stopped(netdev) &&
> +     (E1000_DESC_UNUSED(adapter->tx_ring) > E1000_TX_QUEUE_WAKE)) {
> +    netif_start_queue(netdev);
> +  }
> +
> +  return skb_head;
> +}
> +
> +static int
> +e1000_poll_on(struct net_device *dev)
> +{
> +  struct e1000_adapter *adapter = dev->priv;
> +  unsigned long flags;
> +
> +  if (!dev->polling) {
> +    printk("e1000_poll_on\n");
> +
> +		local_save_flags(flags);
> +		local_irq_disable();
> +
> +
> +    dev->polling = 2;
> +
> +		e1000_irq_disable(adapter);
> +
> +		local_irq_restore(flags);
> +  }
> +
> +  return 0;
> +}
> +
> +static int
> +e1000_poll_off(struct net_device *dev)
> +{
> +  struct e1000_adapter *adapter = dev->priv;
> +
> +  if(dev->polling > 0){
> +    dev->polling = 0;
> +    e1000_irq_enable(adapter);
> +    printk("e1000_poll_off\n");
> +  }
> +
> +  return 0;
> +}
> +
> +static int
> +e1000_tx_eob(struct net_device *dev)
> +{
> +  struct e1000_adapter *adapter = dev->priv;
> +  E1000_WRITE_REG(&adapter->hw, TDT, adapter->tx_ring->next_to_use);
> +  return 0;
> +}
> +
> +static int
> +e1000_tx_start(struct net_device *dev)
> +{
> +  /*   printk("e1000_tx_start called\n"); */
> +  e1000_tx_eob(dev);
> +  return 0;
> +}
> +
> +#ifdef DEBUG_PRINT
> +
> +/* debugging tools */
> +
> +#define PRT_HEX(str,value) printk("skb->%-10s = 0x%08x\n", str, (unsigned int)value);
> +#define PRT_DEC(str,value) printk("skb->%-10s = %d\n", str, value);
> +void e1000_print_skb(struct sk_buff* skb) 
> +{
> +  int i;
> +  printk("========================\n");
> +  printk("skb           = 0x%08x\n", (unsigned int)skb);
> +  PRT_HEX("next",     skb->next);
> +  PRT_HEX("prev",     skb->prev);
> +  PRT_DEC("len",      skb->len);
> +  PRT_HEX("data",     skb->data);
> +  PRT_HEX("tail",     skb->tail);
> +  PRT_HEX("dev",      skb->dev);
> +  PRT_DEC("cloned",   skb->cloned);
> +  PRT_DEC("pkt_type", skb->pkt_type);
> +  PRT_DEC("users",    skb->users);
> +  PRT_DEC("truesize", skb->truesize);
> +  PRT_HEX("head",     skb->head);
> +  PRT_HEX("end",      skb->end);
> +  PRT_HEX("list",     skb->list);
> +  PRT_DEC("data_len", skb->data_len);
> +  PRT_HEX("csum",     skb->csum);
> +  PRT_HEX("skb_shinfo", skb_shinfo(skb));
> +  PRT_HEX("skb_shinfo->frag_list", skb_shinfo(skb)->frag_list);
> +  PRT_DEC("skb_shinfo->nr_frags", skb_shinfo(skb)->nr_frags);
> +  PRT_DEC("skb_shinfo->dataref", skb_shinfo(skb)->dataref);
> +  for (i=0; i<skb_shinfo(skb)->nr_frags && i<8; ++i)
> +    printk("skb->skb_shinfo->frags[%d]   = 0x%08x\n", i, skb_shinfo(skb)->frags[i]);
> +}
> +
> +void e1000_print_rx_desc(struct e1000_rx_desc *rx_desc)
> +{
> +  printk("rx_desc = 0x%08x\n", rx_desc);
> +  printk("rx_desc->buffer_addr = 0x%08x\n", rx_desc->buffer_addr);
> +  printk("rx_desc->length      = %d\n",     rx_desc->length);
> +  printk("rx_desc->csum        = 0x%04x\n", rx_desc->csum);
> +  printk("rx_desc->status      = 0x%02x\n", rx_desc->status);
> +  printk("rx_desc->errors      = 0x%02x\n", rx_desc->errors);
> +  printk("rx_desc->special     = 0x%04x\n", rx_desc->special);
> +}
> +
> +void e1000_print_rx_buffer_info(struct e1000_buffer *bi)
> +{
> +  printk("buffer_info             = 0x%08x\n", bi);
> +  printk("buffer_info->skb        = 0x%08x\n", bi->skb);
> +  printk("buffer_info->length     = 0x%08x (%d)\n", bi->length, bi->length);
> +  printk("buffer_info->time_stamp = 0x%08x\n", bi->time_stamp);
> +}
> +
> +void e1000_print_rx_desc_ring(struct e1000_desc_ring *desc_ring)
> +{
> +  int i;
> +  struct e1000_buffer *bi;
> +  struct e1000_rx_desc *desc;
> +
> +  printk("\n");
> +  printk("desc_ring                = 0x%08x\n", desc_ring);
> +  printk("desc_ring->desc          = 0x%08x\n", desc_ring->desc);
> +  printk("desc_ring->dma           = 0x%08x\n", desc_ring->dma);
> +  printk("desc_ring->size          = 0x%08x (%d)\n", desc_ring->size, desc_ring->size);
> +  printk("desc_ring->count         = 0x%08x (%d)\n", desc_ring->count, desc_ring->count);
> +  printk("desc_ring->next_to_use   = 0x%08x (%d)\n", desc_ring->next_to_use,
> desc_ring->next_to_use);
> +  printk("desc_ring->next_to_clean = 0x%08x (%d)\n", desc_ring->next_to_clean,
> desc_ring->next_to_clean);
> +  printk("desc_ring->buffer_info   = 0x%08x\n", desc_ring->buffer_info);
> +
> +  printk("\n");
> +  bi = desc_ring->buffer_info;
> +  desc = desc_ring->desc;
> +  for (i=0; i<desc_ring->count; ++i) {
> +    printk("===================================================== desc/buffer_info # %d\n", i);
> +    e1000_print_rx_buffer_info(bi++);
> +    e1000_print_rx_desc(desc++);
> +  }
> +
> +}
> +
> +#undef PRT_HEX
> +#undef PRT_DEC
> +
> +#endif
> +
>  /* e1000_main.c */
> diff -ruN e1000-6.1.16.2.DB/src/e1000_param.c e1000-6.1.16.2.DB-patched/src/e1000_param.c
> --- e1000-6.1.16.2.DB/src/e1000_param.c	2006-01-05 19:23:20.000000000 -0500
> +++ e1000-6.1.16.2.DB-patched/src/e1000_param.c	2006-03-01 12:11:50.000000000 -0500
> @@ -410,7 +410,7 @@
>  			.type = list_option,
>  			.name = "Flow Control",
>  			.err  = "reading default settings from EEPROM",
> -			.def  = e1000_fc_default,
> +			def:  e1000_fc_none, /* RTM, was e1000_fc_default */
>  			.arg  = { .l = { .nr = ARRAY_SIZE(fc_list),
>  					 .p = fc_list }}
>  		};
> > _______________________________________________
> click mailing list
> click at amsterdam.lcs.mit.edu
> https://amsterdam.lcs.mit.edu/mailman/listinfo/click
> 


__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 


More information about the click mailing list