Author: jfv
Date: Tue Nov 23 22:12:02 2010
New Revision: 215781
URL: http://svn.freebsd.org/changeset/base/215781

Log:
  - New 82580 devices supported
  - Fixes from John Baldwin: vlan shadow tables made per/interface,
    make vlan hw setup only happen when capability enabled, and
    finally, make a tuneable interrupt rate. Thanks John!
  - Tweaked watchdog handling to avoid any false positives, now
    detection is in the TX clean path, with only the final check
    and init happening in the local timer.
  - limit queues to 8 for all devices, with 82576 or 82580 on
    larger machines it can get greater than this, and it seems
    mostly a resource waste to do so. Even 8 might be high but
    it can be manually reduced.
  - use 2k, 4k and now 9k clusters based on the MTU size.
  - rework the igb_refresh_mbuf() code, its important to
    make sure the descriptor is rewritten even when reusing
    mbufs since writeback clobbers things.
  
  MFC: in a few days, this delta needs to get to 8.2

Modified:
  head/sys/dev/e1000/if_igb.c
  head/sys/dev/e1000/if_igb.h

Modified: head/sys/dev/e1000/if_igb.c
==============================================================================
--- head/sys/dev/e1000/if_igb.c Tue Nov 23 22:07:10 2010        (r215780)
+++ head/sys/dev/e1000/if_igb.c Tue Nov 23 22:12:02 2010        (r215781)
@@ -99,7 +99,7 @@ int   igb_display_debug_stats = 0;
 /*********************************************************************
  *  Driver version:
  *********************************************************************/
-char igb_driver_version[] = "version - 2.0.4";
+char igb_driver_version[] = "version - 2.0.7";
 
 
 /*********************************************************************
@@ -137,6 +137,10 @@ static igb_vendor_info_t igb_vendor_info
        { 0x8086, E1000_DEV_ID_82580_SGMII,     PCI_ANY_ID, PCI_ANY_ID, 0},
        { 0x8086, E1000_DEV_ID_82580_COPPER_DUAL,
                                                PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_82580_QUAD_FIBER,
+                                               PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_DH89XXCC_SERDES, PCI_ANY_ID, PCI_ANY_ID, 0},
+       { 0x8086, E1000_DEV_ID_DH89XXCC_SGMII,  PCI_ANY_ID, PCI_ANY_ID, 0},
        /* required last entry */
        { 0, 0, 0, 0, 0}
 };
@@ -307,11 +311,19 @@ static int igb_enable_msix = 1;
 TUNABLE_INT("hw.igb.enable_msix", &igb_enable_msix);
 
 /*
- * Header split has seemed to be beneficial in
- * many circumstances tested, however there have
- * been some stability issues, so the default is
- * off. 
- */
+** Tuneable Interrupt rate
+*/
+static int igb_max_interrupt_rate = 8000;
+TUNABLE_INT("hw.igb.max_interrupt_rate", &igb_max_interrupt_rate);
+
+/*
+** Header split causes the packet header to
+** be dma'd to a seperate mbuf from the payload.
+** this can have memory alignment benefits. But
+** another plus is that small packets often fit
+** into the header and thus use no cluster. Its
+** a very workload dependent type feature.
+*/
 static bool igb_header_split = FALSE;
 TUNABLE_INT("hw.igb.hdr_split", &igb_header_split);
 
@@ -330,15 +342,6 @@ TUNABLE_INT("hw.igb.rx_process_limit", &
 static int igb_fc_setting = e1000_fc_full;
 TUNABLE_INT("hw.igb.fc_setting", &igb_fc_setting);
 
-/*
-** Shadow VFTA table, this is needed because
-** the real filter table gets cleared during
-** a soft reset and the driver needs to be able
-** to repopulate it.
-*/
-static u32 igb_shadow_vfta[IGB_VFTA_SIZE];
-
-
 /*********************************************************************
  *  Device identification routine
  *
@@ -818,7 +821,7 @@ igb_start_locked(struct tx_ring *txr, st
 
                /* Set watchdog on */
                txr->watchdog_time = ticks;
-               txr->watchdog_check = TRUE;
+               txr->queue_status = IGB_QUEUE_WORKING;
        }
 }
  
@@ -922,7 +925,7 @@ igb_mq_start_locked(struct ifnet *ifp, s
        }
        if (enq > 0) {
                /* Set the watchdog */
-               txr->watchdog_check = TRUE;
+               txr->queue_status = IGB_QUEUE_WORKING;
                txr->watchdog_time = ticks;
        }
        return (err);
@@ -1049,6 +1052,11 @@ igb_ioctl(struct ifnet *ifp, u_long comm
                }
                break;
        case SIOCSIFMEDIA:
+               /*
+               ** As the speed/duplex settings are being
+               ** changed, we need toreset the PHY.
+               */
+               adapter->hw.phy.reset_disable = FALSE;
                /* Check SOL/IDER usage */
                IGB_CORE_LOCK(adapter);
                if (e1000_check_reset_block(&adapter->hw)) {
@@ -1161,19 +1169,6 @@ igb_init_locked(struct adapter *adapter)
 
        E1000_WRITE_REG(&adapter->hw, E1000_VET, ETHERTYPE_VLAN);
 
-        /* Use real VLAN Filter support? */
-       if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
-               if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
-                       /* Use real VLAN Filter support */
-                       igb_setup_vlan_hw_support(adapter);
-               else {
-                       u32 ctrl;
-                       ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL);
-                       ctrl |= E1000_CTRL_VME;
-                       E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl);
-               }
-       }
-                                
        /* Set hardware offload abilities */
        ifp->if_hwassist = 0;
        if (ifp->if_capenable & IFCAP_TXCSUM) {
@@ -1201,10 +1196,12 @@ igb_init_locked(struct adapter *adapter)
        ** Figure out the desired mbuf pool
        ** for doing jumbo/packetsplit
        */
-       if (ifp->if_mtu > ETHERMTU)
+       if (adapter->max_frame_size <= 2048)
+               adapter->rx_mbuf_sz = MCLBYTES;
+       else if (adapter->max_frame_size <= 4096)
                adapter->rx_mbuf_sz = MJUMPAGESIZE;
        else
-               adapter->rx_mbuf_sz = MCLBYTES;
+               adapter->rx_mbuf_sz = MJUM9BYTES;
 
        /* Prepare receive descriptors and buffers */
        if (igb_setup_receive_structures(adapter)) {
@@ -1213,6 +1210,19 @@ igb_init_locked(struct adapter *adapter)
        }
        igb_initialize_receive_units(adapter);
 
+        /* Use real VLAN Filter support? */
+       if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) {
+               if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
+                       /* Use real VLAN Filter support */
+                       igb_setup_vlan_hw_support(adapter);
+               else {
+                       u32 ctrl;
+                       ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL);
+                       ctrl |= E1000_CTRL_VME;
+                       E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl);
+               }
+       }
+                                
        /* Don't lose promiscuous settings */
        igb_set_promisc(adapter);
 
@@ -1225,9 +1235,6 @@ igb_init_locked(struct adapter *adapter)
        if (adapter->msix > 1) /* Set up queue routing */
                igb_configure_queues(adapter);
 
-       /* Set up VLAN tag offload and filter */
-       igb_setup_vlan_hw_support(adapter);
-
        /* this clears any pending interrupts */
        E1000_READ_REG(&adapter->hw, E1000_ICR);
 #ifdef DEVICE_POLLING
@@ -1627,11 +1634,6 @@ igb_media_change(struct ifnet *ifp)
                device_printf(adapter->dev, "Unsupported media type\n");
        }
 
-       /* As the speed/duplex settings my have changed we need to
-        * reset the PHY.
-        */
-       adapter->hw.phy.reset_disable = FALSE;
-
        igb_init_locked(adapter);
        IGB_CORE_UNLOCK(adapter);
 
@@ -1947,18 +1949,9 @@ igb_local_timer(void *arg)
         /*
         ** Watchdog: check for time since any descriptor was cleaned
         */
-       for (int i = 0; i < adapter->num_queues; i++, txr++) {
-               IGB_TX_LOCK(txr);
-               if ((txr->watchdog_check == FALSE) ||
-                   (txr->tx_avail == adapter->num_tx_desc)) {
-                       IGB_TX_UNLOCK(txr);
-                       continue;
-               }
-               if ((ticks - txr->watchdog_time) > IGB_WATCHDOG)
+       for (int i = 0; i < adapter->num_queues; i++, txr++)
+               if (txr->queue_status == IGB_QUEUE_HUNG) 
                        goto timeout;
-               IGB_TX_UNLOCK(txr);
-       }
-
 out:
        callout_reset(&adapter->timer, hz, igb_local_timer, adapter);
        return;
@@ -1973,7 +1966,6 @@ timeout:
             txr->me, txr->tx_avail, txr->next_to_clean);
        adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
        adapter->watchdog_events++;
-       IGB_TX_UNLOCK(txr);
        igb_init_locked(adapter);
 }
 
@@ -2037,7 +2029,7 @@ igb_update_link_status(struct adapter *a
                if_link_state_change(ifp, LINK_STATE_DOWN);
                /* Turn off watchdogs */
                for (int i = 0; i < adapter->num_queues; i++, txr++)
-                       txr->watchdog_check = FALSE;
+                       txr->queue_status = IGB_QUEUE_IDLE;
        }
 }
 
@@ -2069,7 +2061,7 @@ igb_stop(void *arg)
        /* Unarm watchdog timer. */
        for (int i = 0; i < adapter->num_queues; i++, txr++) {
                IGB_TX_LOCK(txr);
-               txr->watchdog_check = FALSE;
+               txr->queue_status = IGB_QUEUE_IDLE;
                IGB_TX_UNLOCK(txr);
        }
 
@@ -2280,8 +2272,7 @@ igb_configure_queues(struct adapter *ada
 {
        struct  e1000_hw        *hw = &adapter->hw;
        struct  igb_queue       *que;
-       u32                     tmp, ivar = 0;
-       u32                     newitr = IGB_DEFAULT_ITR;
+       u32                     tmp, ivar = 0, newitr = 0;
 
        /* First turn on RSS capability */
        if (adapter->hw.mac.type > e1000_82575)
@@ -2398,6 +2389,9 @@ igb_configure_queues(struct adapter *ada
        }
 
        /* Set the starting interrupt rate */
+       if (igb_max_interrupt_rate > 0)
+               newitr = (4000000 / igb_max_interrupt_rate) & 0x7FFC;
+
         if (hw->mac.type == e1000_82575)
                 newitr |= newitr << 16;
         else
@@ -2509,6 +2503,8 @@ igb_setup_msix(struct adapter *adapter)
        /* Manual override */
        if (igb_num_queues != 0)
                queues = igb_num_queues;
+       if (queues > 8)  /* max queues */
+               queues = 8;
 
        /* Can have max of 4 queues on 82575 */
        if ((adapter->hw.mac.type == e1000_82575) && (queues > 4))
@@ -2636,7 +2632,7 @@ igb_reset(struct adapter *adapter)
        fc->send_xon = TRUE;
 
        /* Set Flow control, use the tunable location if sane */
-       if ((igb_fc_setting >= 0) || (igb_fc_setting < 4))
+       if ((igb_fc_setting >= 0) && (igb_fc_setting < 4))
                fc->requested_mode = igb_fc_setting;
        else
                fc->requested_mode = e1000_fc_none;
@@ -2728,10 +2724,11 @@ igb_setup_interface(device_t dev, struct
        ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM;
        ifp->if_capabilities |= IFCAP_TSO4;
        ifp->if_capabilities |= IFCAP_JUMBO_MTU;
-       if (igb_header_split)
-               ifp->if_capabilities |= IFCAP_LRO;
-
        ifp->if_capenable = ifp->if_capabilities;
+
+       /* Don't enable LRO by default */
+       ifp->if_capabilities |= IFCAP_LRO;
+
 #ifdef DEVICE_POLLING
        ifp->if_capabilities |= IFCAP_POLLING;
 #endif
@@ -3172,7 +3169,7 @@ igb_initialize_transmit_units(struct ada
                    E1000_READ_REG(hw, E1000_TDBAL(i)),
                    E1000_READ_REG(hw, E1000_TDLEN(i)));
 
-               txr->watchdog_check = FALSE;
+               txr->queue_status = IGB_QUEUE_IDLE;
 
                txdctl |= IGB_TX_PTHRESH;
                txdctl |= IGB_TX_HTHRESH << 8;
@@ -3184,14 +3181,14 @@ igb_initialize_transmit_units(struct ada
        if (adapter->hw.mac.type == e1000_vfadapt)
                return;
 
+       e1000_config_collision_dist(hw);
+
        /* Program the Transmit Control Register */
        tctl = E1000_READ_REG(hw, E1000_TCTL);
        tctl &= ~E1000_TCTL_CT;
        tctl |= (E1000_TCTL_PSP | E1000_TCTL_RTLC | E1000_TCTL_EN |
                   (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT));
 
-       e1000_config_collision_dist(hw);
-
        /* This write will effectively turn on the transmit unit. */
        E1000_WRITE_REG(hw, E1000_TCTL, tctl);
 }
@@ -3500,16 +3497,19 @@ static bool
 igb_txeof(struct tx_ring *txr)
 {
        struct adapter  *adapter = txr->adapter;
-        int first, last, done;
+        int first, last, done, processed;
         struct igb_tx_buffer *tx_buffer;
         struct e1000_tx_desc   *tx_desc, *eop_desc;
        struct ifnet   *ifp = adapter->ifp;
 
        IGB_TX_LOCK_ASSERT(txr);
 
-        if (txr->tx_avail == adapter->num_tx_desc)
+        if (txr->tx_avail == adapter->num_tx_desc) {
+               txr->queue_status = IGB_QUEUE_IDLE;
                 return FALSE;
+       }
 
+       processed = 0;
         first = txr->next_to_clean;
         tx_desc = &txr->tx_base[first];
         tx_buffer = &txr->tx_buffers[first];
@@ -3536,6 +3536,7 @@ igb_txeof(struct tx_ring *txr)
                        tx_desc->lower.data = 0;
                        tx_desc->buffer_addr = 0;
                        ++txr->tx_avail;
+                       ++processed;
 
                        if (tx_buffer->m_head) {
                                txr->bytes +=
@@ -3575,6 +3576,15 @@ igb_txeof(struct tx_ring *txr)
 
         txr->next_to_clean = first;
 
+       /*
+       ** Watchdog calculation, we know there's
+       ** work outstanding or the first return
+       ** would have been taken, so none processed
+       ** for too long indicates a hang.
+       */
+       if ((!processed) && ((ticks - txr->watchdog_time) > IGB_WATCHDOG))
+               txr->queue_status = IGB_QUEUE_HUNG;
+
         /*
          * If we have enough room, clear IFF_DRV_OACTIVE
          * to tell the stack that it is OK to send packets.
@@ -3583,7 +3593,7 @@ igb_txeof(struct tx_ring *txr)
                 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
                /* All clean, turn off the watchdog */
                 if (txr->tx_avail == adapter->num_tx_desc) {
-                       txr->watchdog_check = FALSE;
+                       txr->queue_status = IGB_QUEUE_IDLE;
                        return (FALSE);
                }
         }
@@ -3615,51 +3625,59 @@ igb_refresh_mbufs(struct rx_ring *rxr, i
        cleaned = -1; /* Signify no completions */
        while (i != limit) {
                rxbuf = &rxr->rx_buffers[i];
-               if ((rxbuf->m_head == NULL) && (rxr->hdr_split)) {
+               /* No hdr mbuf used with header split off */
+               if (rxr->hdr_split == FALSE)
+                       goto no_split;
+               if (rxbuf->m_head == NULL) {
                        mh = m_gethdr(M_DONTWAIT, MT_DATA);
                        if (mh == NULL)
                                goto update;
-                       mh->m_pkthdr.len = mh->m_len = MHLEN;
-                       mh->m_len = MHLEN;
-                       mh->m_flags |= M_PKTHDR;
-                       m_adj(mh, ETHER_ALIGN);
-                       /* Get the memory mapping */
-                       error = bus_dmamap_load_mbuf_sg(rxr->htag,
-                           rxbuf->hmap, mh, hseg, &nsegs, BUS_DMA_NOWAIT);
-                       if (error != 0) {
-                               printf("GET BUF: dmamap load"
-                                   " failure - %d\n", error);
-                               m_free(mh);
-                               goto update;
-                       }
-                       rxbuf->m_head = mh;
-                       bus_dmamap_sync(rxr->htag, rxbuf->hmap,
-                           BUS_DMASYNC_PREREAD);
-                       rxr->rx_base[i].read.hdr_addr =
-                           htole64(hseg[0].ds_addr);
-               }
+               } else
+                       mh = rxbuf->m_head;
 
+               mh->m_pkthdr.len = mh->m_len = MHLEN;
+               mh->m_len = MHLEN;
+               mh->m_flags |= M_PKTHDR;
+               /* Get the memory mapping */
+               error = bus_dmamap_load_mbuf_sg(rxr->htag,
+                   rxbuf->hmap, mh, hseg, &nsegs, BUS_DMA_NOWAIT);
+               if (error != 0) {
+                       printf("Refresh mbufs: hdr dmamap load"
+                           " failure - %d\n", error);
+                       m_free(mh);
+                       rxbuf->m_head = NULL;
+                       goto update;
+               }
+               rxbuf->m_head = mh;
+               bus_dmamap_sync(rxr->htag, rxbuf->hmap,
+                   BUS_DMASYNC_PREREAD);
+               rxr->rx_base[i].read.hdr_addr =
+                   htole64(hseg[0].ds_addr);
+no_split:
                if (rxbuf->m_pack == NULL) {
                        mp = m_getjcl(M_DONTWAIT, MT_DATA,
                            M_PKTHDR, adapter->rx_mbuf_sz);
                        if (mp == NULL)
                                goto update;
-                       mp->m_pkthdr.len = mp->m_len = adapter->rx_mbuf_sz;
-                       /* Get the memory mapping */
-                       error = bus_dmamap_load_mbuf_sg(rxr->ptag,
-                           rxbuf->pmap, mp, pseg, &nsegs, BUS_DMA_NOWAIT);
-                       if (error != 0) {
-                               printf("GET BUF: dmamap load"
-                                   " failure - %d\n", error);
-                               m_free(mp);
-                               goto update;
-                       }
-                       rxbuf->m_pack = mp;
-                       bus_dmamap_sync(rxr->ptag, rxbuf->pmap,
-                           BUS_DMASYNC_PREREAD);
-                       rxr->rx_base[i].read.pkt_addr =
-                           htole64(pseg[0].ds_addr);
+               } else
+                       mp = rxbuf->m_pack;
+
+               mp->m_pkthdr.len = mp->m_len = adapter->rx_mbuf_sz;
+               /* Get the memory mapping */
+               error = bus_dmamap_load_mbuf_sg(rxr->ptag,
+                   rxbuf->pmap, mp, pseg, &nsegs, BUS_DMA_NOWAIT);
+               if (error != 0) {
+                       printf("Refresh mbufs: payload dmamap load"
+                           " failure - %d\n", error);
+                       m_free(mp);
+                       rxbuf->m_pack = NULL;
+                       goto update;
                }
+               rxbuf->m_pack = mp;
+               bus_dmamap_sync(rxr->ptag, rxbuf->pmap,
+                   BUS_DMASYNC_PREREAD);
+               rxr->rx_base[i].read.pkt_addr =
+                   htole64(pseg[0].ds_addr);
 
                cleaned = i;
                /* Calculate next index */
@@ -3722,9 +3740,9 @@ igb_allocate_receive_buffers(struct rx_r
                                   BUS_SPACE_MAXADDR,   /* lowaddr */
                                   BUS_SPACE_MAXADDR,   /* highaddr */
                                   NULL, NULL,          /* filter, filterarg */
-                                  MJUMPAGESIZE,        /* maxsize */
+                                  MJUM9BYTES,          /* maxsize */
                                   1,                   /* nsegments */
-                                  MJUMPAGESIZE,        /* maxsegsize */
+                                  MJUM9BYTES,          /* maxsegsize */
                                   0,                   /* flags */
                                   NULL,                /* lockfunc */
                                   NULL,                /* lockfuncarg */
@@ -3826,7 +3844,7 @@ igb_setup_receive_ring(struct rx_ring *r
                rxr->hdr_split = TRUE;
 
         /* Now replenish the ring mbufs */
-       for (int j = 0; j != adapter->num_rx_desc; ++j) {
+       for (int j = 0; j < adapter->num_rx_desc; ++j) {
                struct mbuf     *mh, *mp;
 
                rxbuf = &rxr->rx_buffers[j];
@@ -3897,8 +3915,8 @@ skip_head:
        ** are undesireable in similar setups.
        */
        if (ifp->if_capenable & IFCAP_LRO) {
-               int err = tcp_lro_init(lro);
-               if (err) {
+               error = tcp_lro_init(lro);
+               if (error) {
                        device_printf(dev, "LRO Initialization failed!\n");
                        goto fail;
                }
@@ -3940,7 +3958,9 @@ fail:
         */
        for (int j = 0; j > i; ++j) {
                rxr = &adapter->rx_rings[i];
+               IGB_RX_LOCK(rxr);
                igb_free_receive_ring(rxr);
+               IGB_RX_UNLOCK(rxr);
        }
 
        return (ENOBUFS);
@@ -3983,9 +4003,13 @@ igb_initialize_receive_units(struct adap
        */
        if (ifp->if_mtu > ETHERMTU) {
                rctl |= E1000_RCTL_LPE;
-               srrctl |= 4096 >> E1000_SRRCTL_BSIZEPKT_SHIFT;
-               rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX;
-
+               if (adapter->rx_mbuf_sz == MJUMPAGESIZE) {
+                       srrctl |= 4096 >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+                       rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX;
+               } else if (adapter->rx_mbuf_sz > MJUMPAGESIZE) {
+                       srrctl |= 8192 >> E1000_SRRCTL_BSIZEPKT_SHIFT;
+                       rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX;
+               }
                /* Set maximum packet len */
                psize = adapter->max_frame_size;
                /* are we on a vlan? */
@@ -4194,11 +4218,11 @@ igb_free_receive_buffers(struct rx_ring 
 static __inline void
 igb_rx_discard(struct rx_ring *rxr, int i)
 {
-       struct adapter          *adapter = rxr->adapter;
        struct igb_rx_buf       *rbuf;
-       struct mbuf             *mh, *mp;
 
        rbuf = &rxr->rx_buffers[i];
+
+       /* Partially received? Free the chain */
        if (rxr->fmp != NULL) {
                rxr->fmp->m_flags |= M_PKTHDR;
                m_freem(rxr->fmp);
@@ -4206,19 +4230,23 @@ igb_rx_discard(struct rx_ring *rxr, int 
                rxr->lmp = NULL;
        }
 
-       mh = rbuf->m_head;
-       mp = rbuf->m_pack;
+       /*
+       ** With advanced descriptors the writeback
+       ** clobbers the buffer addrs, so its easier
+       ** to just free the existing mbufs and take
+       ** the normal refresh path to get new buffers
+       ** and mapping.
+       */
+       if (rbuf->m_head) {
+               m_free(rbuf->m_head);
+               rbuf->m_head = NULL;
+       }
 
-       /* Reuse loaded DMA map and just update mbuf chain */
-       if (mh) {       /* with no hdr split would be null */
-               mh->m_len = MHLEN;
-               mh->m_flags |= M_PKTHDR;
-               mh->m_next = NULL;
+       if (rbuf->m_pack) {
+               m_free(rbuf->m_pack);
+               rbuf->m_pack = NULL;
        }
 
-       mp->m_len = mp->m_pkthdr.len = adapter->rx_mbuf_sz;
-       mp->m_data = mp->m_ext.ext_buf;
-       mp->m_next = NULL;
        return;
 }
 
@@ -4333,10 +4361,9 @@ igb_rxeof(struct igb_queue *que, int cou
                            E1000_RXDADV_HDRBUFLEN_SHIFT;
                        if (hlen > IGB_HDR_BUF)
                                hlen = IGB_HDR_BUF;
-                       /* Handle the header mbuf */
                        mh = rxr->rx_buffers[i].m_head;
                        mh->m_len = hlen;
-                       /* clear buf info for refresh */
+                       /* clear buf pointer for refresh */
                        rxbuf->m_head = NULL;
                        /*
                        ** Get the payload length, this
@@ -4347,7 +4374,7 @@ igb_rxeof(struct igb_queue *que, int cou
                                mp = rxr->rx_buffers[i].m_pack;
                                mp->m_len = plen;
                                mh->m_next = mp;
-                               /* clear buf info for refresh */
+                               /* clear buf pointer */
                                rxbuf->m_pack = NULL;
                                rxr->rx_split_packets++;
                        }
@@ -4368,7 +4395,7 @@ igb_rxeof(struct igb_queue *que, int cou
                /* Initial frame - setup */
                if (rxr->fmp == NULL) {
                        mh->m_pkthdr.len = mh->m_len;
-                       /* Store the first mbuf */
+                       /* Save the head of the chain */
                        rxr->fmp = mh;
                        rxr->lmp = mh;
                        if (mp != NULL) {
@@ -4533,12 +4560,15 @@ igb_register_vlan(void *arg, struct ifne
        if ((vtag == 0) || (vtag > 4095))       /* Invalid */
                 return;
 
+       IGB_CORE_LOCK(adapter);
        index = (vtag >> 5) & 0x7F;
        bit = vtag & 0x1F;
-       igb_shadow_vfta[index] |= (1 << bit);
+       adapter->shadow_vfta[index] |= (1 << bit);
        ++adapter->num_vlans;
        /* Re-init to load the changes */
-       igb_init(adapter);
+       if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
+               igb_init_locked(adapter);
+       IGB_CORE_UNLOCK(adapter);
 }
 
 /*
@@ -4557,12 +4587,15 @@ igb_unregister_vlan(void *arg, struct if
        if ((vtag == 0) || (vtag > 4095))       /* Invalid */
                 return;
 
+       IGB_CORE_LOCK(adapter);
        index = (vtag >> 5) & 0x7F;
        bit = vtag & 0x1F;
-       igb_shadow_vfta[index] &= ~(1 << bit);
+       adapter->shadow_vfta[index] &= ~(1 << bit);
        --adapter->num_vlans;
        /* Re-init to load the changes */
-       igb_init(adapter);
+       if (ifp->if_capenable & IFCAP_VLAN_HWFILTER)
+               igb_init_locked(adapter);
+       IGB_CORE_UNLOCK(adapter);
 }
 
 static void
@@ -4585,12 +4618,13 @@ igb_setup_vlan_hw_support(struct adapter
        ** we need to repopulate it now.
        */
        for (int i = 0; i < IGB_VFTA_SIZE; i++)
-                if (igb_shadow_vfta[i] != 0) {
+                if (adapter->shadow_vfta[i] != 0) {
                        if (hw->mac.type == e1000_vfadapt)
-                               e1000_vfta_set_vf(hw, igb_shadow_vfta[i], TRUE);
+                               e1000_vfta_set_vf(hw,
+                                   adapter->shadow_vfta[i], TRUE);
                        else
                                E1000_WRITE_REG_ARRAY(hw, E1000_VFTA,
-                                i, igb_shadow_vfta[i]);
+                                i, adapter->shadow_vfta[i]);
                }
 
        if (hw->mac.type == e1000_vfadapt)
@@ -4994,6 +5028,28 @@ igb_sysctl_reg_handler(SYSCTL_HANDLER_AR
 }
 
 /*
+**  Tuneable interrupt rate handler
+*/
+static int
+igb_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS)
+{
+       struct igb_queue        *que = ((struct igb_queue *)oidp->oid_arg1);
+       int                     error;
+       u32                     reg, usec, rate;
+                        
+       reg = E1000_READ_REG(&que->adapter->hw, E1000_EITR(que->msix));
+       usec = ((reg & 0x7FFC) >> 2);
+       if (usec > 0)
+               rate = 1000000 / usec;
+       else
+               rate = 0;
+       error = sysctl_handle_int(oidp, &rate, 0, req);
+       if (error || !req->newptr)
+               return error;
+       return 0;
+}
+
+/*
  * Add sysctl variables, one per statistic, to the system.
  */
 static void
@@ -5065,6 +5121,12 @@ igb_add_hw_stats(struct adapter *adapter
                                            CTLFLAG_RD, NULL, "Queue Name");
                queue_list = SYSCTL_CHILDREN(queue_node);
 
+               SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate", 
+                               CTLFLAG_RD, &adapter->queues[i],
+                               sizeof(&adapter->queues[i]),
+                               igb_sysctl_interrupt_rate_handler,
+                               "IU", "Interrupt Rate");
+
                SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", 
                                CTLFLAG_RD, adapter, E1000_TDH(txr->me),
                                igb_sysctl_reg_handler, "IU",

Modified: head/sys/dev/e1000/if_igb.h
==============================================================================
--- head/sys/dev/e1000/if_igb.h Tue Nov 23 22:07:10 2010        (r215780)
+++ head/sys/dev/e1000/if_igb.h Tue Nov 23 22:12:02 2010        (r215781)
@@ -190,6 +190,9 @@
 #define IGB_TX_BUFFER_SIZE             ((uint32_t) 1514)
 #define IGB_FC_PAUSE_TIME              0x0680
 #define IGB_EEPROM_APME                        0x400;
+#define IGB_QUEUE_IDLE                 0
+#define IGB_QUEUE_WORKING              1
+#define IGB_QUEUE_HUNG                 2
 
 /*
  * TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be
@@ -237,7 +240,7 @@
 
 /* Define the starting Interrupt rate per Queue */
 #define IGB_INTS_PER_SEC        8000
-#define IGB_DEFAULT_ITR          1000000000/(IGB_INTS_PER_SEC * 256)
+#define IGB_DEFAULT_ITR         ((1000000/IGB_INTS_PER_SEC) << 2)
 
 #define IGB_LINK_ITR            2000
 
@@ -300,7 +303,7 @@ struct tx_ring {
        u32                     bytes;
        u32                     packets;
 
-       bool                    watchdog_check;
+       int                     queue_status;
        int                     watchdog_time;
        int                     tdt;
        int                     tdh;
@@ -384,7 +387,15 @@ struct adapter {
        int             wol;
        int             has_manage;
 
-       /* Info about the board itself */
+       /*
+       ** Shadow VFTA table, this is needed because
+       ** the real vlan filter table gets cleared during
+       ** a soft reset and the driver needs to be able
+       ** to repopulate it.
+       */
+       u32             shadow_vfta[IGB_VFTA_SIZE];
+
+       /* Info about the interface */
        u8              link_active;
        u16             link_speed;
        u16             link_duplex;
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to