diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-16 17:48:54 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-16 17:48:54 -0700 |
commit | 1f1c2881f673671539b25686df463518d69c4649 (patch) | |
tree | 45f4a79f2371ae4525fd621d4b5820732efa161e /drivers/net/atl1 | |
parent | 7608a864e5211df1e3c1948e2719aec7c27b9333 (diff) | |
parent | c5e3ae8823693b260ce1f217adca8add1bc0b3de (diff) |
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6: (37 commits)
forcedeth bug fix: realtek phy
forcedeth bug fix: vitesse phy
forcedeth bug fix: cicada phy
atl1: reorder atl1_main functions
atl1: fix excessively indented code
atl1: cleanup atl1_main
atl1: header file cleanup
atl1: remove irq_sem
cdc-subset to support new vendor/product ID
8139cp: implement the missing dev->tx_timeout
myri10ge: Remove nonsensical limit in the tx done routine
gianfar: kill unused header
EP93XX_ETH must select MII
macb: Add multicast capability
macb: Use generic PHY layer
s390: add barriers to qeth driver
s390: scatter-gather for inbound traffic in qeth driver
eHEA: Introducing support vor DLPAR memory add
Fix a potential NULL pointer dereference in free_shared_mem() in drivers/net/s2io.c
[PATCH] softmac: Fix ESSID problem
...
Diffstat (limited to 'drivers/net/atl1')
-rw-r--r-- | drivers/net/atl1/atl1.h | 156 | ||||
-rw-r--r-- | drivers/net/atl1/atl1_main.c | 2176 |
2 files changed, 1172 insertions, 1160 deletions
diff --git a/drivers/net/atl1/atl1.h b/drivers/net/atl1/atl1.h index df4c1a0071a..ff4765f6c3d 100644 --- a/drivers/net/atl1/atl1.h +++ b/drivers/net/atl1/atl1.h @@ -43,6 +43,7 @@ extern const struct ethtool_ops atl1_ethtool_ops; struct atl1_adapter; #define ATL1_MAX_INTR 3 +#define ATL1_MAX_TX_BUF_LEN 0x3000 /* 12288 bytes */ #define ATL1_DEFAULT_TPD 256 #define ATL1_MAX_TPD 1024 @@ -57,29 +58,45 @@ struct atl1_adapter; #define ATL1_RRD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_return_desc) /* + * This detached comment is preserved for documentation purposes only. + * It was originally attached to some code that got deleted, but seems + * important enough to keep around... + * + * <begin detached comment> * Some workarounds require millisecond delays and are run during interrupt * context. Most notably, when establishing link, the phy may need tweaking * but cannot process phy register reads/writes faster than millisecond * intervals...and we establish link due to a "link status change" interrupt. + * <end detached comment> + */ + +/* + * atl1_ring_header represents a single, contiguous block of DMA space + * mapped for the three descriptor rings (tpd, rfd, rrd) and the two + * message blocks (cmb, smb) described below */ +struct atl1_ring_header { + void *desc; /* virtual address */ + dma_addr_t dma; /* physical address*/ + unsigned int size; /* length in bytes */ +}; /* - * wrapper around a pointer to a socket buffer, - * so a DMA handle can be stored along with the buffer + * atl1_buffer is wrapper around a pointer to a socket buffer + * so a DMA handle can be stored along with the skb */ struct atl1_buffer { - struct sk_buff *skb; - u16 length; - u16 alloced; + struct sk_buff *skb; /* socket buffer */ + u16 length; /* rx buffer length */ + u16 alloced; /* 1 if skb allocated */ dma_addr_t dma; }; -#define MAX_TX_BUF_LEN 0x3000 /* 12KB */ - +/* transmit packet descriptor (tpd) ring */ struct atl1_tpd_ring { - void *desc; /* pointer to the descriptor ring memory */ - dma_addr_t dma; /* physical adress of the descriptor ring */ - u16 size; /* length of descriptor ring in bytes */ + void *desc; /* descriptor ring virtual address */ + dma_addr_t dma; /* descriptor ring physical address */ + u16 size; /* descriptor ring length in bytes */ u16 count; /* number of descriptors in the ring */ u16 hw_idx; /* hardware index */ atomic_t next_to_clean; @@ -87,36 +104,34 @@ struct atl1_tpd_ring { struct atl1_buffer *buffer_info; }; +/* receive free descriptor (rfd) ring */ struct atl1_rfd_ring { - void *desc; - dma_addr_t dma; - u16 size; - u16 count; + void *desc; /* descriptor ring virtual address */ + dma_addr_t dma; /* descriptor ring physical address */ + u16 size; /* descriptor ring length in bytes */ + u16 count; /* number of descriptors in the ring */ atomic_t next_to_use; u16 next_to_clean; struct atl1_buffer *buffer_info; }; +/* receive return descriptor (rrd) ring */ struct atl1_rrd_ring { - void *desc; - dma_addr_t dma; - unsigned int size; - u16 count; + void *desc; /* descriptor ring virtual address */ + dma_addr_t dma; /* descriptor ring physical address */ + unsigned int size; /* descriptor ring length in bytes */ + u16 count; /* number of descriptors in the ring */ u16 next_to_use; atomic_t next_to_clean; }; -struct atl1_ring_header { - void *desc; /* pointer to the descriptor ring memory */ - dma_addr_t dma; /* physical adress of the descriptor ring */ - unsigned int size; /* length of descriptor ring in bytes */ -}; - +/* coalescing message block (cmb) */ struct atl1_cmb { struct coals_msg_block *cmb; dma_addr_t dma; }; +/* statistics message block (smb) */ struct atl1_smb { struct stats_msg_block *smb; dma_addr_t dma; @@ -141,24 +156,26 @@ struct atl1_sft_stats { u64 tx_aborted_errors; u64 tx_window_errors; u64 tx_carrier_errors; - - u64 tx_pause; /* num Pause packet transmitted. */ - u64 excecol; /* num tx packets aborted due to excessive collisions. */ - u64 deffer; /* num deferred tx packets */ - u64 scc; /* num packets subsequently transmitted successfully w/ single prior collision. */ - u64 mcc; /* num packets subsequently transmitted successfully w/ multiple prior collisions. */ + u64 tx_pause; /* num pause packets transmitted. */ + u64 excecol; /* num tx packets w/ excessive collisions. */ + u64 deffer; /* num tx packets deferred */ + u64 scc; /* num packets subsequently transmitted + * successfully w/ single prior collision. */ + u64 mcc; /* num packets subsequently transmitted + * successfully w/ multiple prior collisions. */ u64 latecol; /* num tx packets w/ late collisions. */ - u64 tx_underun; /* num tx packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */ - u64 tx_trunc; /* num tx packets truncated due to size exceeding MTU, regardless whether truncated by Selene or not. (The name doesn't really reflect the meaning in this case.) */ + u64 tx_underun; /* num tx packets aborted due to transmit + * FIFO underrun, or TRD FIFO underrun */ + u64 tx_trunc; /* num tx packets truncated due to size + * exceeding MTU, regardless whether truncated + * by the chip or not. (The name doesn't really + * reflect the meaning in this case.) */ u64 rx_pause; /* num Pause packets received. */ u64 rx_rrd_ov; u64 rx_trunc; }; -/* board specific private data structure */ -#define ATL1_REGS_LEN 8 - -/* Structure containing variables used by the shared code */ +/* hardware structure */ struct atl1_hw { u8 __iomem *hw_addr; struct atl1_adapter *back; @@ -167,24 +184,35 @@ struct atl1_hw { enum atl1_dma_req_block dmar_block; enum atl1_dma_req_block dmaw_block; u8 preamble_len; - u8 max_retry; /* Retransmission maximum, after which the packet will be discarded */ - u8 jam_ipg; /* IPG to start JAM for collision based flow control in half-duplex mode. In units of 8-bit time */ - u8 ipgt; /* Desired back to back inter-packet gap. The default is 96-bit time */ - u8 min_ifg; /* Minimum number of IFG to enforce in between RX frames. Frame gap below such IFP is dropped */ + u8 max_retry; /* Retransmission maximum, after which the + * packet will be discarded */ + u8 jam_ipg; /* IPG to start JAM for collision based flow + * control in half-duplex mode. In units of + * 8-bit time */ + u8 ipgt; /* Desired back to back inter-packet gap. + * The default is 96-bit time */ + u8 min_ifg; /* Minimum number of IFG to enforce in between + * receive frames. Frame gap below such IFP + * is dropped */ u8 ipgr1; /* 64bit Carrier-Sense window */ u8 ipgr2; /* 96-bit IPG window */ - u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned burst. Each TPD is 16 bytes long */ - u8 rfd_burst; /* Number of RFD to prefetch in cache-aligned burst. Each RFD is 12 bytes long */ + u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned + * burst. Each TPD is 16 bytes long */ + u8 rfd_burst; /* Number of RFD to prefetch in cache-aligned + * burst. Each RFD is 12 bytes long */ u8 rfd_fetch_gap; - u8 rrd_burst; /* Threshold number of RRDs that can be retired in a burst. Each RRD is 16 bytes long */ + u8 rrd_burst; /* Threshold number of RRDs that can be retired + * in a burst. Each RRD is 16 bytes long */ u8 tpd_fetch_th; u8 tpd_fetch_gap; u16 tx_jumbo_task_th; - u16 txf_burst; /* Number of data bytes to read in a cache-aligned burst. Each SRAM entry is - 8 bytes long */ - u16 rx_jumbo_th; /* Jumbo packet size for non-VLAN packet. VLAN packets should add 4 bytes */ + u16 txf_burst; /* Number of data bytes to read in a cache- + * aligned burst. Each SRAM entry is 8 bytes */ + u16 rx_jumbo_th; /* Jumbo packet size for non-VLAN packet. VLAN + * packets should add 4 bytes */ u16 rx_jumbo_lkah; - u16 rrd_ret_timer; /* RRD retirement timer. Decrement by 1 after every 512ns passes. */ + u16 rrd_ret_timer; /* RRD retirement timer. Decrement by 1 after + * every 512ns passes. */ u16 lcol; /* Collision Window */ u16 cmb_tpd; @@ -194,48 +222,35 @@ struct atl1_hw { u32 smb_timer; u16 media_type; u16 autoneg_advertised; - u16 pci_cmd_word; u16 mii_autoneg_adv_reg; u16 mii_1000t_ctrl_reg; - u32 mem_rang; - u32 txcw; u32 max_frame_size; u32 min_frame_size; - u32 mc_filter_type; - u32 num_mc_addrs; - u32 collision_delta; - u32 tx_packet_delta; - u16 phy_spd_default; u16 dev_rev; /* spi flash */ u8 flash_vendor; - u8 dma_fairness; u8 mac_addr[ETH_ALEN]; u8 perm_mac_addr[ETH_ALEN]; - /* bool phy_preamble_sup; */ bool phy_configured; }; struct atl1_adapter { - /* OS defined structs */ struct net_device *netdev; struct pci_dev *pdev; struct net_device_stats net_stats; struct atl1_sft_stats soft_stats; - struct vlan_group *vlgrp; u32 rx_buffer_len; u32 wol; u16 link_speed; u16 link_duplex; spinlock_t lock; - atomic_t irq_sem; struct work_struct tx_timeout_task; struct work_struct link_chg_task; struct work_struct pcie_dma_to_rst_task; @@ -243,9 +258,7 @@ struct atl1_adapter { struct timer_list phy_config_timer; bool phy_timer_pending; - bool mac_disabled; - - /* All descriptor rings' memory */ + /* all descriptor rings' memory */ struct atl1_ring_header ring_header; /* TX */ @@ -258,25 +271,16 @@ struct atl1_adapter { u64 hw_csum_err; u64 hw_csum_good; - u32 gorcl; - u64 gorcl_old; - - /* Interrupt Moderator timer ( 2us resolution) */ - u16 imt; - /* Interrupt Clear timer (2us resolution) */ - u16 ict; - - /* MII interface info */ - struct mii_if_info mii; + u16 imt; /* interrupt moderator timer (2us resolution */ + u16 ict; /* interrupt clear timer (2us resolution */ + struct mii_if_info mii; /* MII interface info */ /* structs defined in atl1_hw.h */ - u32 bd_number; /* board number */ + u32 bd_number; /* board number */ bool pci_using_64; struct atl1_hw hw; struct atl1_smb smb; struct atl1_cmb cmb; - - u32 pci_state[16]; }; #endif /* _ATL1_H_ */ diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index 501919eb7f5..4a18b881ae9 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -38,7 +38,7 @@ * TODO: * Fix TSO; tx performance is horrible with TSO enabled. * Wake on LAN. - * Add more ethtool functions, including set ring parameters. + * Add more ethtool functions. * Fix abstruse irq enable/disable condition described here: * http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2 * @@ -158,13 +158,70 @@ static int __devinit atl1_sw_init(struct atl1_adapter *adapter) hw->cmb_tx_timer = 1; /* about 2us */ hw->smb_timer = 100000; /* about 200ms */ - atomic_set(&adapter->irq_sem, 0); spin_lock_init(&adapter->lock); spin_lock_init(&adapter->mb_lock); return 0; } +static int mdio_read(struct net_device *netdev, int phy_id, int reg_num) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + u16 result; + + atl1_read_phy_reg(&adapter->hw, reg_num & 0x1f, &result); + + return result; +} + +static void mdio_write(struct net_device *netdev, int phy_id, int reg_num, + int val) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + + atl1_write_phy_reg(&adapter->hw, reg_num, val); +} + +/* + * atl1_mii_ioctl - + * @netdev: + * @ifreq: + * @cmd: + */ +static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct atl1_adapter *adapter = netdev_priv(netdev); + unsigned long flags; + int retval; + + if (!netif_running(netdev)) + return -EINVAL; + + spin_lock_irqsave(&adapter->lock, flags); + retval = generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL); + spin_unlock_irqrestore(&adapter->lock, flags); + + return retval; +} + +/* + * atl1_ioctl - + * @netdev: + * @ifreq: + * @cmd: + */ +static int atl1_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return atl1_mii_ioctl(netdev, ifr, cmd); + default: + return -EOPNOTSUPP; + } +} + /* * atl1_setup_mem_resources - allocate Tx / RX descriptor resources * @adapter: board private structure @@ -188,19 +245,22 @@ s32 atl1_setup_ring_resources(struct atl1_adapter *adapter) goto err_nomem; } rfd_ring->buffer_info = - (struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count); + (struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count); - /* real ring DMA buffer */ - ring_header->size = size = sizeof(struct tx_packet_desc) * - tpd_ring->count - + sizeof(struct rx_free_desc) * rfd_ring->count - + sizeof(struct rx_return_desc) * rrd_ring->count - + sizeof(struct coals_msg_block) - + sizeof(struct stats_msg_block) - + 40; /* "40: for 8 bytes align" huh? -- CHS */ + /* real ring DMA buffer + * each ring/block may need up to 8 bytes for alignment, hence the + * additional 40 bytes tacked onto the end. + */ + ring_header->size = size = + sizeof(struct tx_packet_desc) * tpd_ring->count + + sizeof(struct rx_free_desc) * rfd_ring->count + + sizeof(struct rx_return_desc) * rrd_ring->count + + sizeof(struct coals_msg_block) + + sizeof(struct stats_msg_block) + + 40; ring_header->desc = pci_alloc_consistent(pdev, ring_header->size, - &ring_header->dma); + &ring_header->dma); if (unlikely(!ring_header->desc)) { dev_err(&pdev->dev, "pci_alloc_consistent failed\n"); goto err_nomem; @@ -214,8 +274,6 @@ s32 atl1_setup_ring_resources(struct atl1_adapter *adapter) tpd_ring->dma += offset; tpd_ring->desc = (u8 *) ring_header->desc + offset; tpd_ring->size = sizeof(struct tx_packet_desc) * tpd_ring->count; - atomic_set(&tpd_ring->next_to_use, 0); - atomic_set(&tpd_ring->next_to_clean, 0); /* init RFD ring */ rfd_ring->dma = tpd_ring->dma + tpd_ring->size; @@ -223,9 +281,7 @@ s32 atl1_setup_ring_resources(struct atl1_adapter *adapter) rfd_ring->dma += offset; rfd_ring->desc = (u8 *) tpd_ring->desc + (tpd_ring->size + offset); rfd_ring->size = sizeof(struct rx_free_desc) * rfd_ring->count; - rfd_ring->next_to_clean = 0; - /* rfd_ring->next_to_use = rfd_ring->count - 1; */ - atomic_set(&rfd_ring->next_to_use, 0); + /* init RRD ring */ rrd_ring->dma = rfd_ring->dma + rfd_ring->size; @@ -233,23 +289,22 @@ s32 atl1_setup_ring_resources(struct atl1_adapter *adapter) rrd_ring->dma += offset; rrd_ring->desc = (u8 *) rfd_ring->desc + (rfd_ring->size + offset); rrd_ring->size = sizeof(struct rx_return_desc) * rrd_ring->count; - rrd_ring->next_to_use = 0; - atomic_set(&rrd_ring->next_to_clean, 0); + /* init CMB */ adapter->cmb.dma = rrd_ring->dma + rrd_ring->size; offset = (adapter->cmb.dma & 0x7) ? (8 - (adapter->cmb.dma & 0x7)) : 0; adapter->cmb.dma += offset; - adapter->cmb.cmb = - (struct coals_msg_block *) ((u8 *) rrd_ring->desc + - (rrd_ring->size + offset)); + adapter->cmb.cmb = (struct coals_msg_block *) + ((u8 *) rrd_ring->desc + (rrd_ring->size + offset)); /* init SMB */ adapter->smb.dma = adapter->cmb.dma + sizeof(struct coals_msg_block); offset = (adapter->smb.dma & 0x7) ? (8 - (adapter->smb.dma & 0x7)) : 0; adapter->smb.dma += offset; adapter->smb.smb = (struct stats_msg_block *) - ((u8 *) adapter->cmb.cmb + (sizeof(struct coals_msg_block) + offset)); + ((u8 *) adapter->cmb.cmb + + (sizeof(struct coals_msg_block) + offset)); return ATL1_SUCCESS; @@ -258,559 +313,133 @@ err_nomem: return -ENOMEM; } -/* - * atl1_irq_enable - Enable default interrupt generation settings - * @adapter: board private structure - */ -static void atl1_irq_enable(struct atl1_adapter *adapter) -{ - if (likely(!atomic_dec_and_test(&adapter->irq_sem))) - iowrite32(IMR_NORMAL_MASK, adapter->hw.hw_addr + REG_IMR); -} - -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; -} - -static void atl1_rx_checksum(struct atl1_adapter *adapter, - struct rx_return_desc *rrd, - struct sk_buff *skb) +void atl1_init_ring_ptrs(struct atl1_adapter *adapter) { - 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_dbg(&adapter->pdev->dev, "rx checksum error\n"); - return; - } - } + struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; + struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring; + struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring; - /* not IPv4 */ - if (!(rrd->pkt_flg & PACKET_FLAG_IPV4)) - /* checksum is invalid, but it's not an IPv4 pkt, so ok */ - return; + atomic_set(&tpd_ring->next_to_use, 0); + atomic_set(&tpd_ring->next_to_clean, 0); - /* 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; - } + rfd_ring->next_to_clean = 0; + atomic_set(&rfd_ring->next_to_use, 0); - /* IPv4, but hardware thinks its checksum is wrong */ - dev_dbg(&adapter->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; + rrd_ring->next_to_use = 0; + atomic_set(&rrd_ring->next_to_clean, 0); } /* - * atl1_alloc_rx_buffers - Replace used receive buffers - * @adapter: address of board private structure + * atl1_clean_rx_ring - Free RFD Buffers + * @adapter: 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) +static void atl1_clean_rx_ring(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_dbg(&adapter->pdev->dev, - "incomplete RRD DMA transfer\n"); - udelay(1); - goto chk_rrd; - } - /* bad rrd */ - dev_dbg(&adapter->pdev->dev, "bad RRD\n"); - /* see if update RFD index */ - if (rrd->num_buf > 1) { - 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 */ - while (rfd_ring->next_to_clean != - (rrd->buf_indx + num_buf)) { - 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; - } - } - } - } - - /* 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 */ + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; - break; - } -rrd_ok: - /* clean alloc flag for bad rrd */ - while (rfd_ring->next_to_clean != rrd->buf_indx) { - 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; + /* Free all the Rx ring sk_buffs */ + for (i = 0; i < rfd_ring->count; i++) { + buffer_info = &rfd_ring->buffer_info[i]; + if (buffer_info->dma) { + pci_unmap_page(pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_FROMDEVICE); + buffer_info->dma = 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; - } + if (buffer_info->skb) { + dev_kfree_skb(buffer_info->skb); + buffer_info->skb = NULL; } - - /* 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 - ETHERNET_FCS_SIZE); - - /* 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); + size = sizeof(struct atl1_buffer) * rfd_ring->count; + memset(rfd_ring->buffer_info, 0, size); - /* update mailbox ? */ - if (count) { - u32 tpd_next_to_use; - u32 rfd_next_to_use; - u32 rrd_next_to_clean; + /* Zero out the descriptor ring */ + memset(rfd_ring->desc, 0, rfd_ring->size); - spin_lock(&adapter->mb_lock); + rfd_ring->next_to_clean = 0; + atomic_set(&rfd_ring->next_to_use, 0); - 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(&adapter->mb_lock); - } + rrd_ring->next_to_use = 0; + atomic_set(&rrd_ring->next_to_clean, 0); } -static void atl1_intr_tx(struct atl1_adapter *adapter) +/* + * atl1_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + */ +static void atl1_clean_tx_ring(struct atl1_adapter *adapter) { struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring; struct atl1_buffer *buffer_info; - u16 sw_tpd_next_to_clean; - u16 cmb_tpd_next_to_clean; - - sw_tpd_next_to_clean = atomic_read(&tpd_ring->next_to_clean); - cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx); - - while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) { - struct tx_packet_desc *tpd; + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; - tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean); - buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean]; + /* Free all the Tx ring sk_buffs */ + for (i = 0; i < tpd_ring->count; i++) { + buffer_info = &tpd_ring->buffer_info[i]; if (buffer_info->dma) { - pci_unmap_page(adapter->pdev, buffer_info->dma, - buffer_info->length, PCI_DMA_TODEVICE); + pci_unmap_page(pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); buffer_info->dma = 0; } + } + for (i = 0; i < tpd_ring->count; i++) { + buffer_info = &tpd_ring->buffer_info[i]; if (buffer_info->skb) { - dev_kfree_skb_irq(buffer_info->skb); + dev_kfree_skb_any(buffer_info->skb); buffer_info->skb = NULL; } - tpd->buffer_addr = 0; - tpd->desc.data = 0; - - if (++sw_tpd_next_to_clean == tpd_ring->count) - sw_tpd_next_to_clean = 0; } - atomic_set(&tpd_ring->next_to_clean, sw_tpd_next_to_clean); - - if (netif_queue_stopped(adapter->netdev) - && netif_carrier_ok(adapter->netdev)) - netif_wake_queue(adapter->netdev); -} -static void atl1_check_for_link(struct atl1_adapter *adapter) -{ - struct net_device *netdev = adapter->netdev; - u16 phy_data = 0; - - spin_lock(&adapter->lock); - adapter->phy_timer_pending = false; - atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); - atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); - spin_unlock(&adapter->lock); - - /* notify upper layer link down ASAP */ - if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */ - if (netif_carrier_ok(netdev)) { /* old link state: Up */ - dev_info(&adapter->pdev->dev, "%s link is down\n", - netdev->name); - adapter->link_speed = SPEED_0; - netif_carrier_off(netdev); - netif_stop_queue(netdev); - } - } - schedule_work(&adapter->link_chg_task); -} - -/* - * atl1_intr - Interrupt Handler - * @irq: interrupt number - * @data: pointer to a network interface device structure - * @pt_regs: CPU registers structure - */ -static irqreturn_t atl1_intr(int irq, void *data) -{ - /*struct atl1_adapter *adapter = ((struct net_device *)data)->priv;*/ - struct atl1_adapter *adapter = netdev_priv(data); - u32 status; - u8 update_rx; - int max_ints = 10; - - status = adapter->cmb.cmb->int_stats; - if (!status) - return IRQ_NONE; - - update_rx = 0; - - do { - /* clear CMB interrupt status at once */ - adapter->cmb.cmb->int_stats = 0; - - if (status & ISR_GPHY) /* clear phy status */ - atl1_clear_phy_int(adapter); - - /* clear ISR status, and Enable CMB DMA/Disable Interrupt */ - iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR); - - /* check if SMB intr */ - if (status & ISR_SMB) - atl1_inc_smb(adapter); - - /* check if PCIE PHY Link down */ - if (status & ISR_PHY_LINKDOWN) { - dev_dbg(&adapter->pdev->dev, "pcie phy link down %x\n", - status); - if (netif_running(adapter->netdev)) { /* reset MAC */ - iowrite32(0, adapter->hw.hw_addr + REG_IMR); - schedule_work(&adapter->pcie_dma_to_rst_task); - return IRQ_HANDLED; - } - } - - /* check if DMA read/write error ? */ - if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) { - dev_dbg(&adapter->pdev->dev, - "pcie DMA r/w error (status = 0x%x)\n", - status); - iowrite32(0, adapter->hw.hw_addr + REG_IMR); - schedule_work(&adapter->pcie_dma_to_rst_task); - return IRQ_HANDLED; - } - - /* link event */ - if (status & ISR_GPHY) { - adapter->soft_stats.tx_carrier_errors++; - atl1_check_for_link(adapter); - } - - /* transmit event */ - if (status & ISR_CMB_TX) - atl1_intr_tx(adapter); - - /* rx exception */ - if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN | - ISR_RRD_OV | ISR_HOST_RFD_UNRUN | - ISR_HOST_RRD_OV | ISR_CMB_RX))) { - if (status & (ISR_RXF_OV | ISR_RFD_UNRUN | - ISR_RRD_OV | ISR_HOST_RFD_UNRUN | - ISR_HOST_RRD_OV)) - dev_dbg(&adapter->pdev->dev, - "rx exception, ISR = 0x%x\n", status); - atl1_intr_rx(adapter); - |