From owner-svn-src-head@FreeBSD.ORG Fri Jul 9 00:38:00 2010 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8E2B3106566B; Fri, 9 Jul 2010 00:38:00 +0000 (UTC) (envelope-from np@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 7BEF68FC0C; Fri, 9 Jul 2010 00:38:00 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o690c0lu074697; Fri, 9 Jul 2010 00:38:00 GMT (envelope-from np@svn.freebsd.org) Received: (from np@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o690c0mI074691; Fri, 9 Jul 2010 00:38:00 GMT (envelope-from np@svn.freebsd.org) Message-Id: <201007090038.o690c0mI074691@svn.freebsd.org> From: Navdeep Parhar Date: Fri, 9 Jul 2010 00:38:00 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r209841 - in head/sys/dev/cxgb: . common X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 09 Jul 2010 00:38:00 -0000 Author: np Date: Fri Jul 9 00:38:00 2010 New Revision: 209841 URL: http://svn.freebsd.org/changeset/base/209841 Log: Improve cxgb(4)'s behaviour when faced with temporarily "bouncy" links: - Run the adapter's tick at 1Hz and remove link state checks from it. Instead, have each port check its link state. Delay the check so that it takes place slightly after the driver is notified of a change in link state. This is a cheap way to debounce these notifications if many are received in rapid succession. POLL_LINK_1ST_TIME flag can also be eliminated as a side effect of these changes. - Do not reset the PHY when link goes down. - Clear port's link_fault flag if the PHY indicates link is down. - get_link_status_r should leave speed and duplex alone when link is down. MFC after: 1 month Modified: head/sys/dev/cxgb/common/cxgb_ael1002.c head/sys/dev/cxgb/common/cxgb_common.h head/sys/dev/cxgb/common/cxgb_t3_hw.c head/sys/dev/cxgb/cxgb_adapter.h head/sys/dev/cxgb/cxgb_main.c Modified: head/sys/dev/cxgb/common/cxgb_ael1002.c ============================================================================== --- head/sys/dev/cxgb/common/cxgb_ael1002.c Fri Jul 9 00:36:35 2010 (r209840) +++ head/sys/dev/cxgb/common/cxgb_ael1002.c Fri Jul 9 00:38:00 2010 (r209841) @@ -297,6 +297,9 @@ static int get_link_status_r(struct cphy if (err) return err; *link_ok = (stat0 & stat1 & (stat2 >> 12)) & 1; + + if (*link_ok == 0) + return (0); } if (speed) *speed = SPEED_10000; @@ -1947,8 +1950,6 @@ static int ael2020_intr_enable(struct cp if (err) return err; - phy->caps |= POLL_LINK_1ST_TIME; - /* enable standard Link Alarm Status Interrupts */ err = t3_phy_lasi_intr_enable(phy); if (err) Modified: head/sys/dev/cxgb/common/cxgb_common.h ============================================================================== --- head/sys/dev/cxgb/common/cxgb_common.h Fri Jul 9 00:36:35 2010 (r209840) +++ head/sys/dev/cxgb/common/cxgb_common.h Fri Jul 9 00:38:00 2010 (r209841) @@ -60,7 +60,6 @@ enum { /* skip 25 */ SUPPORTED_MISC_IRQ = 1 << 26, SUPPORTED_IRQ = (SUPPORTED_LINK_IRQ | SUPPORTED_MISC_IRQ), - POLL_LINK_1ST_TIME = 1 << 27 }; enum { /* adapter interrupt-maintained statistics */ Modified: head/sys/dev/cxgb/common/cxgb_t3_hw.c ============================================================================== --- head/sys/dev/cxgb/common/cxgb_t3_hw.c Fri Jul 9 00:36:35 2010 (r209840) +++ head/sys/dev/cxgb/common/cxgb_t3_hw.c Fri Jul 9 00:38:00 2010 (r209841) @@ -1530,6 +1530,9 @@ void t3_link_changed(adapter_t *adapter, phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc); + if (link_ok == 0) + pi->link_fault = LF_NO; + if (lc->requested_fc & PAUSE_AUTONEG) fc &= lc->requested_fc; else @@ -1608,12 +1611,8 @@ void t3_link_changed(adapter_t *adapter, F_XGM_INT, 0); } - if (!link_fault) { - if (is_10G(adapter)) - pi->phy.ops->power_down(&pi->phy, 1); + if (!link_fault) t3_mac_disable(mac, MAC_DIRECTION_RX); - t3_link_start(phy, mac, lc); - } /* * Make sure Tx FIFO continues to drain, even as rxen is left @@ -2160,13 +2159,14 @@ static int mac_intr_handler(adapter_t *a mac->stats.xaui_pcs_ctc_err++; if (cause & F_XAUIPCSALIGNCHANGE) mac->stats.xaui_pcs_align_change++; - if (cause & F_XGM_INT) { - t3_set_reg_field(adap, - A_XGM_INT_ENABLE + mac->offset, - F_XGM_INT, 0); + if (cause & F_XGM_INT & + t3_read_reg(adap, A_XGM_INT_ENABLE + mac->offset)) { + t3_set_reg_field(adap, A_XGM_INT_ENABLE + mac->offset, + F_XGM_INT, 0); /* link fault suspected */ pi->link_fault = LF_MAYBE; + t3_os_link_intr(pi); } t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause); @@ -2194,7 +2194,7 @@ static int phy_intr_handler(adapter_t *a int phy_cause = p->phy.ops->intr_handler(&p->phy); if (phy_cause & cphy_cause_link_change) - t3_link_changed(adapter, i); + t3_os_link_intr(p); if (phy_cause & cphy_cause_fifo_error) p->phy.fifo_errors++; if (phy_cause & cphy_cause_module_change) Modified: head/sys/dev/cxgb/cxgb_adapter.h ============================================================================== --- head/sys/dev/cxgb/cxgb_adapter.h Fri Jul 9 00:36:35 2010 (r209840) +++ head/sys/dev/cxgb/cxgb_adapter.h Fri Jul 9 00:38:00 2010 (r209841) @@ -106,6 +106,8 @@ struct port_info { int link_fault; uint8_t hw_addr[ETHER_ADDR_LEN]; + struct callout link_check_ch; + struct task link_check_task; struct task timer_reclaim_task; struct cdev *port_cdev; @@ -494,6 +496,7 @@ adap2pinfo(struct adapter *adap, int idx int t3_os_find_pci_capability(adapter_t *adapter, int cap); int t3_os_pci_save_state(struct adapter *adapter); int t3_os_pci_restore_state(struct adapter *adapter); +void t3_os_link_intr(struct port_info *); void t3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed, int duplex, int fc, int mac_was_reset); void t3_os_phymod_changed(struct adapter *adap, int port_id); @@ -527,10 +530,6 @@ int t3_get_desc(const struct sge_qset *q unsigned char *data); void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p); -#define CXGB_TICKS(a) ((a)->params.linkpoll_period ? \ - (hz * (a)->params.linkpoll_period) / 10 : \ - (a)->params.stats_update_period * hz) - /* * XXX figure out how we can return this to being private to sge */ Modified: head/sys/dev/cxgb/cxgb_main.c ============================================================================== --- head/sys/dev/cxgb/cxgb_main.c Fri Jul 9 00:36:35 2010 (r209840) +++ head/sys/dev/cxgb/cxgb_main.c Fri Jul 9 00:38:00 2010 (r209841) @@ -97,6 +97,8 @@ static int setup_sge_qsets(adapter_t *); static void cxgb_async_intr(void *); static void cxgb_tick_handler(void *, int); static void cxgb_tick(void *); +static void link_check_callout(void *); +static void check_link_status(void *, int); static void setup_rss(adapter_t *sc); static int alloc_filters(struct adapter *); static int setup_hw_filters(struct adapter *); @@ -670,7 +672,7 @@ cxgb_controller_attach(device_t dev) sc->params.vpd.port_type[2], sc->params.vpd.port_type[3]); device_printf(sc->dev, "Firmware Version %s\n", &sc->fw_version[0]); - callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); + callout_reset(&sc->cxgb_tick_ch, hz, cxgb_tick, sc); t3_add_attach_sysctls(sc); out: if (error) @@ -1007,6 +1009,9 @@ cxgb_port_attach(device_t dev) device_get_unit(device_get_parent(dev)), p->port_id); PORT_LOCK_INIT(p, p->lockbuf); + callout_init(&p->link_check_ch, CALLOUT_MPSAFE); + TASK_INIT(&p->link_check_task, 0, check_link_status, p); + /* Allocate an ifnet object and set it up */ ifp = p->ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { @@ -1827,8 +1832,6 @@ cxgb_init_locked(struct port_info *p) ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; PORT_UNLOCK(p); - t3_link_changed(sc, p->port_id); - for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) { struct sge_qset *qs = &sc->sge.qs[i]; struct sge_txq *txq = &qs->txq[TXQ_ETH]; @@ -1839,6 +1842,9 @@ cxgb_init_locked(struct port_info *p) /* all ok */ setbit(&sc->open_device_map, p->port_id); + callout_reset(&p->link_check_ch, + p->phy.caps & SUPPORTED_LINK_IRQ ? hz * 3 : hz / 4, + link_check_callout, p); done: if (may_sleep) { @@ -1914,6 +1920,9 @@ cxgb_uninit_synchronized(struct port_inf taskqueue_drain(sc->tq, &sc->slow_intr_task); taskqueue_drain(sc->tq, &sc->tick_task); + callout_drain(&pi->link_check_ch); + taskqueue_drain(sc->tq, &pi->link_check_task); + PORT_LOCK(pi); ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); @@ -2274,33 +2283,42 @@ cxgb_async_intr(void *data) taskqueue_enqueue(sc->tq, &sc->slow_intr_task); } -static inline int -link_poll_needed(struct port_info *p) +static void +link_check_callout(void *arg) { - struct cphy *phy = &p->phy; + struct port_info *pi = arg; + struct adapter *sc = pi->adapter; - if (phy->caps & POLL_LINK_1ST_TIME) { - p->phy.caps &= ~POLL_LINK_1ST_TIME; - return (1); - } + if (!isset(&sc->open_device_map, pi->port_id)) + return; - return (p->link_fault || !(phy->caps & SUPPORTED_LINK_IRQ)); + taskqueue_enqueue(sc->tq, &pi->link_check_task); } static void -check_link_status(adapter_t *sc) +check_link_status(void *arg, int pending) { - int i; + struct port_info *pi = arg; + struct adapter *sc = pi->adapter; - for (i = 0; i < (sc)->params.nports; ++i) { - struct port_info *p = &sc->port[i]; + if (!isset(&sc->open_device_map, pi->port_id)) + return; - if (!isset(&sc->open_device_map, p->port_id)) - continue; + t3_link_changed(sc, pi->port_id); - if (link_poll_needed(p)) - t3_link_changed(sc, i); - } + if (pi->link_fault || !(pi->phy.caps & SUPPORTED_LINK_IRQ)) + callout_reset(&pi->link_check_ch, hz, link_check_callout, pi); +} + +void +t3_os_link_intr(struct port_info *pi) +{ + /* + * Schedule a link check in the near future. If the link is flapping + * rapidly we'll keep resetting the callout and delaying the check until + * things stabilize a bit. + */ + callout_reset(&pi->link_check_ch, hz / 4, link_check_callout, pi); } static void @@ -2352,7 +2370,7 @@ cxgb_tick(void *arg) return; taskqueue_enqueue(sc->tq, &sc->tick_task); - callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); + callout_reset(&sc->cxgb_tick_ch, hz, cxgb_tick, sc); } static void @@ -2366,8 +2384,6 @@ cxgb_tick_handler(void *arg, int count) if (sc->flags & CXGB_SHUTDOWN || !(sc->flags & FULL_INIT_DONE)) return; - check_link_status(sc); - if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map) check_t3b2_mac(sc);