[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20170617194137.GC1974@lunn.ch>
Date: Sat, 17 Jun 2017 21:41:37 +0200
From: Andrew Lunn <andrew@...n.ch>
To: Salil Mehta <salil.mehta@...wei.com>
Cc: davem@...emloft.net, yisen.zhuang@...wei.com,
huangdaode@...ilicon.com, lipeng321@...wei.com,
mehta.salil.lnk@...il.com, netdev@...r.kernel.org,
linux-kernel@...r.kernel.org, linuxarm@...wei.com
Subject: Re: [PATCH V3 net-next 1/8] net: hns3: Add support of HNS3 Ethernet
Driver for hip08 SoC
> +
> + for (i = 0; i < priv->vector_num; i++) {
> + tqp_vectors = &priv->tqp_vector[i];
> +
> + if (tqp_vectors->irq_init_flag == HNS3_VEVTOR_INITED)
Should VEVTOR be VECTOR?
> +static void hns3_set_vector_gl(struct hns3_enet_tqp_vector *tqp_vector,
> + u32 gl_value)
> +{
> + writel(gl_value, tqp_vector->mask_addr + HNS3_VECTOR_GL0_OFFSET);
> + writel(gl_value, tqp_vector->mask_addr + HNS3_VECTOR_GL1_OFFSET);
> + writel(gl_value, tqp_vector->mask_addr + HNS3_VECTOR_GL2_OFFSET);
> +}
> +
> +static void hns3_set_vector_rl(struct hns3_enet_tqp_vector *tqp_vector,
> + u32 rl_value)
Could you use more informative names. What does gl and rl mean?
> +{
> + writel(rl_value, tqp_vector->mask_addr + HNS3_VECTOR_RL_OFFSET);
> +}
> +
> +static void hns3_vector_gl_rl_init(struct hns3_enet_tqp_vector *tqp_vector)
> +{
> + /* Default :enable interrupt coalesce */
> + tqp_vector->rx_group.int_gl = HNS3_INT_GL_50K;
> + tqp_vector->tx_group.int_gl = HNS3_INT_GL_50K;
> + hns3_set_vector_gl(tqp_vector, HNS3_INT_GL_50K);
> + hns3_set_vector_rl(tqp_vector, 0);
> + tqp_vector->rx_group.flow_level = HNS3_FLOW_LOW;
> + tqp_vector->tx_group.flow_level = HNS3_FLOW_LOW;
> +}
> +
> +static int hns3_nic_net_up(struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + int i, j;
> + int ret;
> +
> + ret = hns3_nic_init_irq(priv);
> + if (ret != 0) {
> + netdev_err(ndev, "hns init irq failed! ret=%d\n", ret);
> + return ret;
> + }
> +
> + for (i = 0; i < priv->vector_num; i++)
> + hns3_vector_enable(&priv->tqp_vector[i]);
> +
> + ret = h->ae_algo->ops->start ? h->ae_algo->ops->start(h) : 0;
> + if (ret)
> + goto out_start_err;
> +
> + return 0;
> +
> +out_start_err:
> + netif_stop_queue(ndev);
This seems asymmetric. Where is the netif_start_queue()?
> +
> + for (j = i - 1; j >= 0; j--)
> + hns3_vector_disable(&priv->tqp_vector[j]);
> +
> + return ret;
> +}
> +
> +static int hns3_nic_net_open(struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + int ret;
> +
> + netif_carrier_off(ndev);
> +
> + ret = netif_set_real_num_tx_queues(ndev, h->kinfo.num_tqps);
> + if (ret < 0) {
> + netdev_err(ndev, "netif_set_real_num_tx_queues fail, ret=%d!\n",
> + ret);
> + return ret;
> + }
> +
> + ret = netif_set_real_num_rx_queues(ndev, h->kinfo.num_tqps);
> + if (ret < 0) {
> + netdev_err(ndev,
> + "netif_set_real_num_rx_queues fail, ret=%d!\n", ret);
> + return ret;
> + }
> +
> + ret = hns3_nic_net_up(ndev);
> + if (ret) {
> + netdev_err(ndev,
> + "hns net up fail, ret=%d!\n", ret);
> + return ret;
> + }
> +
> + netif_carrier_on(ndev);
Carrier on should be performed when the PHY says there is link.
> + netif_tx_wake_all_queues(ndev);
> +
> + return 0;
> +}
> +
> +static void hns3_nic_net_down(struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_ae_ops *ops;
> + int i;
> +
> + netif_tx_stop_all_queues(ndev);
> + netif_carrier_off(ndev);
> +
> + ops = priv->ae_handle->ae_algo->ops;
> +
> + if (ops->stop)
> + ops->stop(priv->ae_handle);
> +
> + for (i = 0; i < priv->vector_num; i++)
> + hns3_vector_disable(&priv->tqp_vector[i]);
> +}
> +
> +static int hns3_nic_net_stop(struct net_device *ndev)
> +{
> + hns3_nic_net_down(ndev);
> +
> + return 0;
> +}
> +
> +void hns3_set_multicast_list(struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + struct netdev_hw_addr *ha = NULL;
> +
> + if (!h) {
> + netdev_err(ndev, "hnae handle is null\n");
> + return;
> + }
> +
> + if (h->ae_algo->ops->set_mc_addr) {
> + netdev_for_each_mc_addr(ha, ndev)
> + if (h->ae_algo->ops->set_mc_addr(h, ha->addr))
> + netdev_err(ndev, "set multicast fail\n");
> + }
> +}
> +
> +static int hns3_nic_uc_sync(struct net_device *netdev,
> + const unsigned char *addr)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(netdev);
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (h->ae_algo->ops->add_uc_addr)
> + return h->ae_algo->ops->add_uc_addr(h, addr);
> +
> + return 0;
> +}
> +
> +static int hns3_nic_uc_unsync(struct net_device *netdev,
> + const unsigned char *addr)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(netdev);
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (h->ae_algo->ops->rm_uc_addr)
> + return h->ae_algo->ops->rm_uc_addr(h, addr);
> +
> + return 0;
> +}
> +
> +static int hns3_nic_mc_sync(struct net_device *netdev,
> + const unsigned char *addr)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(netdev);
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (h->ae_algo->ops->add_uc_addr)
> + return h->ae_algo->ops->add_mc_addr(h, addr);
> +
> + return 0;
> +}
> +
> +static int hns3_nic_mc_unsync(struct net_device *netdev,
> + const unsigned char *addr)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(netdev);
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (h->ae_algo->ops->rm_uc_addr)
> + return h->ae_algo->ops->rm_mc_addr(h, addr);
> +
> + return 0;
> +}
> +
> +void hns3_nic_set_rx_mode(struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (h->ae_algo->ops->set_promisc_mode) {
> + if (ndev->flags & IFF_PROMISC)
> + h->ae_algo->ops->set_promisc_mode(h, 1);
> + else
> + h->ae_algo->ops->set_promisc_mode(h, 0);
> + }
> + if (__dev_uc_sync(ndev, hns3_nic_uc_sync, hns3_nic_uc_unsync))
> + netdev_err(ndev, "sync uc address fail\n");
> + if (ndev->flags & IFF_MULTICAST)
> + if (__dev_mc_sync(ndev, hns3_nic_mc_sync, hns3_nic_mc_unsync))
> + netdev_err(ndev, "sync mc address fail\n");
> +}
> +
> +static int hns3_set_tso(struct sk_buff *skb, u32 *paylen,
> + u16 *mss, u32 *type_cs_vlan_tso)
> +{
> + union {
> + struct iphdr *v4;
> + struct ipv6hdr *v6;
> + unsigned char *hdr;
> + } l3;
You have this repeated a few times. Might be better to pull it out
into a header file.
> + union {
> + struct tcphdr *tcp;
> + struct udphdr *udp;
> + unsigned char *hdr;
> + } l4;
You can probably pull this out as well, or maybe the version with the
gre header.
> +static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv,
> + int size, dma_addr_t dma, int frag_end,
> + enum hns_desc_type type)
> +{
> + struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use];
> + struct hns3_desc *desc = &ring->desc[ring->next_to_use];
> + u32 ol_type_vlan_len_msec = 0;
> + u16 bdtp_fe_sc_vld_ra_ri = 0;
> + u32 type_cs_vlan_tso = 0;
> + struct sk_buff *skb;
> + u32 paylen = 0;
> + u16 mss = 0;
> + __be16 protocol;
> + u8 ol4_proto;
> + u8 il4_proto;
> + int ret;
> +
> + /* The txbd's baseinfo of DESC_TYPE_PAGE & DESC_TYPE_SKB */
> + desc_cb->priv = priv;
> + desc_cb->length = size;
> + desc_cb->dma = dma;
> + desc_cb->type = type;
> +
> + /* now, fill the descriptor */
> + desc->addr = cpu_to_le64(dma);
> + desc->tx.send_size = cpu_to_le16((u16)size);
> + hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri, frag_end);
> + desc->tx.bdtp_fe_sc_vld_ra_ri = cpu_to_le16(bdtp_fe_sc_vld_ra_ri);
> +
> + if (type == DESC_TYPE_SKB) {
> + skb = (struct sk_buff *)priv;
> + paylen = cpu_to_le16(skb->len);
> +
> + if (skb->ip_summed == CHECKSUM_PARTIAL) {
> + skb_reset_mac_len(skb);
> + protocol = skb->protocol;
> +
> + /* vlan packe t*/
> + if (protocol == htons(ETH_P_8021Q)) {
> + protocol = vlan_get_protocol(skb);
> + skb->protocol = protocol;
> + }
> + hns3_get_l4_protocol(skb, &ol4_proto, &il4_proto);
> + hns3_set_l2l3l4_len(skb, ol4_proto, il4_proto,
> + &type_cs_vlan_tso,
> + &ol_type_vlan_len_msec);
> + ret = hns3_set_l3l4_type_csum(skb, ol4_proto, il4_proto,
> + &type_cs_vlan_tso,
> + &ol_type_vlan_len_msec);
> + if (ret)
> + return ret;
> +
> + ret = hns3_set_tso(skb, &paylen, &mss,
> + &type_cs_vlan_tso);
> + if (ret)
> + return ret;
> + }
> +
> + /* Set txbd */
> + desc->tx.ol_type_vlan_len_msec =
> + cpu_to_le32(ol_type_vlan_len_msec);
> + desc->tx.type_cs_vlan_tso_len =
> + cpu_to_le32(type_cs_vlan_tso);
> + desc->tx.paylen = cpu_to_le16(paylen);
> + desc->tx.mss = cpu_to_le16(mss);
> + }
> +
> + /* move ring pointer to next.*/
> + ring_ptr_move_fw(ring, next_to_use);
> +
> + return 0;
> +}
> +
> +static int hns3_fill_desc_tso(struct hns3_enet_ring *ring, void *priv,
> + int size, dma_addr_t dma, int frag_end,
> + enum hns_desc_type type)
> +{
> + int frag_buf_num;
> + int sizeoflast;
> + int ret, k;
> +
> + frag_buf_num = (size + HNS3_MAX_BD_SIZE - 1) / HNS3_MAX_BD_SIZE;
> + sizeoflast = size % HNS3_MAX_BD_SIZE;
> + sizeoflast = sizeoflast ? sizeoflast : HNS3_MAX_BD_SIZE;
> +
> + /* When the frag size is bigger than hardware, split this frag */
> + for (k = 0; k < frag_buf_num; k++) {
> + ret = hns3_fill_desc(ring, priv,
> + (k == frag_buf_num - 1) ?
> + sizeoflast : HNS3_MAX_BD_SIZE,
> + dma + HNS3_MAX_BD_SIZE * k,
> + frag_end && (k == frag_buf_num - 1) ? 1 : 0,
> + (type == DESC_TYPE_SKB && !k) ?
> + DESC_TYPE_SKB : DESC_TYPE_PAGE);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int hns3_nic_maybe_stop_tso(struct sk_buff **out_skb, int *bnum,
> + struct hns3_enet_ring *ring)
> +{
> + struct sk_buff *skb = *out_skb;
> + struct skb_frag_struct *frag;
> + int bdnum_for_frag;
> + int frag_num;
> + int buf_num;
> + int size;
> + int i;
> +
> + size = skb_headlen(skb);
> + buf_num = (size + HNS3_MAX_BD_SIZE - 1) / HNS3_MAX_BD_SIZE;
> +
> + frag_num = skb_shinfo(skb)->nr_frags;
> + for (i = 0; i < frag_num; i++) {
> + frag = &skb_shinfo(skb)->frags[i];
> + size = skb_frag_size(frag);
> + bdnum_for_frag =
> + (size + HNS3_MAX_BD_SIZE - 1) / HNS3_MAX_BD_SIZE;
> + if (bdnum_for_frag > HNS3_MAX_BD_PER_FRAG)
> + return -ENOMEM;
> +
> + buf_num += bdnum_for_frag;
> + }
> +
> + if (buf_num > ring_space(ring))
> + return -EBUSY;
> +
> + *bnum = buf_num;
> + return 0;
> +}
> +
> +static int hns3_nic_maybe_stop_tx(struct sk_buff **out_skb, int *bnum,
> + struct hns3_enet_ring *ring)
> +{
> + struct sk_buff *skb = *out_skb;
> + int buf_num;
> +
> + /* No. of segments (plus a header) */
> + buf_num = skb_shinfo(skb)->nr_frags + 1;
> +
> + if (buf_num > ring_space(ring))
> + return -EBUSY;
> +
> + *bnum = buf_num;
> +
> + return 0;
> +}
> +
> +static void hns_nic_dma_unmap(struct hns3_enet_ring *ring, int next_to_use_orig)
> +{
> + struct device *dev = ring_to_dev(ring);
> +
> + while (1) {
> + /* check if this is where we started */
> + if (ring->next_to_use == next_to_use_orig)
> + break;
> +
> + /* unmap the descriptor dma address */
> + if (ring->desc_cb[ring->next_to_use].type == DESC_TYPE_SKB)
> + dma_unmap_single(dev,
> + ring->desc_cb[ring->next_to_use].dma,
> + ring->desc_cb[ring->next_to_use].length,
> + DMA_TO_DEVICE);
> + else
> + dma_unmap_page(dev,
> + ring->desc_cb[ring->next_to_use].dma,
> + ring->desc_cb[ring->next_to_use].length,
> + DMA_TO_DEVICE);
> +
> + /* rollback one */
> + ring_ptr_move_bw(ring, next_to_use);
> + }
> +}
> +
> +int hns3_nic_net_xmit_hw(struct net_device *ndev,
> + struct sk_buff *skb,
> + struct hns3_nic_ring_data *ring_data)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hns3_enet_ring *ring = ring_data->ring;
> + struct device *dev = priv->dev;
> + struct netdev_queue *dev_queue;
> + struct skb_frag_struct *frag;
> + int next_to_use_head;
> + int next_to_use_frag;
> + dma_addr_t dma;
> + int buf_num;
> + int seg_num;
> + int size;
> + int ret;
> + int i;
> +
> + if (!skb || !ring)
> + return -ENOMEM;
> +
> + /* Prefetch the data used later */
> + prefetch(skb->data);
> +
> + switch (priv->ops.maybe_stop_tx(&skb, &buf_num, ring)) {
> + case -EBUSY:
> + ring->stats.tx_busy++;
> + goto out_net_tx_busy;
> + case -ENOMEM:
> + ring->stats.sw_err_cnt++;
> + netdev_err(ndev, "no memory to xmit!\n");
> + goto out_err_tx_ok;
> + default:
> + break;
> + }
> +
> + /* No. of segments (plus a header) */
> + seg_num = skb_shinfo(skb)->nr_frags + 1;
> + /* Fill the first part */
> + size = skb_headlen(skb);
> +
> + next_to_use_head = ring->next_to_use;
> +
> + dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
> + if (dma_mapping_error(dev, dma)) {
> + netdev_err(ndev, "TX head DMA map failed\n");
> + ring->stats.sw_err_cnt++;
> + goto out_err_tx_ok;
> + }
> +
> + ret = priv->ops.fill_desc(ring, skb, size, dma, seg_num == 1 ? 1 : 0,
> + DESC_TYPE_SKB);
> + if (ret)
> + goto head_dma_map_err;
> +
> + next_to_use_frag = ring->next_to_use;
> + /* Fill the fragments */
> + for (i = 1; i < seg_num; i++) {
> + frag = &skb_shinfo(skb)->frags[i - 1];
> + size = skb_frag_size(frag);
> + dma = skb_frag_dma_map(dev, frag, 0, size, DMA_TO_DEVICE);
> + if (dma_mapping_error(dev, dma)) {
> + netdev_err(ndev, "TX frag(%d) DMA map failed\n", i);
> + ring->stats.sw_err_cnt++;
> + goto frag_dma_map_err;
> + }
> + ret = priv->ops.fill_desc(ring, skb_frag_page(frag), size, dma,
> + seg_num - 1 == i ? 1 : 0,
> + DESC_TYPE_PAGE);
> +
> + if (ret)
> + goto frag_dma_map_err;
> + }
> +
> + /* Complete translate all packets */
> + dev_queue = netdev_get_tx_queue(ndev, ring_data->queue_index);
> + netdev_tx_sent_queue(dev_queue, skb->len);
> +
> + wmb(); /* Commit all data before submit */
> +
> + hnae_queue_xmit(ring->tqp, buf_num);
> +
> + ring->stats.tx_pkts++;
> + ring->stats.tx_bytes += skb->len;
> +
> + return NETDEV_TX_OK;
> +
> +frag_dma_map_err:
> + hns_nic_dma_unmap(ring, next_to_use_frag);
> +
> +head_dma_map_err:
> + hns_nic_dma_unmap(ring, next_to_use_head);
> +
> +out_err_tx_ok:
> + dev_kfree_skb_any(skb);
> + return NETDEV_TX_OK;
> +
> +out_net_tx_busy:
> + netif_stop_subqueue(ndev, ring_data->queue_index);
> + smp_mb(); /* Commit all data before submit */
> +
> + return NETDEV_TX_BUSY;
> +}
> +
> +static netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb,
> + struct net_device *ndev)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + int ret;
> +
> + ret = hns3_nic_net_xmit_hw(ndev, skb,
> + &tx_ring_data(priv, skb->queue_mapping));
> + if (ret == NETDEV_TX_OK) {
> + netif_trans_update(ndev);
> + ndev->stats.tx_bytes += skb->len;
> + ndev->stats.tx_packets++;
> + }
> +
> + return (netdev_tx_t)ret;
> +}
> +
> +static int hns3_nic_net_set_mac_address(struct net_device *ndev, void *p)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + struct sockaddr *mac_addr = p;
> + int ret;
> +
> + if (!mac_addr || !is_valid_ether_addr((const u8 *)mac_addr->sa_data))
> + return -EADDRNOTAVAIL;
> +
> + ret = h->ae_algo->ops->set_mac_addr(h, mac_addr->sa_data);
> + if (ret) {
> + netdev_err(ndev, "set_mac_address fail, ret=%d!\n", ret);
> + return ret;
> + }
> +
> + ether_addr_copy(ndev->dev_addr, mac_addr->sa_data);
> +
> + return 0;
> +}
> +
> +static int hns3_nic_set_features(struct net_device *netdev,
> + netdev_features_t features)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(netdev);
> +
> + if (features & (NETIF_F_TSO | NETIF_F_TSO6)) {
> + priv->ops.fill_desc = hns3_fill_desc_tso;
> + priv->ops.maybe_stop_tx = hns3_nic_maybe_stop_tso;
> + } else {
> + priv->ops.fill_desc = hns3_fill_desc;
> + priv->ops.maybe_stop_tx = hns3_nic_maybe_stop_tx;
> + }
> +
> + netdev->features = features;
> + return 0;
> +}
> +
> +static void
> +hns3_nic_get_stats64(struct net_device *ndev, struct rtnl_link_stats64 *stats)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + int queue_num = priv->ae_handle->kinfo.num_tqps;
> + u64 tx_bytes = 0;
> + u64 rx_bytes = 0;
> + u64 tx_pkts = 0;
> + u64 rx_pkts = 0;
> + int idx = 0;
> +
> + for (idx = 0; idx < queue_num; idx++) {
> + tx_bytes += priv->ring_data[idx].ring->stats.tx_bytes;
> + tx_pkts += priv->ring_data[idx].ring->stats.tx_pkts;
> + rx_bytes +=
> + priv->ring_data[idx + queue_num].ring->stats.rx_bytes;
> + rx_pkts += priv->ring_data[idx + queue_num].ring->stats.rx_pkts;
> + }
> +
> + stats->tx_bytes = tx_bytes;
> + stats->tx_packets = tx_pkts;
> + stats->rx_bytes = rx_bytes;
> + stats->rx_packets = rx_pkts;
> +
> + stats->rx_errors = ndev->stats.rx_errors;
> + stats->multicast = ndev->stats.multicast;
> + stats->rx_length_errors = ndev->stats.rx_length_errors;
> + stats->rx_crc_errors = ndev->stats.rx_crc_errors;
> + stats->rx_missed_errors = ndev->stats.rx_missed_errors;
> +
> + stats->tx_errors = ndev->stats.tx_errors;
> + stats->rx_dropped = ndev->stats.rx_dropped;
> + stats->tx_dropped = ndev->stats.tx_dropped;
> + stats->collisions = ndev->stats.collisions;
> + stats->rx_over_errors = ndev->stats.rx_over_errors;
> + stats->rx_frame_errors = ndev->stats.rx_frame_errors;
> + stats->rx_fifo_errors = ndev->stats.rx_fifo_errors;
> + stats->tx_aborted_errors = ndev->stats.tx_aborted_errors;
> + stats->tx_carrier_errors = ndev->stats.tx_carrier_errors;
> + stats->tx_fifo_errors = ndev->stats.tx_fifo_errors;
> + stats->tx_heartbeat_errors = ndev->stats.tx_heartbeat_errors;
> + stats->tx_window_errors = ndev->stats.tx_window_errors;
> + stats->rx_compressed = ndev->stats.rx_compressed;
> + stats->tx_compressed = ndev->stats.tx_compressed;
> +}
> +
> +static void hns3_add_tunnel_port(struct net_device *ndev, u16 port,
> + enum hns3_udp_tnl_type type)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hns3_udp_tunnel *udp_tnl = &priv->udp_tnl[type];
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (udp_tnl->used && udp_tnl->dst_port == port) {
> + udp_tnl->used++;
> + return;
> + }
> +
> + if (udp_tnl->used) {
> + netdev_warn(ndev,
> + "UDP tunnel [%d], port [%d] offload\n", type, port);
> + return;
> + }
> +
> + udp_tnl->dst_port = port;
> + udp_tnl->used = 1;
> + /* TBD send command to hardware to add port */
> + if (h->ae_algo->ops->add_tunnel_udp)
> + h->ae_algo->ops->add_tunnel_udp(h, port);
> +}
> +
> +static void hns3_del_tunnel_port(struct net_device *ndev, u16 port,
> + enum hns3_udp_tnl_type type)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hns3_udp_tunnel *udp_tnl = &priv->udp_tnl[type];
> + struct hnae3_handle *h = priv->ae_handle;
> +
> + if (!udp_tnl->used || udp_tnl->dst_port != port) {
> + netdev_warn(ndev,
> + "Invalid UDP tunnel port %d\n", port);
> + return;
> + }
> +
> + udp_tnl->used--;
> + if (udp_tnl->used)
> + return;
> +
> + udp_tnl->dst_port = 0;
> + /* TBD send command to hardware to del port */
> + if (h->ae_algo->ops->del_tunnel_udp)
> + h->ae_algo->ops->add_tunnel_udp(h, port);
> +}
> +
> +/* hns3_nic_udp_tunnel_add - Get notifiacetion about UDP tunnel ports
> + * @netdev: This physical ports's netdev
> + * @ti: Tunnel information
> + */
> +static void hns3_nic_udp_tunnel_add(struct net_device *ndev,
> + struct udp_tunnel_info *ti)
> +{
> + u16 port_n = ntohs(ti->port);
> +
> + switch (ti->type) {
> + case UDP_TUNNEL_TYPE_VXLAN:
> + hns3_add_tunnel_port(ndev, port_n, HNS3_UDP_TNL_VXLAN);
> + break;
> + case UDP_TUNNEL_TYPE_GENEVE:
> + hns3_add_tunnel_port(ndev, port_n, HNS3_UDP_TNL_GENEVE);
> + break;
> + default:
> + netdev_err(ndev, "unsupported tunnel type %d\n", ti->type);
> + break;
> + }
> +}
> +
> +static void hns3_nic_udp_tunnel_del(struct net_device *ndev,
> + struct udp_tunnel_info *ti)
> +{
> + u16 port_n = ntohs(ti->port);
> +
> + switch (ti->type) {
> + case UDP_TUNNEL_TYPE_VXLAN:
> + hns3_del_tunnel_port(ndev, port_n, HNS3_UDP_TNL_VXLAN);
> + break;
> + case UDP_TUNNEL_TYPE_GENEVE:
> + hns3_del_tunnel_port(ndev, port_n, HNS3_UDP_TNL_GENEVE);
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static int hns3_setup_tc(struct net_device *ndev, u8 tc)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + struct hnae3_knic_private_info *kinfo = &h->kinfo;
> + int i, ret;
> +
> + if (tc > HNAE3_MAX_TC)
> + return -EINVAL;
> +
> + if (kinfo->num_tc == tc)
> + return 0;
> +
> + if (!ndev)
> + return -EINVAL;
> +
> + if (!tc) {
> + netdev_reset_tc(ndev);
> + return 0;
> + }
> +
> + /* Set num_tc for netdev */
> + ret = netdev_set_num_tc(ndev, tc);
> + if (ret)
> + return ret;
> +
> + /* Set per TC queues for the VSI */
> + for (i = 0; i < HNAE3_MAX_TC; i++) {
> + if (kinfo->tc_info[i].enable)
> + netdev_set_tc_queue(ndev,
> + kinfo->tc_info[i].tc,
> + kinfo->tc_info[i].tqp_count,
> + kinfo->tc_info[i].tqp_offset);
> + }
> +
> + return 0;
> +}
> +
> +static int hns3_nic_setup_tc(struct net_device *dev, u32 handle,
> + u32 chain_index, __be16 protocol,
> + struct tc_to_netdev *tc)
> +{
> + if (handle != TC_H_ROOT || tc->type != TC_SETUP_MQPRIO)
> + return -EINVAL;
> +
> + return hns3_setup_tc(dev, tc->mqprio->num_tc);
> +}
> +
> +static int hns3_vlan_rx_add_vid(struct net_device *ndev,
> + __be16 proto, u16 vid)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + int ret = -EIO;
> +
> + if (h->ae_algo->ops->set_vlan_filter)
> + ret = h->ae_algo->ops->set_vlan_filter(h, proto, vid, false);
> +
> + return ret;
> +}
> +
> +static int hns3_vlan_rx_kill_vid(struct net_device *ndev,
> + __be16 proto, u16 vid)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + int ret = -EIO;
> +
> + if (h->ae_algo->ops->set_vlan_filter)
> + ret = h->ae_algo->ops->set_vlan_filter(h, proto, vid, true);
> +
> + return ret;
> +}
> +
> +static int hns3_ndo_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan,
> + u8 qos, __be16 vlan_proto)
> +{
> + struct hns3_nic_priv *priv = netdev_priv(ndev);
> + struct hnae3_handle *h = priv->ae_handle;
> + int ret = -EIO;
> +
> + if (h->ae_algo->ops->set_vf_vlan_filter)
> + ret = h->ae_algo->ops->set_vf_vlan_filter(h, vf, vlan,
> + qos, vlan_proto);
> +
> + return ret;
> +}
> +
> +static const struct net_device_ops hns3_nic_netdev_ops = {
> + .ndo_open = hns3_nic_net_open,
> + .ndo_stop = hns3_nic_net_stop,
> + .ndo_start_xmit = hns3_nic_net_xmit,
> + .ndo_set_mac_address = hns3_nic_net_set_mac_address,
> + .ndo_set_features = hns3_nic_set_features,
> + .ndo_get_stats64 = hns3_nic_get_stats64,
> + .ndo_setup_tc = hns3_nic_setup_tc,
> + .ndo_set_rx_mode = hns3_nic_set_rx_mode,
> + .ndo_udp_tunnel_add = hns3_nic_udp_tunnel_add,
> + .ndo_udp_tunnel_del = hns3_nic_udp_tunnel_del,
> + .ndo_vlan_rx_add_vid = hns3_vlan_rx_add_vid,
> + .ndo_vlan_rx_kill_vid = hns3_vlan_rx_kill_vid,
> + .ndo_set_vf_vlan = hns3_ndo_set_vf_vlan,
> +};
> +
> +/* hns3_probe - Device initialization routine
> + * @pdev: PCI device information struct
> + * @ent: entry in hns3_pci_tbl
> + *
> + * hns3_probe initializes a PF identified by a pci_dev structure.
> + * The OS initialization, configuring of the PF private structure,
> + * and a hardware reset occur.
> + *
> + * Returns 0 on success, negative on failure
> + */
> +static int hns3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
> +{
> + struct hnae3_ae_dev *ae_dev;
> + int ret;
> +
> + ae_dev = kzalloc(sizeof(*ae_dev), GFP_KERNEL);
> + if (!ae_dev) {
> + ret = -ENOMEM;
> + return ret;
> + }
> +
> + ae_dev->pdev = pdev;
> + ae_dev->dev_type = HNAE3_DEV_KNIC;
> + pci_set_drvdata(pdev, ae_dev);
> +
> + return hnae3_register_ae_dev(ae_dev);
> +}
> +
> +/* hns3_remove - Device removal routine
> + * @pdev: PCI device information struct
> + */
> +static void hns3_remove(struct pci_dev *pdev)
> +{
> + struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
> +
> + hnae3_unregister_ae_dev(ae_dev);
> +
> + pci_set_drvdata(pdev, NULL);
> +}
> +
> +static struct pci_driver hns3_driver = {
> + .name = hns3_driver_name,
> + .id_table = hns3_pci_tbl,
> + .probe = hns3_probe,
> + .remove = hns3_remove,
> +};
> +
> +/* set default feature to hns3 */
> +static void hns3_set_default_feature(struct net_device *ndev)
> +{
> + ndev->priv_flags |= IFF_UNICAST_FLT;
> +
> + ndev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
> + NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
> + NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
> + NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
> + NETIF_F_GSO_UDP_TUNNEL_CSUM;
> +
> + ndev->hw_enc_features |= NETIF_F_TSO_MANGLEID;
> +
> + ndev->gso_partial_features |= NETIF_F_GSO_GRE_CSUM;
> +
> + ndev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
> + NETIF_F_HW_VLAN_CTAG_FILTER |
> + NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
> + NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
> + NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
> + NETIF_F_GSO_UDP_TUNNEL_CSUM;
> +
> + ndev->vlan_features |=
> + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
> + NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO |
> + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
> + NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
> + NETIF_F_GSO_UDP_TUNNEL_CSUM;
> +
> + ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
> + NETIF_F_HW_VLAN_CTAG_FILTER |
> + NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
> + NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE |
> + NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
> + NETIF_F_GSO_UDP_TUNNEL_CSUM;
> +}
> +
> +static int hns3_alloc_buffer(struct hns3_enet_ring *ring,
> + struct hns3_desc_cb *cb)
> +{
> + unsigned int order = hnae_page_order(ring);
> + struct page *p;
> +
> + p = dev_alloc_pages(order);
> + if (!p)
> + return -ENOMEM;
> +
> + cb->priv = p;
> + cb->page_offset = 0;
> + cb->reuse_flag = 0;
> + cb->buf = page_address(p);
> + cb->length = hnae_page_size(ring);
> + cb->type = DESC_TYPE_PAGE;
> +
> + memset(cb->buf, 0, cb->length);
> +
> + return 0;
> +}
> +
> +static void hns3_free_buffer(struct hns3_enet_ring *ring,
> + struct hns3_desc_cb *cb)
> +{
> + if (cb->type == DESC_TYPE_SKB)
> + dev_kfree_skb_any((struct sk_buff *)cb->priv);
> + else if (!HNAE3_IS_TX_RING(ring))
> + put_page((struct page *)cb->priv);
> + memset(cb, 0, sizeof(*cb));
> +}
> +
> +static int hns3_map_buffer(struct hns3_enet_ring *ring, struct hns3_desc_cb *cb)
> +{
> + cb->dma = dma_map_page(ring_to_dev(ring), cb->priv, 0,
> + cb->length, ring_to_dma_dir(ring));
> +
> + if (dma_mapping_error(ring_to_dev(ring), cb->dma))
> + return -EIO;
> +
> + return 0;
> +}
> +
> +static void hns3_unmap_buffer(struct hns3_enet_ring *ring,
> + struct hns3_desc_cb *cb)
> +{
> + if (cb->type == DESC_TYPE_SKB)
> + dma_unmap_single(ring_to_dev(ring), cb->dma, cb->length,
> + ring_to_dma_dir(ring));
> + else
> + dma_unmap_page(ring_to_dev(ring), cb->dma, cb->length,
> + ring_to_dma_dir(ring));
> +}
> +
> +static inline void hns3_buffer_detach(struct hns3_enet_ring *ring, int i)
> +{
> + hns3_unmap_buffer(ring, &ring->desc_cb[i]);
> + ring->desc[i].addr = 0;
> +}
> +
> +static inline void hns3_free_buffer_detach(struct hns3_enet_ring *ring, int i)
> +{
> + struct hns3_desc_cb *cb = &ring->desc_cb[i];
> +
> + if (!ring->desc_cb[i].dma)
> + return;
> +
> + hns3_buffer_detach(ring, i);
> + hns3_free_buffer(ring, cb);
> +}
> +
> +static void hns3_free_buffers(struct hns3_enet_ring *ring)
> +{
> + int i;
> +
> + for (i = 0; i < ring->desc_num; i++)
> + hns3_free_buffer_detach(ring, i);
> +}
> +
> +/* free desc along with its attached buffer */
> +static void hns3_free_desc(struct hns3_enet_ring *ring)
> +{
> + hns3_free_buffers(ring);
> +
> + dma_unmap_single(ring_to_dev(ring), ring->desc_dma_addr,
> + ring->desc_num * sizeof(ring->desc[0]),
> + DMA_BIDIRECTIONAL);
> + ring->desc_dma_addr = 0;
> + kfree(ring->desc);
> + ring->desc = NULL;
> +}
> +
> +static int hns3_alloc_desc(struct hns3_enet_ring *ring)
> +{
> + int size = ring->desc_num * sizeof(ring->desc[0]);
> +
> + ring->desc = kzalloc(size, GFP_KERNEL);
> + if (!ring->desc)
> + return -ENOMEM;
> +
> + ring->desc_dma_addr = dma_map_single(ring_to_dev(ring),
> + ring->desc, size, DMA_BIDIRECTIONAL);
> + if (dma_mapping_error(ring_to_dev(ring), ring->desc_dma_addr)) {
> + ring->desc_dma_addr = 0;
> + kfree(ring->desc);
> + ring->desc = NULL;
> + return -ENOMEM;
> + }
> +
> + return 0;
> +}
> +
> +static inline int hns3_reserve_buffer_map(struct hns3_enet_ring *ring,
> + struct hns3_desc_cb *cb)
No need to use inline. Leave the compiler to decide. This is true in
general.
> +static bool hns3_get_new_int_gl(struct hns3_enet_ring_group *ring_group)
> +{
> + enum hns3_flow_level_range new_flow_level;
> + struct hns3_enet_tqp_vector *tqp_vector;
> + int packets_per_secs;
> + int bytes_per_usecs;
> + u16 new_int_gl;
> + int usecs;
> +
> + if (!ring_group->int_gl)
> + return false;
> +
> + if (ring_group->total_packets == 0) {
> + ring_group->int_gl = HNS3_INT_GL_50K;
> + ring_group->flow_level = HNS3_FLOW_LOW;
> + return true;
> + }
> + /* Simple throttlerate management
> + * 0-10MB/s lower (50000 ints/s)
> + * 10-20MB/s middle (20000 ints/s)
> + * 20-1249MB/s high (18000 ints/s)
> + * > 40000pps ultra (8000 ints/s)
> + */
> +
> + new_flow_level = ring_group->flow_level;
> + new_int_gl = ring_group->int_gl;
> + tqp_vector = ring_group->ring->tqp_vector;
> + usecs = (ring_group->int_gl << 1);
> + bytes_per_usecs = ring_group->total_bytes / usecs;
> + /* 1000000 microseconds */
> + packets_per_secs = ring_group->total_packets * 1000000 / usecs;
> +
> + switch (new_flow_level) {
> + case HNS3_FLOW_LOW:
> + if (bytes_per_usecs > 10)
> + new_flow_level = HNS3_FLOW_MID;
> + break;
> + case HNS3_FLOW_MID:
> + if (bytes_per_usecs > 20)
> + new_flow_level = HNS3_FLOW_HIGH;
> + else if (bytes_per_usecs <= 10)
> + new_flow_level = HNS3_FLOW_LOW;
> + break;
> + case HNS3_FLOW_HIGH:
> + case HNS3_FLOW_ULTRA:
> + default:
> + if (bytes_per_usecs <= 20)
> + new_flow_level = HNS3_FLOW_MID;
> + break;
> + }
> +#define HNS3_RX_ULTRA_PACKET_RATE 40000
It is not normal to put #defines like this in the middle of the code.
> +
> + if ((packets_per_secs > HNS3_RX_ULTRA_PACKET_RATE) &&
> + (&tqp_vector->rx_group == ring_group))
> + new_flow_level = HNS3_FLOW_ULTRA;
> +
> + switch (new_flow_level) {
> + case HNS3_FLOW_LOW:
> + new_int_gl = HNS3_INT_GL_50K;
> + break;
> + case HNS3_FLOW_MID:
> + new_int_gl = HNS3_INT_GL_20K;
> + break;
> + case HNS3_FLOW_HIGH:
> + new_int_gl = HNS3_INT_GL_18K;
> + break;
> + case HNS3_FLOW_ULTRA:
> + new_int_gl = HNS3_INT_GL_8K;
> + break;
> + default:
> + break;
> + }
> +
> + ring_group->total_bytes = 0;
> + ring_group->total_packets = 0;
> + ring_group->flow_level = new_flow_level;
> + if (new_int_gl != ring_group->int_gl) {
> + ring_group->int_gl = new_int_gl;
> + return true;
> + }
> + return false;
> +}
> +/* Set mac addr if it is configed. or leave it to the AE driver */
configured
> +/* hns3_init_module - Driver registration routine
> + * hns3_init_module is the first routine called when the driver is
> + * loaded. All it does is register with the PCI subsystem.
> + */
> +static int __init hns3_init_module(void)
> +{
> + struct hnae3_client *client;
> + int ret;
> +
> + pr_info("%s: %s - version\n", hns3_driver_name, hns3_driver_string);
> + pr_info("%s: %s\n", hns3_driver_name, hns3_copyright);
> +
> + client = kzalloc(sizeof(*client), GFP_KERNEL);
> + if (!client) {
> + ret = -ENOMEM;
> + goto err_client_alloc;
> + }
> +
> + client->type = HNAE3_CLIENT_KNIC;
> + snprintf(client->name, HNAE3_CLIENT_NAME_LENGTH - 1, "%s",
> + hns3_driver_name);
> +
> + client->ops = &client_ops;
> +
> + ret = hnae3_register_client(client);
> + if (ret)
> + return ret;
> +
> + return pci_register_driver(&hns3_driver);
> +
> +err_client_alloc:
> + return ret;
> +}
> +module_init(hns3_init_module);
> +
> +/* hns3_exit_module - Driver exit cleanup routine
> + * hns3_exit_module is called just before the driver is removed
> + * from memory.
> + */
> +static void __exit hns3_exit_module(void)
> +{
> + pci_unregister_driver(&hns3_driver);
You would normally expect any memory allocated in the init function to
be cleared in the exit function. When does client memory get freed?
Andrew
Powered by blists - more mailing lists