igb: Add support for enabling VFs to PF driver.

This patch adds the support to handle requests from the VF to perform
operations such as completing resets, setting/reading mac address, adding
vlans, adding multicast addresses, setting rlpml, and general
communications between the PF and all VFs.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Alexander Duyck
2009-02-19 20:40:07 -08:00
committed by David S. Miller
parent e173952257
commit 4ae196dfd6
12 changed files with 1077 additions and 26 deletions

View File

@@ -122,10 +122,16 @@ static void igb_vlan_rx_register(struct net_device *, struct vlan_group *);
static void igb_vlan_rx_add_vid(struct net_device *, u16);
static void igb_vlan_rx_kill_vid(struct net_device *, u16);
static void igb_restore_vlan(struct igb_adapter *);
static void igb_ping_all_vfs(struct igb_adapter *);
static void igb_msg_task(struct igb_adapter *);
static int igb_rcv_msg_from_vf(struct igb_adapter *, u32);
static inline void igb_set_rah_pool(struct e1000_hw *, int , int);
static void igb_set_mc_list_pools(struct igb_adapter *, int, u16);
static void igb_vmm_control(struct igb_adapter *);
static inline void igb_set_vmolr(struct e1000_hw *, int);
static inline void igb_set_vf_rlpml(struct igb_adapter *, int, int);
static inline int igb_set_vf_rlpml(struct igb_adapter *, int, int);
static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *);
static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
static int igb_suspend(struct pci_dev *, pm_message_t);
#ifdef CONFIG_PM
@@ -768,7 +774,10 @@ static void igb_irq_enable(struct igb_adapter *adapter)
wr32(E1000_EIAC, adapter->eims_enable_mask);
wr32(E1000_EIAM, adapter->eims_enable_mask);
wr32(E1000_EIMS, adapter->eims_enable_mask);
wr32(E1000_IMS, E1000_IMS_LSC | E1000_IMS_DOUTSYNC);
if (adapter->vfs_allocated_count)
wr32(E1000_MBVFIMR, 0xFF);
wr32(E1000_IMS, (E1000_IMS_LSC | E1000_IMS_VMMB |
E1000_IMS_DOUTSYNC));
} else {
wr32(E1000_IMS, IMS_ENABLE_MASK);
wr32(E1000_IAM, IMS_ENABLE_MASK);
@@ -892,6 +901,7 @@ int igb_up(struct igb_adapter *adapter)
if (adapter->msix_entries)
igb_configure_msix(adapter);
igb_vmm_control(adapter);
igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0);
igb_set_vmolr(hw, adapter->vfs_allocated_count);
@@ -1047,6 +1057,20 @@ void igb_reset(struct igb_adapter *adapter)
fc->send_xon = 1;
fc->type = fc->original_type;
/* disable receive for all VFs and wait one second */
if (adapter->vfs_allocated_count) {
int i;
for (i = 0 ; i < adapter->vfs_allocated_count; i++)
adapter->vf_data[i].clear_to_send = false;
/* ping all the active vfs to let them know we are going down */
igb_ping_all_vfs(adapter);
/* disable transmits and receives */
wr32(E1000_VFRE, 0);
wr32(E1000_VFTE, 0);
}
/* Allow time for pending master requests to run */
adapter->hw.mac.ops.reset_hw(&adapter->hw);
wr32(E1000_WUC, 0);
@@ -1624,6 +1648,7 @@ static int igb_open(struct net_device *netdev)
* clean_rx handler before we do so. */
igb_configure(adapter);
igb_vmm_control(adapter);
igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0);
igb_set_vmolr(hw, adapter->vfs_allocated_count);
@@ -2456,6 +2481,8 @@ static void igb_set_multi(struct net_device *netdev)
mac->rar_entry_count);
igb_set_mc_list_pools(adapter, i, mac->rar_entry_count);
igb_restore_vf_multicasts(adapter);
kfree(mta_list);
}
@@ -2571,6 +2598,8 @@ static void igb_watchdog_task(struct work_struct *work)
netif_carrier_on(netdev);
netif_tx_wake_all_queues(netdev);
igb_ping_all_vfs(adapter);
/* link state has changed, schedule phy info update */
if (!test_bit(__IGB_DOWN, &adapter->state))
mod_timer(&adapter->phy_info_timer,
@@ -2586,6 +2615,8 @@ static void igb_watchdog_task(struct work_struct *work)
netif_carrier_off(netdev);
netif_tx_stop_all_queues(netdev);
igb_ping_all_vfs(adapter);
/* link state has changed, schedule phy info update */
if (!test_bit(__IGB_DOWN, &adapter->state))
mod_timer(&adapter->phy_info_timer,
@@ -3523,15 +3554,19 @@ static irqreturn_t igb_msix_other(int irq, void *data)
/* HW is reporting DMA is out of sync */
adapter->stats.doosync++;
}
if (!(icr & E1000_ICR_LSC))
goto no_link_interrupt;
hw->mac.get_link_status = 1;
/* guard against interrupt when we're going down */
if (!test_bit(__IGB_DOWN, &adapter->state))
mod_timer(&adapter->watchdog_timer, jiffies + 1);
no_link_interrupt:
wr32(E1000_IMS, E1000_IMS_LSC | E1000_IMS_DOUTSYNC);
/* Check for a mailbox event */
if (icr & E1000_ICR_VMMB)
igb_msg_task(adapter);
if (icr & E1000_ICR_LSC) {
hw->mac.get_link_status = 1;
/* guard against interrupt when we're going down */
if (!test_bit(__IGB_DOWN, &adapter->state))
mod_timer(&adapter->watchdog_timer, jiffies + 1);
}
wr32(E1000_IMS, E1000_IMS_LSC | E1000_IMS_DOUTSYNC | E1000_IMS_VMMB);
wr32(E1000_EIMS, adapter->eims_other);
return IRQ_HANDLED;
@@ -3719,6 +3754,317 @@ static int igb_notify_dca(struct notifier_block *nb, unsigned long event,
}
#endif /* CONFIG_IGB_DCA */
static void igb_ping_all_vfs(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 ping;
int i;
for (i = 0 ; i < adapter->vfs_allocated_count; i++) {
ping = E1000_PF_CONTROL_MSG;
if (adapter->vf_data[i].clear_to_send)
ping |= E1000_VT_MSGTYPE_CTS;
igb_write_mbx(hw, &ping, 1, i);
}
}
static int igb_set_vf_multicasts(struct igb_adapter *adapter,
u32 *msgbuf, u32 vf)
{
int n = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
u16 *hash_list = (u16 *)&msgbuf[1];
struct vf_data_storage *vf_data = &adapter->vf_data[vf];
int i;
/* only up to 30 hash values supported */
if (n > 30)
n = 30;
/* salt away the number of multi cast addresses assigned
* to this VF for later use to restore when the PF multi cast
* list changes
*/
vf_data->num_vf_mc_hashes = n;
/* VFs are limited to using the MTA hash table for their multicast
* addresses */
for (i = 0; i < n; i++)
vf_data->vf_mc_hashes[i] = hash_list[i];;
/* Flush and reset the mta with the new values */
igb_set_multi(adapter->netdev);
return 0;
}
static void igb_restore_vf_multicasts(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
struct vf_data_storage *vf_data;
int i, j;
for (i = 0; i < adapter->vfs_allocated_count; i++) {
vf_data = &adapter->vf_data[i];
for (j = 0; j < vf_data[i].num_vf_mc_hashes; j++)
igb_mta_set(hw, vf_data->vf_mc_hashes[j]);
}
}
static void igb_clear_vf_vfta(struct igb_adapter *adapter, u32 vf)
{
struct e1000_hw *hw = &adapter->hw;
u32 pool_mask, reg, vid;
int i;
pool_mask = 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
/* Find the vlan filter for this id */
for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
reg = rd32(E1000_VLVF(i));
/* remove the vf from the pool */
reg &= ~pool_mask;
/* if pool is empty then remove entry from vfta */
if (!(reg & E1000_VLVF_POOLSEL_MASK) &&
(reg & E1000_VLVF_VLANID_ENABLE)) {
reg = 0;
vid = reg & E1000_VLVF_VLANID_MASK;
igb_vfta_set(hw, vid, false);
}
wr32(E1000_VLVF(i), reg);
}
}
static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf)
{
struct e1000_hw *hw = &adapter->hw;
u32 reg, i;
/* It is an error to call this function when VFs are not enabled */
if (!adapter->vfs_allocated_count)
return -1;
/* Find the vlan filter for this id */
for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
reg = rd32(E1000_VLVF(i));
if ((reg & E1000_VLVF_VLANID_ENABLE) &&
vid == (reg & E1000_VLVF_VLANID_MASK))
break;
}
if (add) {
if (i == E1000_VLVF_ARRAY_SIZE) {
/* Did not find a matching VLAN ID entry that was
* enabled. Search for a free filter entry, i.e.
* one without the enable bit set
*/
for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
reg = rd32(E1000_VLVF(i));
if (!(reg & E1000_VLVF_VLANID_ENABLE))
break;
}
}
if (i < E1000_VLVF_ARRAY_SIZE) {
/* Found an enabled/available entry */
reg |= 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
/* if !enabled we need to set this up in vfta */
if (!(reg & E1000_VLVF_VLANID_ENABLE)) {
/* add VID to filter table */
igb_vfta_set(hw, vid, true);
reg |= E1000_VLVF_VLANID_ENABLE;
}
wr32(E1000_VLVF(i), reg);
return 0;
}
} else {
if (i < E1000_VLVF_ARRAY_SIZE) {
/* remove vf from the pool */
reg &= ~(1 << (E1000_VLVF_POOLSEL_SHIFT + vf));
/* if pool is empty then remove entry from vfta */
if (!(reg & E1000_VLVF_POOLSEL_MASK)) {
reg = 0;
igb_vfta_set(hw, vid, false);
}
wr32(E1000_VLVF(i), reg);
return 0;
}
}
return -1;
}
static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
{
int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
return igb_vlvf_set(adapter, vid, add, vf);
}
static inline void igb_vf_reset_event(struct igb_adapter *adapter, u32 vf)
{
struct e1000_hw *hw = &adapter->hw;
/* disable mailbox functionality for vf */
adapter->vf_data[vf].clear_to_send = false;
/* reset offloads to defaults */
igb_set_vmolr(hw, vf);
/* reset vlans for device */
igb_clear_vf_vfta(adapter, vf);
/* reset multicast table array for vf */
adapter->vf_data[vf].num_vf_mc_hashes = 0;
/* Flush and reset the mta with the new values */
igb_set_multi(adapter->netdev);
}
static inline void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf)
{
struct e1000_hw *hw = &adapter->hw;
unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses;
u32 reg, msgbuf[3];
u8 *addr = (u8 *)(&msgbuf[1]);
/* process all the same items cleared in a function level reset */
igb_vf_reset_event(adapter, vf);
/* set vf mac address */
igb_rar_set(hw, vf_mac, vf + 1);
igb_set_rah_pool(hw, vf, vf + 1);
/* enable transmit and receive for vf */
reg = rd32(E1000_VFTE);
wr32(E1000_VFTE, reg | (1 << vf));
reg = rd32(E1000_VFRE);
wr32(E1000_VFRE, reg | (1 << vf));
/* enable mailbox functionality for vf */
adapter->vf_data[vf].clear_to_send = true;
/* reply to reset with ack and vf mac address */
msgbuf[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_ACK;
memcpy(addr, vf_mac, 6);
igb_write_mbx(hw, msgbuf, 3, vf);
}
static int igb_set_vf_mac_addr(struct igb_adapter *adapter, u32 *msg, int vf)
{
unsigned char *addr = (char *)&msg[1];
int err = -1;
if (is_valid_ether_addr(addr))
err = igb_set_vf_mac(adapter, vf, addr);
return err;
}
static void igb_rcv_ack_from_vf(struct igb_adapter *adapter, u32 vf)
{
struct e1000_hw *hw = &adapter->hw;
u32 msg = E1000_VT_MSGTYPE_NACK;
/* if device isn't clear to send it shouldn't be reading either */
if (!adapter->vf_data[vf].clear_to_send)
igb_write_mbx(hw, &msg, 1, vf);
}
static void igb_msg_task(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 vf;
for (vf = 0; vf < adapter->vfs_allocated_count; vf++) {
/* process any reset requests */
if (!igb_check_for_rst(hw, vf)) {
adapter->vf_data[vf].clear_to_send = false;
igb_vf_reset_event(adapter, vf);
}
/* process any messages pending */
if (!igb_check_for_msg(hw, vf))
igb_rcv_msg_from_vf(adapter, vf);
/* process any acks */
if (!igb_check_for_ack(hw, vf))
igb_rcv_ack_from_vf(adapter, vf);
}
}
static int igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
{
u32 mbx_size = E1000_VFMAILBOX_SIZE;
u32 msgbuf[mbx_size];
struct e1000_hw *hw = &adapter->hw;
s32 retval;
retval = igb_read_mbx(hw, msgbuf, mbx_size, vf);
if (retval)
dev_err(&adapter->pdev->dev,
"Error receiving message from VF\n");
/* this is a message we already processed, do nothing */
if (msgbuf[0] & (E1000_VT_MSGTYPE_ACK | E1000_VT_MSGTYPE_NACK))
return retval;
/*
* until the vf completes a reset it should not be
* allowed to start any configuration.
*/
if (msgbuf[0] == E1000_VF_RESET) {
igb_vf_reset_msg(adapter, vf);
return retval;
}
if (!adapter->vf_data[vf].clear_to_send) {
msgbuf[0] |= E1000_VT_MSGTYPE_NACK;
igb_write_mbx(hw, msgbuf, 1, vf);
return retval;
}
switch ((msgbuf[0] & 0xFFFF)) {
case E1000_VF_SET_MAC_ADDR:
retval = igb_set_vf_mac_addr(adapter, msgbuf, vf);
break;
case E1000_VF_SET_MULTICAST:
retval = igb_set_vf_multicasts(adapter, msgbuf, vf);
break;
case E1000_VF_SET_LPE:
retval = igb_set_vf_rlpml(adapter, msgbuf[1], vf);
break;
case E1000_VF_SET_VLAN:
retval = igb_set_vf_vlan(adapter, msgbuf, vf);
break;
default:
dev_err(&adapter->pdev->dev, "Unhandled Msg %08x\n", msgbuf[0]);
retval = -1;
break;
}
/* notify the VF of the results of what it sent us */
if (retval)
msgbuf[0] |= E1000_VT_MSGTYPE_NACK;
else
msgbuf[0] |= E1000_VT_MSGTYPE_ACK;
msgbuf[0] |= E1000_VT_MSGTYPE_CTS;
igb_write_mbx(hw, msgbuf, 1, vf);
return retval;
}
/**
* igb_intr_msi - Interrupt Handler
* @irq: interrupt number
@@ -4582,24 +4928,25 @@ static void igb_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
u32 vfta, index;
int pf_id = adapter->vfs_allocated_count;
if ((hw->mng_cookie.status &
E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
(vid == adapter->mng_vlan_id))
return;
/* add VID to filter table */
index = (vid >> 5) & 0x7F;
vfta = array_rd32(E1000_VFTA, index);
vfta |= (1 << (vid & 0x1F));
igb_write_vfta(&adapter->hw, index, vfta);
/* add vid to vlvf if sr-iov is enabled,
* if that fails add directly to filter table */
if (igb_vlvf_set(adapter, vid, true, pf_id))
igb_vfta_set(hw, vid, true);
}
static void igb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
u32 vfta, index;
int pf_id = adapter->vfs_allocated_count;
igb_irq_disable(adapter);
vlan_group_set_device(adapter->vlgrp, vid, NULL);
@@ -4615,11 +4962,10 @@ static void igb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
return;
}
/* remove VID from filter table */
index = (vid >> 5) & 0x7F;
vfta = array_rd32(E1000_VFTA, index);
vfta &= ~(1 << (vid & 0x1F));
igb_write_vfta(&adapter->hw, index, vfta);
/* remove vid from vlvf if sr-iov is enabled,
* if not in vlvf remove from vfta */
if (igb_vlvf_set(adapter, vid, false, pf_id))
igb_vfta_set(hw, vid, false);
}
static void igb_restore_vlan(struct igb_adapter *adapter)
@@ -4950,8 +5296,8 @@ static inline void igb_set_vmolr(struct e1000_hw *hw, int vfn)
wr32(E1000_VMOLR(vfn), reg_data);
}
static inline void igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
int vfn)
static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
int vfn)
{
struct e1000_hw *hw = &adapter->hw;
u32 vmolr;
@@ -4960,6 +5306,8 @@ static inline void igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
vmolr &= ~E1000_VMOLR_RLPML_MASK;
vmolr |= size | E1000_VMOLR_LPE;
wr32(E1000_VMOLR(vfn), vmolr);
return 0;
}
static inline void igb_set_rah_pool(struct e1000_hw *hw, int pool, int entry)
@@ -4985,4 +5333,37 @@ static void igb_set_mc_list_pools(struct igb_adapter *adapter,
igb_set_rah_pool(hw, adapter->vfs_allocated_count, i);
}
static int igb_set_vf_mac(struct igb_adapter *adapter,
int vf, unsigned char *mac_addr)
{
struct e1000_hw *hw = &adapter->hw;
int rar_entry = vf + 1; /* VF MAC addresses start at entry 1 */
igb_rar_set(hw, mac_addr, rar_entry);
memcpy(adapter->vf_data[vf].vf_mac_addresses, mac_addr, 6);
igb_set_rah_pool(hw, vf, rar_entry);
return 0;
}
static void igb_vmm_control(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 reg_data;
if (!adapter->vfs_allocated_count)
return;
/* VF's need PF reset indication before they
* can send/receive mail */
reg_data = rd32(E1000_CTRL_EXT);
reg_data |= E1000_CTRL_EXT_PFRSTD;
wr32(E1000_CTRL_EXT, reg_data);
igb_vmdq_set_loopback_pf(hw, true);
igb_vmdq_set_replication_pf(hw, true);
}
/* igb_main.c */