📄 atl1_main.c
字号:
if (atl1_rcb_128 == hw->rcb_value) value |= DMA_CTRL_RCB_VALUE; iowrite32(value, hw->hw_addr + REG_DMA_CTRL); /* config CMB / SMB */ value = (hw->cmb_tpd > adapter->tpd_ring.count) ? hw->cmb_tpd : adapter->tpd_ring.count; value <<= 16; value |= hw->cmb_rrd; iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TH); value = hw->cmb_rx_timer | ((u32) hw->cmb_tx_timer << 16); iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TIMER); iowrite32(hw->smb_timer, hw->hw_addr + REG_SMB_TIMER); /* --- enable CMB / SMB */ value = CSMB_CTRL_CMB_EN | CSMB_CTRL_SMB_EN; iowrite32(value, hw->hw_addr + REG_CSMB_CTRL); value = ioread32(adapter->hw.hw_addr + REG_ISR); if (unlikely((value & ISR_PHY_LINKDOWN) != 0)) value = 1; /* config failed */ else value = 0; /* clear all interrupt status */ iowrite32(0x3fffffff, adapter->hw.hw_addr + REG_ISR); iowrite32(0, adapter->hw.hw_addr + REG_ISR); return value;}/* * atl1_pcie_patch - Patch for PCIE module */static void atl1_pcie_patch(struct atl1_adapter *adapter){ u32 value; /* much vendor magic here */ value = 0x6500; iowrite32(value, adapter->hw.hw_addr + 0x12FC); /* pcie flow control mode change */ value = ioread32(adapter->hw.hw_addr + 0x1008); value |= 0x8000; iowrite32(value, adapter->hw.hw_addr + 0x1008);}/* * When ACPI resume on some VIA MotherBoard, the Interrupt Disable bit/0x400 * on PCI Command register is disable. * The function enable this bit. * Brackett, 2006/03/15 */static void atl1_via_workaround(struct atl1_adapter *adapter){ unsigned long value; value = ioread16(adapter->hw.hw_addr + PCI_COMMAND); if (value & PCI_COMMAND_INTX_DISABLE) value &= ~PCI_COMMAND_INTX_DISABLE; iowrite32(value, adapter->hw.hw_addr + PCI_COMMAND);}/* * atl1_irq_enable - Enable default interrupt generation settings * @adapter: board private structure */static void atl1_irq_enable(struct atl1_adapter *adapter){ iowrite32(IMR_NORMAL_MASK, adapter->hw.hw_addr + REG_IMR); ioread32(adapter->hw.hw_addr + REG_IMR);}/* * atl1_irq_disable - Mask off interrupt generation on the NIC * @adapter: board private structure */static void atl1_irq_disable(struct atl1_adapter *adapter){ iowrite32(0, adapter->hw.hw_addr + REG_IMR); ioread32(adapter->hw.hw_addr + REG_IMR); synchronize_irq(adapter->pdev->irq);}static void atl1_clear_phy_int(struct atl1_adapter *adapter){ u16 phy_data; unsigned long flags; spin_lock_irqsave(&adapter->lock, flags); atl1_read_phy_reg(&adapter->hw, 19, &phy_data); spin_unlock_irqrestore(&adapter->lock, flags);}static void atl1_inc_smb(struct atl1_adapter *adapter){ struct stats_msg_block *smb = adapter->smb.smb; /* Fill out the OS statistics structure */ adapter->soft_stats.rx_packets += smb->rx_ok; adapter->soft_stats.tx_packets += smb->tx_ok; adapter->soft_stats.rx_bytes += smb->rx_byte_cnt; adapter->soft_stats.tx_bytes += smb->tx_byte_cnt; adapter->soft_stats.multicast += smb->rx_mcast; adapter->soft_stats.collisions += (smb->tx_1_col + smb->tx_2_col * 2 + smb->tx_late_col + smb->tx_abort_col * adapter->hw.max_retry); /* Rx Errors */ adapter->soft_stats.rx_errors += (smb->rx_frag + smb->rx_fcs_err + smb->rx_len_err + smb->rx_sz_ov + smb->rx_rxf_ov + smb->rx_rrd_ov + smb->rx_align_err); adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov; adapter->soft_stats.rx_length_errors += smb->rx_len_err; adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err; adapter->soft_stats.rx_frame_errors += smb->rx_align_err; adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov + smb->rx_rxf_ov); adapter->soft_stats.rx_pause += smb->rx_pause; adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov; adapter->soft_stats.rx_trunc += smb->rx_sz_ov; /* Tx Errors */ adapter->soft_stats.tx_errors += (smb->tx_late_col + smb->tx_abort_col + smb->tx_underrun + smb->tx_trunc); adapter->soft_stats.tx_fifo_errors += smb->tx_underrun; adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col; adapter->soft_stats.tx_window_errors += smb->tx_late_col; adapter->soft_stats.excecol += smb->tx_abort_col; adapter->soft_stats.deffer += smb->tx_defer; adapter->soft_stats.scc += smb->tx_1_col; adapter->soft_stats.mcc += smb->tx_2_col; adapter->soft_stats.latecol += smb->tx_late_col; adapter->soft_stats.tx_underun += smb->tx_underrun; adapter->soft_stats.tx_trunc += smb->tx_trunc; adapter->soft_stats.tx_pause += smb->tx_pause; adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets; adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets; adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes; adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes; adapter->net_stats.multicast = adapter->soft_stats.multicast; adapter->net_stats.collisions = adapter->soft_stats.collisions; adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors; adapter->net_stats.rx_over_errors = adapter->soft_stats.rx_missed_errors; adapter->net_stats.rx_length_errors = adapter->soft_stats.rx_length_errors; adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors; adapter->net_stats.rx_frame_errors = adapter->soft_stats.rx_frame_errors; adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors; adapter->net_stats.rx_missed_errors = adapter->soft_stats.rx_missed_errors; adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors; adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors; adapter->net_stats.tx_aborted_errors = adapter->soft_stats.tx_aborted_errors; adapter->net_stats.tx_window_errors = adapter->soft_stats.tx_window_errors; adapter->net_stats.tx_carrier_errors = adapter->soft_stats.tx_carrier_errors;}/* * atl1_get_stats - Get System Network Statistics * @netdev: network interface device structure * * Returns the address of the device statistics structure. * The statistics are actually updated from the timer callback. */static struct net_device_stats *atl1_get_stats(struct net_device *netdev){ struct atl1_adapter *adapter = netdev_priv(netdev); return &adapter->net_stats;}static void atl1_update_mailbox(struct atl1_adapter *adapter){ unsigned long flags; u32 tpd_next_to_use; u32 rfd_next_to_use; u32 rrd_next_to_clean; u32 value; spin_lock_irqsave(&adapter->mb_lock, flags); tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use); rfd_next_to_use = atomic_read(&adapter->rfd_ring.next_to_use); rrd_next_to_clean = atomic_read(&adapter->rrd_ring.next_to_clean); value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) << MB_RFD_PROD_INDX_SHIFT) | ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) << MB_RRD_CONS_INDX_SHIFT) | ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) << MB_TPD_PROD_INDX_SHIFT); iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX); spin_unlock_irqrestore(&adapter->mb_lock, flags);}static void atl1_clean_alloc_flag(struct atl1_adapter *adapter, struct rx_return_desc *rrd, u16 offset){ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; while (rfd_ring->next_to_clean != (rrd->buf_indx + offset)) { rfd_ring->buffer_info[rfd_ring->next_to_clean].alloced = 0; if (++rfd_ring->next_to_clean == rfd_ring->count) { rfd_ring->next_to_clean = 0; } }}static void atl1_update_rfd_index(struct atl1_adapter *adapter, struct rx_return_desc *rrd){ u16 num_buf; num_buf = (rrd->xsz.xsum_sz.pkt_size + adapter->rx_buffer_len - 1) / adapter->rx_buffer_len; if (rrd->num_buf == num_buf) /* clean alloc flag for bad rrd */ atl1_clean_alloc_flag(adapter, rrd, num_buf);}static void atl1_rx_checksum(struct atl1_adapter *adapter, struct rx_return_desc *rrd, struct sk_buff *skb){ struct pci_dev *pdev = adapter->pdev; skb->ip_summed = CHECKSUM_NONE; if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) { if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC | ERR_FLAG_CODE | ERR_FLAG_OV)) { adapter->hw_csum_err++; dev_printk(KERN_DEBUG, &pdev->dev, "rx checksum error\n"); return; } } /* not IPv4 */ if (!(rrd->pkt_flg & PACKET_FLAG_IPV4)) /* checksum is invalid, but it's not an IPv4 pkt, so ok */ return; /* IPv4 packet */ if (likely(!(rrd->err_flg & (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM)))) { skb->ip_summed = CHECKSUM_UNNECESSARY; adapter->hw_csum_good++; return; } /* IPv4, but hardware thinks its checksum is wrong */ dev_printk(KERN_DEBUG, &pdev->dev, "hw csum wrong, pkt_flag:%x, err_flag:%x\n", rrd->pkt_flg, rrd->err_flg); skb->ip_summed = CHECKSUM_COMPLETE; skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum); adapter->hw_csum_err++; return;}/* * atl1_alloc_rx_buffers - Replace used receive buffers * @adapter: address of board private structure */static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter){ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; struct pci_dev *pdev = adapter->pdev; struct page *page; unsigned long offset; struct atl1_buffer *buffer_info, *next_info; struct sk_buff *skb; u16 num_alloc = 0; u16 rfd_next_to_use, next_next; struct rx_free_desc *rfd_desc; next_next = rfd_next_to_use = atomic_read(&rfd_ring->next_to_use); if (++next_next == rfd_ring->count) next_next = 0; buffer_info = &rfd_ring->buffer_info[rfd_next_to_use]; next_info = &rfd_ring->buffer_info[next_next]; while (!buffer_info->alloced && !next_info->alloced) { if (buffer_info->skb) { buffer_info->alloced = 1; goto next; } rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use); skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN); if (unlikely(!skb)) { /* Better luck next round */ adapter->net_stats.rx_dropped++; break; } /* * Make buffer alignment 2 beyond a 16 byte boundary * this will result in a 16 byte aligned IP header after * the 14 byte MAC header is removed */ skb_reserve(skb, NET_IP_ALIGN); buffer_info->alloced = 1; buffer_info->skb = skb; buffer_info->length = (u16) adapter->rx_buffer_len; page = virt_to_page(skb->data); offset = (unsigned long)skb->data & ~PAGE_MASK; buffer_info->dma = pci_map_page(pdev, page, offset, adapter->rx_buffer_len, PCI_DMA_FROMDEVICE); rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma); rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len); rfd_desc->coalese = 0;next: rfd_next_to_use = next_next; if (unlikely(++next_next == rfd_ring->count)) next_next = 0; buffer_info = &rfd_ring->buffer_info[rfd_next_to_use]; next_info = &rfd_ring->buffer_info[next_next]; num_alloc++; } if (num_alloc) { /* * Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only * applicable for weak-ordered memory model archs, * such as IA-64). */ wmb(); atomic_set(&rfd_ring->next_to_use, (int)rfd_next_to_use); } return num_alloc;}static void atl1_intr_rx(struct atl1_adapter *adapter){ int i, count; u16 length; u16 rrd_next_to_clean; u32 value; struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; struct atl1_buffer *buffer_info; struct rx_return_desc *rrd; struct sk_buff *skb; count = 0; rrd_next_to_clean = atomic_read(&rrd_ring->next_to_clean); while (1) { rrd = ATL1_RRD_DESC(rrd_ring, rrd_next_to_clean); i = 1; if (likely(rrd->xsz.valid)) { /* packet valid */chk_rrd: /* check rrd status */ if (likely(rrd->num_buf == 1)) goto rrd_ok; /* rrd seems to be bad */ if (unlikely(i-- > 0)) { /* rrd may not be DMAed completely */ dev_printk(KERN_DEBUG, &adapter->pdev->dev, "incomplete RRD DMA transfer\n"); udelay(1); goto chk_rrd; } /* bad rrd */ dev_printk(KERN_DEBUG, &adapter->pdev->dev, "bad RRD\n"); /* see if update RFD index */ if (rrd->num_buf > 1) atl1_update_rfd_index(adapter, rrd); /* update rrd */ rrd->xsz.valid = 0; if (++rrd_next_to_clean == rrd_ring->count) rrd_next_to_clean = 0; count++; continue; } else { /* current rrd still not be updated */ break; }rrd_ok: /* clean alloc flag for bad rrd */ atl1_clean_alloc_flag(adapter, rrd, 0); buffer_info = &rfd_ring->buffer_info[rrd->buf_indx]; if (++rfd_ring->next_to_clean == rfd_ring->count) rfd_ring->next_to_clean = 0; /* update rrd next to clean */ if (++rrd_next_to_clean == rrd_ring->count) rrd_next_to_clean = 0; count++; if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) { if (!(rrd->err_flg & (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM | ERR_FLAG_LEN))) { /* packet error, don't need upstream */ buffer_info->alloced = 0; rrd->xsz.valid = 0; continue; } } /* Good Receive */ pci_unmap_page(adapter->pdev, buffer_info->dma, buffer_info->length, PCI_DMA_FROMDEVICE); skb = buffer_info->skb; length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size); skb_put(skb, length - ETH_FCS_LEN); /* Receive Checksum Offload */ atl1_rx_checksum(adapter, rrd, skb); skb->protocol = eth_type_trans(skb, adapter->netdev); if (adapter->vlgrp && (rrd->pkt_flg & PACKET_FLAG_VLAN_INS)) { u16 vlan_tag = (rrd->vlan_tag >> 4) | ((rrd->vlan_tag & 7) << 13) | ((rrd->vlan_tag & 8) << 9); vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag); } else netif_rx(skb); /* let protocol layer free skb */ buffer_info->skb = NULL; buffer_info->alloced = 0; rrd->xsz.valid = 0; adapter->netdev->last_rx = jiffies; } atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean); atl1_alloc_rx_buffers(adapter); /* update mailbox ? */ if (count) { u32 tpd_next_to_use; u32 rfd_next_to_use; spin_lock(&adapter->mb_lock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -