diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 06:04:44 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 06:04:44 +0200 |
commit | f8965467f366fd18f01feafb5db10512d7b4422c (patch) | |
tree | 3706a9cd779859271ca61b85c63a1bc3f82d626e /drivers/net/ixgbe/ixgbe_sriov.c | |
parent | Merge branch 'docs-next' of git://git.lwn.net/linux-2.6 (diff) | |
parent | Merge branch 'master' of /home/davem/src/GIT/linux-2.6/ (diff) | |
download | linux-f8965467f366fd18f01feafb5db10512d7b4422c.tar.xz linux-f8965467f366fd18f01feafb5db10512d7b4422c.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1674 commits)
qlcnic: adding co maintainer
ixgbe: add support for active DA cables
ixgbe: dcb, do not tag tc_prio_control frames
ixgbe: fix ixgbe_tx_is_paused logic
ixgbe: always enable vlan strip/insert when DCB is enabled
ixgbe: remove some redundant code in setting FCoE FIP filter
ixgbe: fix wrong offset to fc_frame_header in ixgbe_fcoe_ddp
ixgbe: fix header len when unsplit packet overflows to data buffer
ipv6: Never schedule DAD timer on dead address
ipv6: Use POSTDAD state
ipv6: Use state_lock to protect ifa state
ipv6: Replace inet6_ifaddr->dead with state
cxgb4: notify upper drivers if the device is already up when they load
cxgb4: keep interrupts available when the ports are brought down
cxgb4: fix initial addition of MAC address
cnic: Return SPQ credit to bnx2x after ring setup and shutdown.
cnic: Convert cnic_local_flags to atomic ops.
can: Fix SJA1000 command register writes on SMP systems
bridge: fix build for CONFIG_SYSFS disabled
ARCNET: Limit com20020 PCI ID matches for SOHARD cards
...
Fix up various conflicts with pcmcia tree drivers/net/
{pcmcia/3c589_cs.c, wireless/orinoco/orinoco_cs.c and
wireless/orinoco/spectrum_cs.c} and feature removal
(Documentation/feature-removal-schedule.txt).
Also fix a non-content conflict due to pm_qos_requirement getting
renamed in the PM tree (now pm_qos_request) in net/mac80211/scan.c
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_sriov.c')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_sriov.c | 137 |
1 files changed, 117 insertions, 20 deletions
diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c index d4cd20f30199..f6cee94ec8e8 100644 --- a/drivers/net/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ixgbe/ixgbe_sriov.c @@ -48,7 +48,11 @@ int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter, int entries, u16 *hash_list, u32 vf) { struct vf_data_storage *vfinfo = &adapter->vfinfo[vf]; + struct ixgbe_hw *hw = &adapter->hw; int i; + u32 vector_bit; + u32 vector_reg; + u32 mta_reg; /* only so many hash values supported */ entries = min(entries, IXGBE_MAX_VF_MC_ENTRIES); @@ -68,8 +72,13 @@ int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter, vfinfo->vf_mc_hashes[i] = hash_list[i];; } - /* Flush and reset the mta with the new values */ - ixgbe_set_rx_mode(adapter->netdev); + for (i = 0; i < vfinfo->num_vf_mc_hashes; i++) { + vector_reg = (vfinfo->vf_mc_hashes[i] >> 5) & 0x7F; + vector_bit = vfinfo->vf_mc_hashes[i] & 0x1F; + mta_reg = IXGBE_READ_REG(hw, IXGBE_MTA(vector_reg)); + mta_reg |= (1 << vector_bit); + IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg); + } return 0; } @@ -98,38 +107,51 @@ void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter) int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid, u32 vf) { - u32 ctrl; - - /* Check if global VLAN already set, if not set it */ - ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL); - if (!(ctrl & IXGBE_VLNCTRL_VFE)) { - /* enable VLAN tag insert/strip */ - ctrl |= IXGBE_VLNCTRL_VFE; - ctrl &= ~IXGBE_VLNCTRL_CFIEN; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl); - } - return adapter->hw.mac.ops.set_vfta(&adapter->hw, vid, vf, (bool)add); } -void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf) +void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe) { u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf)); - vmolr |= (IXGBE_VMOLR_AUPE | - IXGBE_VMOLR_ROMPE | + vmolr |= (IXGBE_VMOLR_ROMPE | IXGBE_VMOLR_ROPE | IXGBE_VMOLR_BAM); + if (aupe) + vmolr |= IXGBE_VMOLR_AUPE; + else + vmolr &= ~IXGBE_VMOLR_AUPE; IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf), vmolr); } +static void ixgbe_set_vmvir(struct ixgbe_adapter *adapter, u32 vid, u32 vf) +{ + struct ixgbe_hw *hw = &adapter->hw; + + if (vid) + IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf), + (vid | IXGBE_VMVIR_VLANA_DEFAULT)); + else + IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf), 0); +} + inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf) { struct ixgbe_hw *hw = &adapter->hw; /* reset offloads to defaults */ - ixgbe_set_vmolr(hw, vf); - + if (adapter->vfinfo[vf].pf_vlan) { + ixgbe_set_vf_vlan(adapter, true, + adapter->vfinfo[vf].pf_vlan, vf); + ixgbe_set_vmvir(adapter, + (adapter->vfinfo[vf].pf_vlan | + (adapter->vfinfo[vf].pf_qos << + VLAN_PRIO_SHIFT)), vf); + ixgbe_set_vmolr(hw, vf, false); + } else { + ixgbe_set_vmvir(adapter, 0, vf); + ixgbe_set_vmolr(hw, vf, true); + } /* reset multicast table array for vf */ adapter->vfinfo[vf].num_vf_mc_hashes = 0; @@ -263,10 +285,12 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf) case IXGBE_VF_SET_MAC_ADDR: { u8 *new_mac = ((u8 *)(&msgbuf[1])); - if (is_valid_ether_addr(new_mac)) + if (is_valid_ether_addr(new_mac) && + !adapter->vfinfo[vf].pf_set_mac) ixgbe_set_vf_mac(adapter, vf, new_mac); else - retval = -1; + ixgbe_set_vf_mac(adapter, + vf, adapter->vfinfo[vf].vf_mac_addresses); } break; case IXGBE_VF_SET_MULTICAST: @@ -360,3 +384,76 @@ void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter) } } +int ixgbe_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + if (!is_valid_ether_addr(mac) || (vf >= adapter->num_vfs)) + return -EINVAL; + adapter->vfinfo[vf].pf_set_mac = true; + dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n", mac, vf); + dev_info(&adapter->pdev->dev, "Reload the VF driver to make this" + " change effective."); + if (test_bit(__IXGBE_DOWN, &adapter->state)) { + dev_warn(&adapter->pdev->dev, "The VF MAC address has been set," + " but the PF device is not up.\n"); + dev_warn(&adapter->pdev->dev, "Bring the PF device up before" + " attempting to use the VF device.\n"); + } + return ixgbe_set_vf_mac(adapter, vf, mac); +} + +int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos) +{ + int err = 0; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if ((vf >= adapter->num_vfs) || (vlan > 4095) || (qos > 7)) + return -EINVAL; + if (vlan || qos) { + err = ixgbe_set_vf_vlan(adapter, true, vlan, vf); + if (err) + goto out; + ixgbe_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf); + ixgbe_set_vmolr(&adapter->hw, vf, false); + adapter->vfinfo[vf].pf_vlan = vlan; + adapter->vfinfo[vf].pf_qos = qos; + dev_info(&adapter->pdev->dev, + "Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf); + if (test_bit(__IXGBE_DOWN, &adapter->state)) { + dev_warn(&adapter->pdev->dev, + "The VF VLAN has been set," + " but the PF device is not up.\n"); + dev_warn(&adapter->pdev->dev, + "Bring the PF device up before" + " attempting to use the VF device.\n"); + } + } else { + err = ixgbe_set_vf_vlan(adapter, false, + adapter->vfinfo[vf].pf_vlan, vf); + ixgbe_set_vmvir(adapter, vlan, vf); + ixgbe_set_vmolr(&adapter->hw, vf, true); + adapter->vfinfo[vf].pf_vlan = 0; + adapter->vfinfo[vf].pf_qos = 0; + } +out: + return err; +} + +int ixgbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate) +{ + return -EOPNOTSUPP; +} + +int ixgbe_ndo_get_vf_config(struct net_device *netdev, + int vf, struct ifla_vf_info *ivi) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + if (vf >= adapter->num_vfs) + return -EINVAL; + ivi->vf = vf; + memcpy(&ivi->mac, adapter->vfinfo[vf].vf_mac_addresses, ETH_ALEN); + ivi->tx_rate = 0; + ivi->vlan = adapter->vfinfo[vf].pf_vlan; + ivi->qos = adapter->vfinfo[vf].pf_qos; + return 0; +} |