[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