diff options
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.c | 27 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_cmds.h | 17 | ||||
-rw-r--r-- | drivers/net/ethernet/emulex/benet/be_main.c | 77 |
3 files changed, 108 insertions, 13 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 52c9085ba5a1..1ab5dab11eff 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -2876,7 +2876,7 @@ int be_cmd_set_mac(struct be_adapter *adapter, u8 *mac, int if_id, u32 dom) } int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid, - u32 domain, u16 intf_id) + u32 domain, u16 intf_id, u16 hsw_mode) { struct be_mcc_wrb *wrb; struct be_cmd_req_set_hsw_config *req; @@ -2903,6 +2903,13 @@ int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid, AMAP_SET_BITS(struct amap_set_hsw_context, pvid_valid, ctxt, 1); AMAP_SET_BITS(struct amap_set_hsw_context, pvid, ctxt, pvid); } + if (!BEx_chip(adapter) && hsw_mode) { + AMAP_SET_BITS(struct amap_set_hsw_context, interface_id, + ctxt, adapter->hba_port_num); + AMAP_SET_BITS(struct amap_set_hsw_context, pport, ctxt, 1); + AMAP_SET_BITS(struct amap_set_hsw_context, port_fwd_type, + ctxt, hsw_mode); + } be_dws_cpu_to_le(req->context, sizeof(req->context)); status = be_mcc_notify_wait(adapter); @@ -2914,7 +2921,7 @@ err: /* Get Hyper switch config */ int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, - u32 domain, u16 intf_id) + u32 domain, u16 intf_id, u8 *mode) { struct be_mcc_wrb *wrb; struct be_cmd_req_get_hsw_config *req; @@ -2937,9 +2944,15 @@ int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, OPCODE_COMMON_GET_HSW_CONFIG, sizeof(*req), wrb, NULL); req->hdr.domain = domain; - AMAP_SET_BITS(struct amap_get_hsw_req_context, interface_id, ctxt, - intf_id); + AMAP_SET_BITS(struct amap_get_hsw_req_context, interface_id, + ctxt, intf_id); AMAP_SET_BITS(struct amap_get_hsw_req_context, pvid_valid, ctxt, 1); + + if (!BEx_chip(adapter)) { + AMAP_SET_BITS(struct amap_get_hsw_req_context, interface_id, + ctxt, adapter->hba_port_num); + AMAP_SET_BITS(struct amap_get_hsw_req_context, pport, ctxt, 1); + } be_dws_cpu_to_le(req->context, sizeof(req->context)); status = be_mcc_notify_wait(adapter); @@ -2950,7 +2963,11 @@ int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, sizeof(resp->context)); vid = AMAP_GET_BITS(struct amap_get_hsw_resp_context, pvid, &resp->context); - *pvid = le16_to_cpu(vid); + if (pvid) + *pvid = le16_to_cpu(vid); + if (mode) + *mode = AMAP_GET_BITS(struct amap_get_hsw_resp_context, + port_fwd_type, &resp->context); } err: diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 52f3d4ca0056..d026226db88c 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1533,12 +1533,17 @@ struct be_cmd_req_set_mac_list { } __packed; /*********************** HSW Config ***********************/ +#define PORT_FWD_TYPE_VEPA 0x3 +#define PORT_FWD_TYPE_VEB 0x2 + struct amap_set_hsw_context { u8 interface_id[16]; u8 rsvd0[14]; u8 pvid_valid; - u8 rsvd1; - u8 rsvd2[16]; + u8 pport; + u8 rsvd1[6]; + u8 port_fwd_type[3]; + u8 rsvd2[7]; u8 pvid[16]; u8 rsvd3[32]; u8 rsvd4[32]; @@ -1563,7 +1568,9 @@ struct amap_get_hsw_req_context { } __packed; struct amap_get_hsw_resp_context { - u8 rsvd1[16]; + u8 rsvd0[6]; + u8 port_fwd_type[3]; + u8 rsvd1[7]; u8 pvid[16]; u8 rsvd2[32]; u8 rsvd3[32]; @@ -1965,9 +1972,9 @@ extern int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, extern int be_cmd_set_mac(struct be_adapter *adapter, u8 *mac, int if_id, u32 dom); extern int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid, - u32 domain, u16 intf_id); + u32 domain, u16 intf_id, u16 hsw_mode); extern int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, - u32 domain, u16 intf_id); + u32 domain, u16 intf_id, u8 *mode); extern int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter); extern int be_cmd_get_ext_fat_capabilites(struct be_adapter *adapter, struct be_dma_mem *cmd); diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 39e0a7697a81..e104db7fcf27 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -21,6 +21,7 @@ #include "be_cmds.h" #include <asm/div64.h> #include <linux/aer.h> +#include <linux/if_bridge.h> MODULE_VERSION(DRV_VER); MODULE_DEVICE_TABLE(pci, be_dev_ids); @@ -1212,14 +1213,14 @@ static int be_set_vf_vlan(struct net_device *netdev, adapter->vf_cfg[vf].vlan_tag = vlan; status = be_cmd_set_hsw_config(adapter, vlan, - vf + 1, adapter->vf_cfg[vf].if_handle); + vf + 1, adapter->vf_cfg[vf].if_handle, 0); } } else { /* Reset Transparent Vlan Tagging. */ adapter->vf_cfg[vf].vlan_tag = 0; vlan = adapter->vf_cfg[vf].def_vid; status = be_cmd_set_hsw_config(adapter, vlan, vf + 1, - adapter->vf_cfg[vf].if_handle); + adapter->vf_cfg[vf].if_handle, 0); } @@ -2917,7 +2918,7 @@ static int be_vf_setup(struct be_adapter *adapter) vf_cfg->tx_rate = lnk_speed; status = be_cmd_get_hsw_config(adapter, &def_vlan, - vf + 1, vf_cfg->if_handle); + vf + 1, vf_cfg->if_handle, NULL); if (status) goto err; vf_cfg->def_vid = def_vlan; @@ -3795,6 +3796,74 @@ fw_exit: return status; } +static int be_ndo_bridge_setlink(struct net_device *dev, + struct nlmsghdr *nlh) +{ + struct be_adapter *adapter = netdev_priv(dev); + struct nlattr *attr, *br_spec; + int rem; + int status = 0; + u16 mode = 0; + + if (!sriov_enabled(adapter)) + return -EOPNOTSUPP; + + br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); + + nla_for_each_nested(attr, br_spec, rem) { + if (nla_type(attr) != IFLA_BRIDGE_MODE) + continue; + + mode = nla_get_u16(attr); + if (mode != BRIDGE_MODE_VEPA && mode != BRIDGE_MODE_VEB) + return -EINVAL; + + status = be_cmd_set_hsw_config(adapter, 0, 0, + adapter->if_handle, + mode == BRIDGE_MODE_VEPA ? + PORT_FWD_TYPE_VEPA : + PORT_FWD_TYPE_VEB); + if (status) + goto err; + + dev_info(&adapter->pdev->dev, "enabled switch mode: %s\n", + mode == BRIDGE_MODE_VEPA ? "VEPA" : "VEB"); + + return status; + } +err: + dev_err(&adapter->pdev->dev, "Failed to set switch mode %s\n", + mode == BRIDGE_MODE_VEPA ? "VEPA" : "VEB"); + + return status; +} + +static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, + struct net_device *dev, + u32 filter_mask) +{ + struct be_adapter *adapter = netdev_priv(dev); + int status = 0; + u8 hsw_mode; + + if (!sriov_enabled(adapter)) + return 0; + + /* BE and Lancer chips support VEB mode only */ + if (BEx_chip(adapter) || lancer_chip(adapter)) { + hsw_mode = PORT_FWD_TYPE_VEB; + } else { + status = be_cmd_get_hsw_config(adapter, NULL, 0, + adapter->if_handle, &hsw_mode); + if (status) + return 0; + } + + return ndo_dflt_bridge_getlink(skb, pid, seq, dev, + hsw_mode == PORT_FWD_TYPE_VEPA ? + BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB); +} + static const struct net_device_ops be_netdev_ops = { .ndo_open = be_open, .ndo_stop = be_close, @@ -3813,6 +3882,8 @@ static const struct net_device_ops be_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = be_netpoll, #endif + .ndo_bridge_setlink = be_ndo_bridge_setlink, + .ndo_bridge_getlink = be_ndo_bridge_getlink, }; static void be_netdev_init(struct net_device *netdev) |