diff options
author | jfv <jfv@FreeBSD.org> | 2010-03-27 00:21:40 +0000 |
---|---|---|
committer | jfv <jfv@FreeBSD.org> | 2010-03-27 00:21:40 +0000 |
commit | 8918ac92eb689cbcb11b62d022055dc35be8307c (patch) | |
tree | 56ba93eba1abadf72b500969032db51e45f29957 /sys/dev/ixgbe/ixgbe_common.c | |
parent | fad010c73280e52d3a801acaf764cba507a95a66 (diff) | |
download | FreeBSD-src-8918ac92eb689cbcb11b62d022055dc35be8307c.zip FreeBSD-src-8918ac92eb689cbcb11b62d022055dc35be8307c.tar.gz |
Update the driver to Intel version 2.1.6
- add some new hardware support for 82599
- Big change to interrupt architecture, it now
uses a queue which contains an RX/TX pair as
the recipient of the interrupt. This will reduce
overall system interrupts/msix usage.
- Improved RX mbuf handling: the old get_buf routine
is no longer synchronized with rxeof, this allows
the elimination of packet discards due to mbuf
allocation failure.
- Much simplified and improved AIM code, it now
happens in the queue interrupt context and takes
into account both the traffic on the RX AND TX
side.
- variety of small tweaks, like ring size, that have
been seen as performance improvements.
- Thanks to those that provided feedback or suggested
changes, I hope I've caught all of them.
Diffstat (limited to 'sys/dev/ixgbe/ixgbe_common.c')
-rw-r--r-- | sys/dev/ixgbe/ixgbe_common.c | 157 |
1 files changed, 118 insertions, 39 deletions
diff --git a/sys/dev/ixgbe/ixgbe_common.c b/sys/dev/ixgbe/ixgbe_common.c index 89e57d8..217c477 100644 --- a/sys/dev/ixgbe/ixgbe_common.c +++ b/sys/dev/ixgbe/ixgbe_common.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -474,8 +474,7 @@ s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw) * Prevent the PCI-E bus from from hanging by disabling PCI-E master * access and verify no pending requests */ - if (ixgbe_disable_pcie_master(hw) != IXGBE_SUCCESS) - DEBUGOUT("PCI-E Master disable polling has failed.\n"); + ixgbe_disable_pcie_master(hw); return IXGBE_SUCCESS; } @@ -2198,10 +2197,14 @@ s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) u32 i; u32 reg_val; u32 number_of_queues; - s32 status = IXGBE_ERR_MASTER_REQUESTS_PENDING; + s32 status = IXGBE_SUCCESS; DEBUGFUNC("ixgbe_disable_pcie_master"); + /* Just jump out if bus mastering is already disabled */ + if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) + goto out; + /* Disable the receive unit by stopping each queue */ number_of_queues = hw->mac.max_rx_queues; for (i = 0; i < number_of_queues; i++) { @@ -2217,13 +2220,42 @@ s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_CTRL, reg_val); for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) { - if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) { - status = IXGBE_SUCCESS; + if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) + goto out; + usec_delay(100); + } + + DEBUGOUT("GIO Master Disable bit didn't clear - requesting resets\n"); + status = IXGBE_ERR_MASTER_REQUESTS_PENDING; + + /* + * The GIO Master Disable bit didn't clear. There are multiple reasons + * for this listed in the datasheet 5.2.5.3.2 Master Disable, and they + * all require a double reset to recover from. Before proceeding, we + * first wait a little more to try to ensure that, at a minimum, the + * PCIe block has no transactions pending. + */ + for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) { + if (!(IXGBE_READ_PCIE_WORD(hw, IXGBE_PCI_DEVICE_STATUS) & + IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING)) break; - } usec_delay(100); } + if (i == IXGBE_PCI_MASTER_DISABLE_TIMEOUT) + DEBUGOUT("PCIe transaction pending bit also did not clear.\n"); + + /* + * Two consecutive resets are required via CTRL.RST per datasheet + * 5.2.5.3.2 Master Disable. We set a flag to inform the reset routine + * of this need. The first reset prevents new master requests from + * being issued by our device. We then must wait 1usec for any + * remaining completions from the PCIe bus to trickle in, and then reset + * again to clear out any effects they may have had on our device. + */ + hw->mac.flags |= IXGBE_FLAGS_DOUBLE_RESET_REQUIRED; + +out: return status; } @@ -2695,6 +2727,10 @@ s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan) u32 first_empty_slot = 0; s32 regindex; + /* short cut the special case */ + if (vlan == 0) + return 0; + /* * Search for the vlan id in the VLVF entries. Save off the first empty * slot found along the way @@ -2717,7 +2753,7 @@ s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan) regindex = first_empty_slot; else { DEBUGOUT("No space in VLVF.\n"); - regindex = -1; + regindex = IXGBE_ERR_NO_SPACE; } } @@ -2738,8 +2774,11 @@ s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind, { s32 regindex; u32 bitindex; + u32 vfta; u32 bits; u32 vt; + u32 targetbit; + bool vfta_changed = FALSE; DEBUGFUNC("ixgbe_set_vfta_generic"); @@ -2749,6 +2788,7 @@ s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind, /* * this is a 2 part operation - first the VFTA, then the * VLVF and VLVFB if VT Mode is set + * We don't write the VFTA until we know the VLVF part succeeded. */ /* Part 1 @@ -2759,13 +2799,20 @@ s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind, */ regindex = (vlan >> 5) & 0x7F; bitindex = vlan & 0x1F; - bits = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex)); - if (vlan_on) - bits |= (1 << bitindex); - else - bits &= ~(1 << bitindex); - IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), bits); + targetbit = (1 << bitindex); + vfta = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex)); + if (vlan_on) { + if (!(vfta & targetbit)) { + vfta |= targetbit; + vfta_changed = TRUE; + } + } else { + if ((vfta & targetbit)) { + vfta &= ~targetbit; + vfta_changed = TRUE; + } + } /* Part 2 * If VT Mode is set @@ -2777,61 +2824,84 @@ s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind, */ vt = IXGBE_READ_REG(hw, IXGBE_VT_CTL); if (vt & IXGBE_VT_CTL_VT_ENABLE) { - if (vlan == 0) { - regindex = 0; - } else { - regindex = ixgbe_find_vlvf_slot(hw, vlan); - if (regindex < 0) - goto out; - } + s32 vlvf_index; + + vlvf_index = ixgbe_find_vlvf_slot(hw, vlan); + if (vlvf_index < 0) + return vlvf_index; if (vlan_on) { /* set the pool bit */ if (vind < 32) { bits = IXGBE_READ_REG(hw, - IXGBE_VLVFB(regindex*2)); + IXGBE_VLVFB(vlvf_index*2)); bits |= (1 << vind); IXGBE_WRITE_REG(hw, - IXGBE_VLVFB(regindex*2), + IXGBE_VLVFB(vlvf_index*2), bits); } else { bits = IXGBE_READ_REG(hw, - IXGBE_VLVFB((regindex*2)+1)); - bits |= (1 << vind); + IXGBE_VLVFB((vlvf_index*2)+1)); + bits |= (1 << (vind-32)); IXGBE_WRITE_REG(hw, - IXGBE_VLVFB((regindex*2)+1), + IXGBE_VLVFB((vlvf_index*2)+1), bits); } } else { /* clear the pool bit */ if (vind < 32) { bits = IXGBE_READ_REG(hw, - IXGBE_VLVFB(regindex*2)); + IXGBE_VLVFB(vlvf_index*2)); bits &= ~(1 << vind); IXGBE_WRITE_REG(hw, - IXGBE_VLVFB(regindex*2), + IXGBE_VLVFB(vlvf_index*2), bits); bits |= IXGBE_READ_REG(hw, - IXGBE_VLVFB((regindex*2)+1)); + IXGBE_VLVFB((vlvf_index*2)+1)); } else { bits = IXGBE_READ_REG(hw, - IXGBE_VLVFB((regindex*2)+1)); - bits &= ~(1 << vind); + IXGBE_VLVFB((vlvf_index*2)+1)); + bits &= ~(1 << (vind-32)); IXGBE_WRITE_REG(hw, - IXGBE_VLVFB((regindex*2)+1), + IXGBE_VLVFB((vlvf_index*2)+1), bits); bits |= IXGBE_READ_REG(hw, - IXGBE_VLVFB(regindex*2)); + IXGBE_VLVFB(vlvf_index*2)); } } - if (bits) - IXGBE_WRITE_REG(hw, IXGBE_VLVF(regindex), + /* + * If there are still bits set in the VLVFB registers + * for the VLAN ID indicated we need to see if the + * caller is requesting that we clear the VFTA entry bit. + * If the caller has requested that we clear the VFTA + * entry bit but there are still pools/VFs using this VLAN + * ID entry then ignore the request. We're not worried + * about the case where we're turning the VFTA VLAN ID + * entry bit on, only when requested to turn it off as + * there may be multiple pools and/or VFs using the + * VLAN ID entry. In that case we cannot clear the + * VFTA bit until all pools/VFs using that VLAN ID have also + * been cleared. This will be indicated by "bits" being + * zero. + */ + if (bits) { + IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), (IXGBE_VLVF_VIEN | vlan)); + if (!vlan_on) { + /* someone wants to clear the vfta entry + * but some pools/VFs are still using it. + * Ignore it. */ + vfta_changed = FALSE; + } + } else - IXGBE_WRITE_REG(hw, IXGBE_VLVF(regindex), 0); + IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), 0); } -out: + + if (vfta_changed) + IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), vfta); + return IXGBE_SUCCESS; } @@ -2869,14 +2939,23 @@ s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw) * Reads the links register to determine if link is up and the current speed **/ s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, - bool *link_up, bool link_up_wait_to_complete) + bool *link_up, bool link_up_wait_to_complete) { - u32 links_reg; + u32 links_reg, links_orig; u32 i; DEBUGFUNC("ixgbe_check_mac_link_generic"); + /* clear the old state */ + links_orig = IXGBE_READ_REG(hw, IXGBE_LINKS); + links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); + + if (links_orig != links_reg) { + DEBUGOUT2("LINKS changed from %08X to %08X\n", + links_orig, links_reg); + } + if (link_up_wait_to_complete) { for (i = 0; i < IXGBE_LINK_UP_TIME; i++) { if (links_reg & IXGBE_LINKS_UP) { |