cxgb4/cxgb4vf: add support for ndo_set_vf_vlan
authorGanesh Goudar <ganeshgr@chelsio.com>
Wed, 24 Jan 2018 15:14:07 +0000 (20:44 +0530)
committerDavid S. Miller <davem@davemloft.net>
Wed, 24 Jan 2018 15:48:25 +0000 (10:48 -0500)
implement ndo_set_vf_vlan for mgmt netdevice to configure
the PCIe VF.

Original work by: Casey Leedom <leedom@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c

index 3e0218735b2b4c0cec3a7f34276b39ff48f9e360..4294673642199d3d40753508ca8a8426e1b41bbb 100644 (file)
@@ -820,6 +820,7 @@ struct vf_info {
        unsigned char vf_mac_addr[ETH_ALEN];
        unsigned int tx_rate;
        bool pf_set_mac;
+       u16 vlan;
 };
 
 struct mbox_list {
@@ -1738,4 +1739,6 @@ void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, struct sge_fl *fl);
 void free_tx_desc(struct adapter *adap, struct sge_txq *q,
                  unsigned int n, bool unmap);
 void free_txq(struct adapter *adap, struct sge_txq *q);
+int t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf,
+                   u16 vlan);
 #endif /* __CXGB4_H__ */
index 4716387830eff0b09899f0afa7f860d1e2ddca88..f0fd2eba30c22527d6a8d1bbc2036efc45e54d69 100644 (file)
@@ -2783,7 +2783,30 @@ static int cxgb4_mgmt_set_vf_rate(struct net_device *dev, int vf,
        return 0;
 }
 
-#endif
+static int cxgb4_mgmt_set_vf_vlan(struct net_device *dev, int vf,
+                                 u16 vlan, u8 qos, __be16 vlan_proto)
+{
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adap = pi->adapter;
+       int ret;
+
+       if (vf >= adap->num_vfs || vlan > 4095 || qos > 7)
+               return -EINVAL;
+
+       if (vlan_proto != htons(ETH_P_8021Q) || qos != 0)
+               return -EPROTONOSUPPORT;
+
+       ret = t4_set_vlan_acl(adap, adap->mbox, vf + 1, vlan);
+       if (!ret) {
+               adap->vfinfo[vf].vlan = vlan;
+               return 0;
+       }
+
+       dev_err(adap->pdev_dev, "Err %d %s VLAN ACL for PF/VF %d/%d\n",
+               ret, (vlan ? "setting" : "clearing"), adap->pf, vf);
+       return ret;
+}
+#endif /* CONFIG_PCI_IOV */
 
 static int cxgb_set_mac_addr(struct net_device *dev, void *p)
 {
@@ -3207,6 +3230,7 @@ static const struct net_device_ops cxgb4_mgmt_netdev_ops = {
        .ndo_get_vf_config    = cxgb4_mgmt_get_vf_config,
        .ndo_set_vf_rate      = cxgb4_mgmt_set_vf_rate,
        .ndo_get_phys_port_id = cxgb4_mgmt_get_phys_port_id,
+       .ndo_set_vf_vlan      = cxgb4_mgmt_set_vf_vlan,
 };
 #endif
 
index 6d76851a4da93c74978d1d036eea5770c9763d11..34055476288c9449b2e30e08c9cbefc540f2d00b 100644 (file)
@@ -9899,3 +9899,35 @@ int t4_i2c_rd(struct adapter *adap, unsigned int mbox, int port,
 
        return ret;
 }
+
+/**
+ *      t4_set_vlan_acl - Set a VLAN id for the specified VF
+ *      @adapter: the adapter
+ *      @mbox: mailbox to use for the FW command
+ *      @vf: one of the VFs instantiated by the specified PF
+ *      @vlan: The vlanid to be set
+ */
+int t4_set_vlan_acl(struct adapter *adap, unsigned int mbox, unsigned int vf,
+                   u16 vlan)
+{
+       struct fw_acl_vlan_cmd vlan_cmd;
+       unsigned int enable;
+
+       enable = (vlan ? FW_ACL_VLAN_CMD_EN_F : 0);
+       memset(&vlan_cmd, 0, sizeof(vlan_cmd));
+       vlan_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_ACL_VLAN_CMD) |
+                                        FW_CMD_REQUEST_F |
+                                        FW_CMD_WRITE_F |
+                                        FW_CMD_EXEC_F |
+                                        FW_ACL_VLAN_CMD_PFN_V(adap->pf) |
+                                        FW_ACL_VLAN_CMD_VFN_V(vf));
+       vlan_cmd.en_to_len16 = cpu_to_be32(enable | FW_LEN16(vlan_cmd));
+       /* Drop all packets that donot match vlan id */
+       vlan_cmd.dropnovlan_fm = FW_ACL_VLAN_CMD_FM_F;
+       if (enable != 0) {
+               vlan_cmd.nvlan = 1;
+               vlan_cmd.vlanid[0] = cpu_to_be16(vlan);
+       }
+
+       return t4_wr_mbox(adap, adap->mbox, &vlan_cmd, sizeof(vlan_cmd), NULL);
+}
index f3310d5b3c4c77908c653c5d483c08756f062d7e..f88766d2401de3a5c380f472adfb640805eec333 100644 (file)
@@ -2353,14 +2353,22 @@ struct fw_acl_vlan_cmd {
 #define FW_ACL_VLAN_CMD_VFN_S          0
 #define FW_ACL_VLAN_CMD_VFN_V(x)       ((x) << FW_ACL_VLAN_CMD_VFN_S)
 
-#define FW_ACL_VLAN_CMD_EN_S   31
-#define FW_ACL_VLAN_CMD_EN_V(x)        ((x) << FW_ACL_VLAN_CMD_EN_S)
+#define FW_ACL_VLAN_CMD_EN_S           31
+#define FW_ACL_VLAN_CMD_EN_M           0x1
+#define FW_ACL_VLAN_CMD_EN_V(x)                ((x) << FW_ACL_VLAN_CMD_EN_S)
+#define FW_ACL_VLAN_CMD_EN_G(x)         \
+       (((x) >> S_FW_ACL_VLAN_CMD_EN_S) & FW_ACL_VLAN_CMD_EN_M)
+#define FW_ACL_VLAN_CMD_EN_F            FW_ACL_VLAN_CMD_EN_V(1U)
 
 #define FW_ACL_VLAN_CMD_DROPNOVLAN_S   7
 #define FW_ACL_VLAN_CMD_DROPNOVLAN_V(x)        ((x) << FW_ACL_VLAN_CMD_DROPNOVLAN_S)
 
-#define FW_ACL_VLAN_CMD_FM_S   6
-#define FW_ACL_VLAN_CMD_FM_V(x)        ((x) << FW_ACL_VLAN_CMD_FM_S)
+#define FW_ACL_VLAN_CMD_FM_S           6
+#define FW_ACL_VLAN_CMD_FM_M           0x1
+#define FW_ACL_VLAN_CMD_FM_V(x)         ((x) << FW_ACL_VLAN_CMD_FM_S)
+#define FW_ACL_VLAN_CMD_FM_G(x)         \
+       (((x) >> FW_ACL_VLAN_CMD_FM_S) & FW_ACL_VLAN_CMD_FM_M)
+#define FW_ACL_VLAN_CMD_FM_F            FW_ACL_VLAN_CMD_FM_V(1U)
 
 /* old 16-bit port capabilities bitmap (fw_port_cap16_t) */
 enum fw_port_cap {
index 08c6ddb84a049ecc75f414a968dba78974d5837f..5883f09e38043f24f3c967638798e5f7a5837ffe 100644 (file)
@@ -92,6 +92,7 @@ struct sge_rspq;
  */
 struct port_info {
        struct adapter *adapter;        /* our adapter */
+       u32 vlan_id;                    /* vlan id for VST */
        u16 viid;                       /* virtual interface ID */
        s16 xact_addr_filt;             /* index of our MAC address filter */
        u16 rss_size;                   /* size of VI's RSS table slice */
index 96f69f80dc99a2bc4597cd5bd98ecf369306c711..b7e79e64d2ed17f96957645f98b1201aefde1103 100644 (file)
@@ -791,6 +791,8 @@ static int cxgb4vf_open(struct net_device *dev)
        if (err)
                goto err_unwind;
 
+       pi->vlan_id = t4vf_get_vf_vlan_acl(adapter);
+
        netif_tx_start_all_queues(dev);
        set_bit(pi->port_id, &adapter->open_device_map);
        return 0;
index 129b914a434cb45a018771a91f2bab23b5cdd2b7..dfce5df7538ef5d123d66c6aa22fd16d83c3c87c 100644 (file)
@@ -1202,6 +1202,10 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
        BUG_ON(qidx >= pi->nqsets);
        txq = &adapter->sge.ethtxq[pi->first_qset + qidx];
 
+       if (pi->vlan_id && !skb_vlan_tag_present(skb))
+               __vlan_hwaccel_put_tag(skb, cpu_to_be16(ETH_P_8021Q),
+                                      pi->vlan_id);
+
        /*
         * Take this opportunity to reclaim any TX Descriptors whose DMA
         * transfers have completed.
@@ -1570,6 +1574,7 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
 {
        struct adapter *adapter = rxq->rspq.adapter;
        struct sge *s = &adapter->sge;
+       struct port_info *pi;
        int ret;
        struct sk_buff *skb;
 
@@ -1586,8 +1591,9 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
        skb->truesize += skb->data_len;
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        skb_record_rx_queue(skb, rxq->rspq.idx);
+       pi = netdev_priv(skb->dev);
 
-       if (pkt->vlan_ex) {
+       if (pkt->vlan_ex && !pi->vlan_id) {
                __vlan_hwaccel_put_tag(skb, cpu_to_be16(ETH_P_8021Q),
                                        be16_to_cpu(pkt->vlan));
                rxq->stats.vlan_ex++;
@@ -1620,6 +1626,7 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
        struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq);
        struct adapter *adapter = rspq->adapter;
        struct sge *s = &adapter->sge;
+       struct port_info *pi;
 
        /*
         * If this is a good TCP packet and we have Generic Receive Offload
@@ -1644,6 +1651,7 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
        __skb_pull(skb, s->pktshift);
        skb->protocol = eth_type_trans(skb, rspq->netdev);
        skb_record_rx_queue(skb, rspq->idx);
+       pi = netdev_priv(skb->dev);
        rxq->stats.pkts++;
 
        if (csum_ok && !pkt->err_vec &&
@@ -1660,9 +1668,10 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
        } else
                skb_checksum_none_assert(skb);
 
-       if (pkt->vlan_ex) {
+       if (pkt->vlan_ex && !pi->vlan_id) {
                rxq->stats.vlan_ex++;
-               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(pkt->vlan));
+               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+                                      be16_to_cpu(pkt->vlan));
        }
 
        netif_receive_skb(skb);
index 9cf9c56b0f7301923bb3fb761535635d07db7ddf..712e8f0c71b49a890320555006af9317c3d63d81 100644 (file)
@@ -413,5 +413,6 @@ int t4vf_handle_fw_rpl(struct adapter *, const __be64 *);
 int t4vf_prep_adapter(struct adapter *);
 int t4vf_get_vf_mac_acl(struct adapter *adapter, unsigned int pf,
                        unsigned int *naddr, u8 *addr);
+int t4vf_get_vf_vlan_acl(struct adapter *adapter);
 
 #endif /* __T4VF_COMMON_H__ */
index 67aec59a14e6d5c866f5915c40a8de693699fd1d..798695bf86784426a062343c93099381c48d9b85 100644 (file)
@@ -2147,3 +2147,31 @@ int t4vf_get_vf_mac_acl(struct adapter *adapter, unsigned int pf,
 
        return ret;
 }
+
+/**
+ *     t4vf_get_vf_vlan_acl - Get the VLAN ID to be set to
+ *                             the VI of this VF.
+ *     @adapter: The adapter
+ *
+ *     Find the VLAN ID to be set to the VF's VI. The requested VLAN ID
+ *     is from the host OS via callback in the PF driver.
+ */
+int t4vf_get_vf_vlan_acl(struct adapter *adapter)
+{
+       struct fw_acl_vlan_cmd cmd;
+       int vlan = 0;
+       int ret = 0;
+
+       cmd.op_to_vfn = htonl(FW_CMD_OP_V(FW_ACL_VLAN_CMD) |
+                             FW_CMD_REQUEST_F | FW_CMD_READ_F);
+
+       /* Note: Do not enable the ACL */
+       cmd.en_to_len16 = cpu_to_be32((unsigned int)FW_LEN16(cmd));
+
+       ret = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &cmd);
+
+       if (!ret)
+               vlan = be16_to_cpu(cmd.vlanid[0]);
+
+       return vlan;
+}