📄 atl1_main.c
字号:
dev_printk(KERN_DEBUG, &adapter->pdev->dev, "rx exception, ISR = 0x%x\n", status); atl1_intr_rx(adapter); } if (--max_ints < 0) break; } while ((status = adapter->cmb.cmb->int_stats)); /* re-enable Interrupt */ iowrite32(ISR_DIS_SMB | ISR_DIS_DMA, adapter->hw.hw_addr + REG_ISR); return IRQ_HANDLED;}/* * atl1_watchdog - Timer Call-back * @data: pointer to netdev cast into an unsigned long */static void atl1_watchdog(unsigned long data){ struct atl1_adapter *adapter = (struct atl1_adapter *)data; /* Reset the timer */ mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);}/* * atl1_phy_config - Timer Call-back * @data: pointer to netdev cast into an unsigned long */static void atl1_phy_config(unsigned long data){ struct atl1_adapter *adapter = (struct atl1_adapter *)data; struct atl1_hw *hw = &adapter->hw; unsigned long flags; spin_lock_irqsave(&adapter->lock, flags); adapter->phy_timer_pending = false; atl1_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg); atl1_write_phy_reg(hw, MII_AT001_CR, hw->mii_1000t_ctrl_reg); atl1_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN); spin_unlock_irqrestore(&adapter->lock, flags);}/* * atl1_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure */static void atl1_tx_timeout(struct net_device *netdev){ struct atl1_adapter *adapter = netdev_priv(netdev); /* Do the reset outside of interrupt context */ schedule_work(&adapter->tx_timeout_task);}/* * Orphaned vendor comment left intact here: * <vendor comment> * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT * will assert. We do soft reset <0x1400=1> according * with the SPEC. BUT, it seemes that PCIE or DMA * state-machine will not be reset. DMAR_TO_INT will * assert again and again. * </vendor comment> */static void atl1_tx_timeout_task(struct work_struct *work){ struct atl1_adapter *adapter = container_of(work, struct atl1_adapter, tx_timeout_task); struct net_device *netdev = adapter->netdev; netif_device_detach(netdev); atl1_down(adapter); atl1_up(adapter); netif_device_attach(netdev);}/* * atl1_link_chg_task - deal with link change event Out of interrupt context */static void atl1_link_chg_task(struct work_struct *work){ struct atl1_adapter *adapter = container_of(work, struct atl1_adapter, link_chg_task); unsigned long flags; spin_lock_irqsave(&adapter->lock, flags); atl1_check_link(adapter); spin_unlock_irqrestore(&adapter->lock, flags);}static void atl1_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp){ struct atl1_adapter *adapter = netdev_priv(netdev); unsigned long flags; u32 ctrl; spin_lock_irqsave(&adapter->lock, flags); /* atl1_irq_disable(adapter); */ adapter->vlgrp = grp; if (grp) { /* enable VLAN tag insert/strip */ ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL); ctrl |= MAC_CTRL_RMV_VLAN; iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL); } else { /* disable VLAN tag insert/strip */ ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL); ctrl &= ~MAC_CTRL_RMV_VLAN; iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL); } /* atl1_irq_enable(adapter); */ spin_unlock_irqrestore(&adapter->lock, flags);}static void atl1_restore_vlan(struct atl1_adapter *adapter){ atl1_vlan_rx_register(adapter->netdev, adapter->vlgrp);}int atl1_reset(struct atl1_adapter *adapter){ int ret; ret = atl1_reset_hw(&adapter->hw); if (ret != ATL1_SUCCESS) return ret; return atl1_init_hw(&adapter->hw);}s32 atl1_up(struct atl1_adapter *adapter){ struct net_device *netdev = adapter->netdev; int err; int irq_flags = IRQF_SAMPLE_RANDOM; /* hardware has been reset, we need to reload some things */ atl1_set_multi(netdev); atl1_init_ring_ptrs(adapter); atl1_restore_vlan(adapter); err = atl1_alloc_rx_buffers(adapter); if (unlikely(!err)) /* no RX BUFFER allocated */ return -ENOMEM; if (unlikely(atl1_configure(adapter))) { err = -EIO; goto err_up; } err = pci_enable_msi(adapter->pdev); if (err) { dev_info(&adapter->pdev->dev, "Unable to enable MSI: %d\n", err); irq_flags |= IRQF_SHARED; } err = request_irq(adapter->pdev->irq, &atl1_intr, irq_flags, netdev->name, netdev); if (unlikely(err)) goto err_up; mod_timer(&adapter->watchdog_timer, jiffies); atl1_irq_enable(adapter); atl1_check_link(adapter); return 0;err_up: pci_disable_msi(adapter->pdev); /* free rx_buffers */ atl1_clean_rx_ring(adapter); return err;}void atl1_down(struct atl1_adapter *adapter){ struct net_device *netdev = adapter->netdev; del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_config_timer); adapter->phy_timer_pending = false; atl1_irq_disable(adapter); free_irq(adapter->pdev->irq, netdev); pci_disable_msi(adapter->pdev); atl1_reset_hw(&adapter->hw); adapter->cmb.cmb->int_stats = 0; adapter->link_speed = SPEED_0; adapter->link_duplex = -1; netif_carrier_off(netdev); netif_stop_queue(netdev); atl1_clean_tx_ring(adapter); atl1_clean_rx_ring(adapter);}/* * atl1_open - Called when a network interface is made active * @netdev: network interface device structure * * Returns 0 on success, negative value on failure * * The open entry point is called when a network interface is made * active by the system (IFF_UP). At this point all resources needed * for transmit and receive operations are allocated, the interrupt * handler is registered with the OS, the watchdog timer is started, * and the stack is notified that the interface is ready. */static int atl1_open(struct net_device *netdev){ struct atl1_adapter *adapter = netdev_priv(netdev); int err; /* allocate transmit descriptors */ err = atl1_setup_ring_resources(adapter); if (err) return err; err = atl1_up(adapter); if (err) goto err_up; return 0;err_up: atl1_reset(adapter); return err;}/* * atl1_close - Disables a network interface * @netdev: network interface device structure * * Returns 0, this is not allowed to fail * * The close entry point is called when an interface is de-activated * by the OS. The hardware is still under the drivers control, but * needs to be disabled. A global MAC reset is issued to stop the * hardware, and all transmit and receive resources are freed. */static int atl1_close(struct net_device *netdev){ struct atl1_adapter *adapter = netdev_priv(netdev); atl1_down(adapter); atl1_free_ring_resources(adapter); return 0;}#ifdef CONFIG_PMstatic int atl1_suspend(struct pci_dev *pdev, pm_message_t state){ struct net_device *netdev = pci_get_drvdata(pdev); struct atl1_adapter *adapter = netdev_priv(netdev); struct atl1_hw *hw = &adapter->hw; u32 ctrl = 0; u32 wufc = adapter->wol; netif_device_detach(netdev); if (netif_running(netdev)) atl1_down(adapter); atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl); if (ctrl & BMSR_LSTATUS) wufc &= ~ATL1_WUFC_LNKC; /* reduce speed to 10/100M */ if (wufc) { atl1_phy_enter_power_saving(hw); /* if resume, let driver to re- setup link */ hw->phy_configured = false; atl1_set_mac_addr(hw); atl1_set_multi(netdev); ctrl = 0; /* turn on magic packet wol */ if (wufc & ATL1_WUFC_MAG) ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN; /* turn on Link change WOL */ if (wufc & ATL1_WUFC_LNKC) ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL); /* turn on all-multi mode if wake on multicast is enabled */ ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL); ctrl &= ~MAC_CTRL_DBG; ctrl &= ~MAC_CTRL_PROMIS_EN; if (wufc & ATL1_WUFC_MC) ctrl |= MAC_CTRL_MC_ALL_EN; else ctrl &= ~MAC_CTRL_MC_ALL_EN; /* turn on broadcast mode if wake on-BC is enabled */ if (wufc & ATL1_WUFC_BC) ctrl |= MAC_CTRL_BC_EN; else ctrl &= ~MAC_CTRL_BC_EN; /* enable RX */ ctrl |= MAC_CTRL_RX_EN; iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL); pci_enable_wake(pdev, PCI_D3hot, 1); pci_enable_wake(pdev, PCI_D3cold, 1); } else { iowrite32(0, hw->hw_addr + REG_WOL_CTRL); pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); } pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); return 0;}static int atl1_resume(struct pci_dev *pdev){ struct net_device *netdev = pci_get_drvdata(pdev); struct atl1_adapter *adapter = netdev_priv(netdev); u32 ret_val; pci_set_power_state(pdev, 0); pci_restore_state(pdev); ret_val = pci_enable_device(pdev); pci_enable_wake(pdev, PCI_D3hot, 0); pci_enable_wake(pdev, PCI_D3cold, 0); iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL); atl1_reset(adapter); if (netif_running(netdev)) atl1_up(adapter); netif_device_attach(netdev); atl1_via_workaround(adapter); return 0;}#else#define atl1_suspend NULL#define atl1_resume NULL#endif#ifdef CONFIG_NET_POLL_CONTROLLERstatic void atl1_poll_controller(struct net_device *netdev){ disable_irq(netdev->irq); atl1_intr(netdev->irq, netdev); enable_irq(netdev->irq);}#endif/* * atl1_probe - Device Initialization Routine * @pdev: PCI device information struct * @ent: entry in atl1_pci_tbl * * Returns 0 on success, negative on failure * * atl1_probe initializes an adapter identified by a pci_dev structure. * The OS initialization, configuring of the adapter private structure, * and a hardware reset occur. */static int __devinit atl1_probe(struct pci_dev *pdev, const struct pci_device_id *ent){ struct net_device *netdev; struct atl1_adapter *adapter; static int cards_found = 0; int err; err = pci_enable_device(pdev); if (err) return err; /* * The atl1 chip can DMA to 64-bit addresses, but it uses a single * shared register for the high 32 bits, so only a single, aligned, * 4 GB physical address range can be used at a time. * * Supporting 64-bit DMA on this hardware is more trouble than it's * worth. It is far easier to limit to 32-bit DMA than update * various kernel subsystems to support the mechanics required by a * fixed-high-32-bit system. */ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (err) { dev_err(&pdev->dev, "no usable DMA configuration\n"); goto err_dma; } /* Mark all PCI regions associated with PCI device * pdev as being reserved by owner atl1_driver_name */ err = pci_request_regions(pdev, atl1_driver_name); if (err) goto err_request_regions; /* Enables bus-mastering on the device and calls * pcibios_set_master to do the needed arch specific settings */ pci_set_master(pdev); netdev = alloc_etherdev(sizeof(struct atl1_adapter)); if (!netdev) { err = -ENOMEM; goto err_alloc_etherdev; } SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); adapter = netdev_priv(netdev); adapter->netdev = netdev; adapter->pdev = pdev; adapter->hw.back = adapter; adapter->hw.hw_addr = pci_iomap(pdev, 0, 0); if (!adapter->hw.hw_addr) { err = -EIO; goto err_pci_iomap; } /* get device revision number */ adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + (REG_MASTER_CTRL + 2)); dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); /* set default ring resource counts */ adapter->rfd_ring.count = adapter->rrd_ring.count = ATL1_DEFAULT_RFD; adapter->tpd_ring.count = ATL1_DEFAULT_TPD; adapter->mii.dev = netdev; adapter->mii.mdio_read = mdio_read; adapter->mii.mdio_write = mdio_write; adapter->mii.phy_id_mask = 0x1f; adapter->mii.reg_num_mask = 0x1f; netdev->open = &atl1_open; netdev->stop = &atl1_close; netdev->hard_start_xmit = &atl1_xmit_frame; netdev->get_stats = &atl1_get_stats; netdev->set_multicast_list = &atl1_set_multi; netdev->set_mac_address = &atl1_set_mac; netdev->change_mtu = &atl1_change_mtu; netdev->do_ioctl = &atl1_ioctl; netdev->tx_timeout = &atl1_tx_timeout; netdev->watchdog_timeo = 5 * HZ;#ifdef CONFIG_N
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -