diff options
Diffstat (limited to 'sys/dev/cxgb/cxgb_main.c')
| -rw-r--r-- | sys/dev/cxgb/cxgb_main.c | 358 |
1 files changed, 177 insertions, 181 deletions
diff --git a/sys/dev/cxgb/cxgb_main.c b/sys/dev/cxgb/cxgb_main.c index cc09aa0438f5..3efcbb73ccf5 100644 --- a/sys/dev/cxgb/cxgb_main.c +++ b/sys/dev/cxgb/cxgb_main.c @@ -115,7 +115,7 @@ static int offload_open(struct port_info *pi); static void touch_bars(device_t dev); static int offload_close(struct t3cdev *tdev); static void cxgb_link_start(struct port_info *p); -static void cxgb_link_fault(void *arg, int ncount); +int t3_detect_link_fault(adapter_t *adapter, int port_id); static device_method_t cxgb_controller_methods[] = { DEVMETHOD(device_probe, cxgb_controller_probe), @@ -392,6 +392,32 @@ upgrade_fw(adapter_t *sc) return (status); } +/* + * The cxgb_controller_attach function is responsible for the initial + * bringup of the device. Its responsibilities include: + * + * 1. Determine if the device supports MSI or MSI-X. + * 2. Allocate bus resources so that we can access the Base Address Register + * 3. Create and initialize mutexes for the controller and its control + * logic such as SGE and MDIO. + * 4. Call hardware specific setup routine for the adapter as a whole. + * 5. Allocate the BAR for doing MSI-X. + * 6. Setup the line interrupt iff MSI-X is not supported. + * 7. Create the driver's taskq. + * 8. Start one task queue service thread. + * 9. Check if the firmware and SRAM are up-to-date. They will be + * auto-updated later (before FULL_INIT_DONE), if required. + * 10. Create a child device for each MAC (port) + * 11. Initialize T3 private state. + * 12. Trigger the LED + * 13. Setup offload iff supported. + * 14. Reset/restart the tick callout. + * 15. Attach sysctls + * + * NOTE: Any modification or deviation from this list MUST be reflected in + * the above comment. Failure to do so will result in problems on various + * error conditions including link flapping. + */ static int cxgb_controller_attach(device_t dev) { @@ -625,6 +651,10 @@ cxgb_controller_attach(device_t dev) sc->params.vpd.ec, sc->params.vpd.sn); device_set_desc_copy(dev, buf); + snprintf(&sc->port_types[0], sizeof(sc->port_types), "%x%x%x%x", + sc->params.vpd.port_type[0], sc->params.vpd.port_type[1], + 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); t3_add_attach_sysctls(sc); @@ -635,6 +665,11 @@ out: return (error); } +/* + * The cxgb_controller_detach routine is called with the device is + * unloaded from the system. + */ + static int cxgb_controller_detach(device_t dev) { @@ -647,6 +682,24 @@ cxgb_controller_detach(device_t dev) return (0); } +/* + * The cxgb_free() is called by the cxgb_controller_detach() routine + * to tear down the structures that were built up in + * cxgb_controller_attach(), and should be the final piece of work + * done when fully unloading the driver. + * + * + * 1. Shutting down the threads started by the cxgb_controller_attach() + * routine. + * 2. Stopping the lower level device and all callouts (cxgb_down_locked()). + * 3. Detaching all of the port devices created during the + * cxgb_controller_attach() routine. + * 4. Removing the device children created via cxgb_controller_attach(). + * 5. Releaseing PCI resources associated with the device. + * 6. Turning off the offload support, iff it was turned on. + * 7. Destroying the mutexes created in cxgb_controller_attach(). + * + */ static void cxgb_free(struct adapter *sc) { @@ -655,14 +708,28 @@ cxgb_free(struct adapter *sc) ADAPTER_LOCK(sc); sc->flags |= CXGB_SHUTDOWN; ADAPTER_UNLOCK(sc); + cxgb_pcpu_shutdown_threads(sc); - ADAPTER_LOCK(sc); -/* - * drops the lock - */ + ADAPTER_LOCK(sc); cxgb_down_locked(sc); + ADAPTER_UNLOCK(sc); + + t3_sge_deinit_sw(sc); + /* + * Wait for last callout + */ + DELAY(hz*100); + + bus_generic_detach(sc->dev); + + for (i = 0; i < (sc)->params.nports; i++) { + if (sc->portdev[i] && + device_delete_child(sc->dev, sc->portdev[i]) != 0) + device_printf(sc->dev, "failed to delete child port\n"); + } + #ifdef MSI_SUPPORTED if (sc->flags & (USING_MSI | USING_MSIX)) { device_printf(sc->dev, "releasing msi message(s)\n"); @@ -676,19 +743,6 @@ cxgb_free(struct adapter *sc) sc->msix_regs_res); } - t3_sge_deinit_sw(sc); - /* - * Wait for last callout - */ - - DELAY(hz*100); - - for (i = 0; i < (sc)->params.nports; ++i) { - if (sc->portdev[i] != NULL) - device_delete_child(sc->dev, sc->portdev[i]); - } - - bus_generic_detach(sc->dev); if (sc->tq != NULL) { taskqueue_free(sc->tq); sc->tq = NULL; @@ -957,6 +1011,7 @@ cxgb_port_attach(device_t dev) } ether_ifattach(ifp, p->hw_addr); + #ifdef IFNET_MULTIQUEUE ifp->if_transmit = cxgb_pcpu_transmit; #endif @@ -1020,40 +1075,104 @@ cxgb_port_attach(device_t dev) bcopy(IF_LLADDR(p->ifp), p->hw_addr, ETHER_ADDR_LEN); t3_sge_init_port(p); - TASK_INIT(&p->link_fault_task, 0, cxgb_link_fault, p); + /* If it's MSI or INTx, allocate a single interrupt for everything */ + if ((sc->flags & USING_MSIX) == 0) { + if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, + &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { + device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n", + sc->irq_rid); + err = EINVAL; + goto out; + } + device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res); + + if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, +#ifdef INTR_FILTERS + NULL, +#endif + sc->cxgb_intr, sc, &sc->intr_tag)) { + device_printf(sc->dev, "Cannot set up interrupt\n"); + err = EINVAL; + goto irq_err; + } + } else { + cxgb_setup_msix(sc, sc->msi_count); + } #if defined(LINK_ATTACH) cxgb_link_start(p); t3_link_changed(sc, p->port_id); #endif - return (0); +out: + return (err); +irq_err: + CH_ERR(sc, "request_irq failed, err %d\n", err); + goto out; } +/* + * cxgb_port_detach() is called via the device_detach methods when + * cxgb_free() calls the bus_generic_detach. It is responsible for + * removing the device from the view of the kernel, i.e. from all + * interfaces lists etc. This routine is only called when the driver is + * being unloaded, not when the link goes down. + * + */ static int cxgb_port_detach(device_t dev) { struct port_info *p; + struct adapter *sc; p = device_get_softc(dev); + sc = p->adapter; + + if (p->port_cdev != NULL) + destroy_dev(p->port_cdev); + + ether_ifdetach(p->ifp); + printf("waiting for callout to stop ..."); + printf("done\n"); PORT_LOCK(p); if (p->ifp->if_drv_flags & IFF_DRV_RUNNING) cxgb_stop_locked(p); PORT_UNLOCK(p); - ether_ifdetach(p->ifp); - printf("waiting for callout to stop ..."); - DELAY(1000000); - printf("done\n"); + if (sc->intr_tag != NULL) { + bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag); + sc->intr_tag = NULL; + } + if (sc->irq_res != NULL) { + device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n", + sc->irq_rid, sc->irq_res); + bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid, + sc->irq_res); + sc->irq_res = NULL; + } + + if (sc->flags & USING_MSIX) + cxgb_teardown_msix(sc); + + callout_drain(&sc->cxgb_tick_ch); + callout_drain(&sc->sge_timer_ch); + + if (sc->tq != NULL) { + printf("draining slow intr\n"); + + taskqueue_drain(sc->tq, &sc->slow_intr_task); + printf("draining ext intr\n"); + taskqueue_drain(sc->tq, &sc->ext_intr_task); + printf("draining tick task\n"); + taskqueue_drain(sc->tq, &sc->tick_task); + } + /* * the lock may be acquired in ifdetach */ PORT_LOCK_DEINIT(p); if_free(p->ifp); - if (p->port_cdev != NULL) - destroy_dev(p->port_cdev); - return (0); } @@ -1142,32 +1261,6 @@ t3_os_pci_restore_state(struct adapter *sc) return (0); } -void t3_os_link_fault(struct adapter *adap, int port_id, int state) -{ - struct port_info *pi = &adap->port[port_id]; - - if (!state) { - if_link_state_change(pi->ifp, LINK_STATE_DOWN); - return; - } - - if (adap->params.nports <= 2) { - struct cmac *mac = &pi->mac; - - /* Clear local faults */ - t3_xgm_intr_disable(adap, port_id); - t3_read_reg(adap, A_XGM_INT_STATUS + pi->mac.offset); - t3_write_reg(adap, A_XGM_INT_CAUSE + pi->mac.offset, F_XGM_INT); - - t3_set_reg_field(adap, A_XGM_INT_ENABLE + pi->mac.offset, - F_XGM_INT, F_XGM_INT); - t3_xgm_intr_enable(adap, pi->port_id); - t3_mac_enable(mac, MAC_DIRECTION_TX); - } - - if_link_state_change(pi->ifp, LINK_STATE_UP); -} - /** * t3_os_link_changed - handle link status changes * @adapter: the adapter associated with the link change @@ -1186,48 +1279,12 @@ t3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed, int duplex, int fc) { struct port_info *pi = &adapter->port[port_id]; - struct cmac *mac = &adapter->port[port_id].mac; if (link_status) { - DELAY(10); - t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); - /* Clear errors created by MAC enable */ - t3_set_reg_field(adapter, A_XGM_STAT_CTRL + pi->mac.offset, - F_CLRSTATS, 1); - - if (adapter->params.nports <= 2) { - /* Clear local faults */ - t3_xgm_intr_disable(adapter, pi->port_id); - t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); - t3_write_reg(adapter, A_XGM_INT_CAUSE + pi->mac.offset, - F_XGM_INT); - - t3_set_reg_field(adapter, - A_XGM_INT_ENABLE + pi->mac.offset, - F_XGM_INT, F_XGM_INT); - t3_xgm_intr_enable(adapter, pi->port_id); - } - + pi->ifp->if_baudrate = IF_Mbps(speed); if_link_state_change(pi->ifp, LINK_STATE_UP); - } else { - t3_xgm_intr_disable(adapter, pi->port_id); - t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); - if (adapter->params.nports <= 2) { - t3_set_reg_field(adapter, - A_XGM_INT_ENABLE + pi->mac.offset, - F_XGM_INT, 0); - } - - /* PR 5666. We shouldn't power down 1G phys */ - if (is_10G(adapter)) - pi->phy.ops->power_down(&pi->phy, 1); - - t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); - t3_mac_disable(mac, MAC_DIRECTION_RX); - t3_link_start(&pi->phy, mac, &pi->link_config); - + } else if_link_state_change(pi->ifp, LINK_STATE_DOWN); - } } /** @@ -1280,22 +1337,6 @@ t3_os_ext_intr_handler(adapter_t *sc) ADAPTER_UNLOCK(sc); } -static void -cxgb_link_fault(void *arg, int ncount) -{ - struct port_info *pi = arg; - - t3_link_fault(pi->adapter, pi->port_id); -} - -void t3_os_link_fault_handler(struct adapter *sc, int port_id) -{ - struct port_info *pi = &sc->port[port_id]; - - pi->link_fault = 1; - taskqueue_enqueue(sc->tq, &pi->link_fault_task); -} - void t3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[]) { @@ -1705,30 +1746,6 @@ cxgb_up(struct adapter *sc) t3_intr_clear(sc); - /* If it's MSI or INTx, allocate a single interrupt for everything */ - if ((sc->flags & USING_MSIX) == 0) { - if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, - &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { - device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n", - sc->irq_rid); - err = EINVAL; - goto out; - } - device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res); - - if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, -#ifdef INTR_FILTERS - NULL, -#endif - sc->cxgb_intr, sc, &sc->intr_tag)) { - device_printf(sc->dev, "Cannot set up interrupt\n"); - err = EINVAL; - goto irq_err; - } - } else { - cxgb_setup_msix(sc, sc->msi_count); - } - t3_sge_start(sc); t3_intr_enable(sc); @@ -1749,14 +1766,11 @@ cxgb_up(struct adapter *sc) } out: return (err); -irq_err: - CH_ERR(sc, "request_irq failed, err %d\n", err); - goto out; } /* - * Release resources when all the ports and offloading have been stopped. + * Bring down the interface but do not free any resources. */ static void cxgb_down_locked(struct adapter *sc) @@ -1765,36 +1779,8 @@ cxgb_down_locked(struct adapter *sc) t3_sge_stop(sc); t3_intr_disable(sc); - if (sc->intr_tag != NULL) { - bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag); - sc->intr_tag = NULL; - } - if (sc->irq_res != NULL) { - device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n", - sc->irq_rid, sc->irq_res); - bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid, - sc->irq_res); - sc->irq_res = NULL; - } - - if (sc->flags & USING_MSIX) - cxgb_teardown_msix(sc); - callout_stop(&sc->cxgb_tick_ch); callout_stop(&sc->sge_timer_ch); - callout_drain(&sc->cxgb_tick_ch); - callout_drain(&sc->sge_timer_ch); - - if (sc->tq != NULL) { - printf("draining slow intr\n"); - - taskqueue_drain(sc->tq, &sc->slow_intr_task); - printf("draining ext intr\n"); - taskqueue_drain(sc->tq, &sc->ext_intr_task); - printf("draining tick task\n"); - taskqueue_drain(sc->tq, &sc->tick_task); - } - ADAPTER_UNLOCK(sc); } static int @@ -1861,8 +1847,9 @@ offload_close(struct t3cdev *tdev) ADAPTER_LOCK(adapter); if (!adapter->open_device_map) cxgb_down_locked(adapter); - else - ADAPTER_UNLOCK(adapter); + + ADAPTER_UNLOCK(adapter); + return (0); } @@ -1905,15 +1892,16 @@ cxgb_init_locked(struct port_info *p) log(LOG_WARNING, "Could not initialize offload capabilities\n"); } + + device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id); + t3_port_intr_enable(sc, p->port_id); + #if !defined(LINK_ATTACH) cxgb_link_start(p); t3_link_changed(sc, p->port_id); #endif ifp->if_baudrate = IF_Mbps(p->link_config.speed); - device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id); - t3_port_intr_enable(sc, p->port_id); - callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); t3_sge_reset_adapter(sc); @@ -1957,10 +1945,10 @@ cxgb_stop_locked(struct port_info *pi) ADAPTER_LOCK(pi->adapter); clrbit(&pi->adapter->open_device_map, pi->port_id); - if (pi->adapter->open_device_map == 0) { + if (pi->adapter->open_device_map == 0) cxgb_down_locked(pi->adapter); - } else - ADAPTER_UNLOCK(pi->adapter); + + ADAPTER_UNLOCK(pi->adapter); #if !defined(LINK_ATTACH) DELAY(100); @@ -2277,12 +2265,23 @@ check_link_status(adapter_t *sc) { int i; + /* For synchronized access to open_device_map */ + ADAPTER_LOCK_ASSERT_OWNED(sc); + for (i = 0; i < (sc)->params.nports; ++i) { struct port_info *p = &sc->port[i]; + struct link_config *lc = &p->link_config; - if (!(p->phy.caps & SUPPORTED_IRQ)) + if (!isset(&sc->open_device_map, p->port_id)) { + /* + * port is down, report link down too. Note + * that we do this for IRQ based PHYs too. + */ + lc->link_ok = 0; + t3_os_link_changed(sc, i, lc->link_ok, lc->speed, + lc->duplex, lc->fc); + } else if (p->link_fault || !(p->phy.caps & SUPPORTED_IRQ)) t3_link_changed(sc, i); - p->ifp->if_baudrate = IF_Mbps(p->link_config.speed); } } @@ -2349,12 +2348,12 @@ cxgb_tick_handler(void *arg, int count) int i; uint32_t cause, reset; - if(sc->flags & CXGB_SHUTDOWN) + if(sc->flags & CXGB_SHUTDOWN || !(sc->flags & FULL_INIT_DONE)) return; ADAPTER_LOCK(sc); - if (p->linkpoll_period) - check_link_status(sc); + + check_link_status(sc); sc->check_task_cnt++; @@ -2396,9 +2395,6 @@ cxgb_tick_handler(void *arg, int count) t3_mac_update_stats(mac); PORT_UNLOCK(pi); - if (pi->link_fault) - taskqueue_enqueue(sc->tq, &pi->link_fault_task); - ifp->if_opackets = mstats->tx_frames_64 + mstats->tx_frames_65_127 + @@ -2528,13 +2524,13 @@ in_range(int val, int lo, int hi) } static int -cxgb_extension_open(struct cdev *dev, int flags, int fmp, d_thread_t *td) +cxgb_extension_open(struct cdev *dev, int flags, int fmp, struct thread *td) { return (0); } static int -cxgb_extension_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) +cxgb_extension_close(struct cdev *dev, int flags, int fmt, struct thread *td) { return (0); } |
